]> git.proxmox.com Git - grub2.git/blame - term/gfxterm.c
2007-07-22 Yoshinori K. Okuji <okuji@enbug.org>
[grub2.git] / term / gfxterm.c
CommitLineData
bd0d7896 1/*
2 * GRUB -- GRand Unified Bootloader
d6b392bd 3 * Copyright (C) 2006,2007 Free Software Foundation, Inc.
bd0d7896 4 *
5a79f472 5 * GRUB is free software: you can redistribute it and/or modify
bd0d7896 6 * it under the terms of the GNU General Public License as published by
5a79f472 7 * the Free Software Foundation, either version 3 of the License, or
bd0d7896 8 * (at your option) any later version.
9 *
5a79f472 10 * GRUB is distributed in the hope that it will be useful,
bd0d7896 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.
14 *
15 * You should have received a copy of the GNU General Public License
5a79f472 16 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
bd0d7896 17 */
18
19#include <grub/machine/memory.h>
20#include <grub/machine/console.h>
21#include <grub/term.h>
22#include <grub/types.h>
23#include <grub/dl.h>
24#include <grub/misc.h>
25#include <grub/normal.h>
26#include <grub/font.h>
27#include <grub/arg.h>
28#include <grub/mm.h>
29#include <grub/env.h>
30#include <grub/video.h>
31
32#define DEFAULT_VIDEO_WIDTH 640
33#define DEFAULT_VIDEO_HEIGHT 480
34#define DEFAULT_VIDEO_FLAGS 0
35
36#define DEFAULT_CHAR_WIDTH 8
37#define DEFAULT_CHAR_HEIGHT 16
38
39#define DEFAULT_BORDER_WIDTH 10
40
41#define DEFAULT_FG_COLOR 0x0a
42#define DEFAULT_BG_COLOR 0x00
43#define DEFAULT_CURSOR_COLOR 0x0f
44
45struct grub_dirty_region
46{
47 int top_left_x;
48 int top_left_y;
49 int bottom_right_x;
50 int bottom_right_y;
51};
52
53struct grub_colored_char
54{
55 /* An Unicode codepoint. */
56 grub_uint32_t code;
57
58 /* Color values. */
59 grub_video_color_t fg_color;
60 grub_video_color_t bg_color;
61
62 /* The width of this character minus one. */
63 unsigned char width;
64
65 /* The column index of this character. */
66 unsigned char index;
67};
68
69struct grub_virtual_screen
70{
71 /* Dimensions of the virtual screen. */
72 unsigned int width;
73 unsigned int height;
74
75 /* Offset in the display. */
76 unsigned int offset_x;
77 unsigned int offset_y;
78
79 /* TTY Character sizes. */
80 unsigned int char_width;
81 unsigned int char_height;
82
83 /* Virtual screen TTY size. */
84 unsigned int columns;
85 unsigned int rows;
86
87 /* Current cursor details. */
88 unsigned int cursor_x;
89 unsigned int cursor_y;
90 int cursor_state;
ad2a06ed 91
bd0d7896 92 /* Color settings. */
93 grub_video_color_t fg_color_setting;
94 grub_video_color_t bg_color_setting;
95 grub_video_color_t fg_color;
96 grub_video_color_t bg_color;
97 grub_video_color_t cursor_color;
98
99 /* Text buffer for virtual screen. Contains (columns * rows) number
100 of entries. */
101 struct grub_colored_char *text_buffer;
102};
103
104static struct grub_virtual_screen virtual_screen;
105
106static grub_dl_t my_mod;
107static struct grub_video_mode_info mode_info;
108
109static struct grub_video_render_target *text_layer;
110
111static struct grub_dirty_region dirty_region;
112
113static void dirty_region_reset (void);
114
115static int dirty_region_is_empty (void);
116
117static void dirty_region_add (int x, int y,
118 unsigned int width, unsigned int height);
119
120static void
121grub_virtual_screen_free (void)
122{
123 /* If virtual screen has been allocated, free it. */
124 if (virtual_screen.text_buffer != 0)
125 grub_free (virtual_screen.text_buffer);
126
127 /* Reset virtual screen data. */
128 grub_memset (&virtual_screen, 0, sizeof (virtual_screen));
ad2a06ed 129
bd0d7896 130 /* Free render targets. */
131 grub_video_delete_render_target (text_layer);
132 text_layer = 0;
133}
134
135static grub_err_t
136grub_virtual_screen_setup (unsigned int x, unsigned int y,
137 unsigned int width, unsigned int height)
138{
139 /* Free old virtual screen. */
140 grub_virtual_screen_free ();
141
142 /* Initialize with default data. */
143 virtual_screen.width = width;
144 virtual_screen.height = height;
145 virtual_screen.offset_x = x;
146 virtual_screen.offset_y = y;
147 virtual_screen.char_width = DEFAULT_CHAR_WIDTH;
148 virtual_screen.char_height = DEFAULT_CHAR_HEIGHT;
149 virtual_screen.cursor_x = 0;
150 virtual_screen.cursor_y = 0;
151 virtual_screen.cursor_state = 1;
152
153 /* Calculate size of text buffer. */
154 virtual_screen.columns = virtual_screen.width / virtual_screen.char_width;
155 virtual_screen.rows = virtual_screen.height / virtual_screen.char_height;
156
157 /* Allocate memory for text buffer. */
158 virtual_screen.text_buffer =
159 (struct grub_colored_char *) grub_malloc (virtual_screen.columns
ad2a06ed 160 * virtual_screen.rows
161 * sizeof (*virtual_screen.text_buffer));
bd0d7896 162 if (grub_errno != GRUB_ERR_NONE)
163 return grub_errno;
164
165 /* Create new render target for text layer. */
166 grub_video_create_render_target (&text_layer,
167 virtual_screen.width,
168 virtual_screen.height,
169 GRUB_VIDEO_MODE_TYPE_RGB
170 | GRUB_VIDEO_MODE_TYPE_ALPHA);
171 if (grub_errno != GRUB_ERR_NONE)
172 return grub_errno;
ad2a06ed 173
bd0d7896 174 /* As we want to have colors compatible with rendering target,
ad2a06ed 175 we can only have those after mode is initialized. */
bd0d7896 176 grub_video_set_active_render_target (text_layer);
ad2a06ed 177
bd0d7896 178 virtual_screen.fg_color_setting = grub_video_map_color (DEFAULT_FG_COLOR);
179 virtual_screen.bg_color_setting = grub_video_map_color (DEFAULT_BG_COLOR);
180 virtual_screen.fg_color = virtual_screen.fg_color_setting;
181 virtual_screen.bg_color = virtual_screen.bg_color_setting;
182 virtual_screen.cursor_color = grub_video_map_color (DEFAULT_CURSOR_COLOR);
ad2a06ed 183
bd0d7896 184 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
ad2a06ed 185
bd0d7896 186 return grub_errno;
187}
188
189static grub_err_t
190grub_gfxterm_init (void)
191{
192 char *modevar;
193 int width = DEFAULT_VIDEO_WIDTH;
194 int height = DEFAULT_VIDEO_HEIGHT;
195 int depth = -1;
196 int flags = DEFAULT_VIDEO_FLAGS;
197 grub_video_color_t color;
ad2a06ed 198
bd0d7896 199 /* Parse gfxmode environment variable if set. */
200 modevar = grub_env_get ("gfxmode");
201 if (modevar)
202 {
203 char *tmp;
29b0ed46 204 char *next_mode;
205 char *current_mode;
bd0d7896 206 char *param;
207 char *value;
29b0ed46 208 int mode_found = 0;
ad2a06ed 209
bd0d7896 210 /* Take copy of env.var. as we don't want to modify that. */
211 tmp = grub_strdup (modevar);
212 modevar = tmp;
ad2a06ed 213
bd0d7896 214 if (grub_errno != GRUB_ERR_NONE)
ad2a06ed 215 return grub_errno;
29b0ed46 216
217 /* Initialize next mode. */
218 next_mode = modevar;
219
220 /* Loop until all modes has been tested out. */
221 while (next_mode != NULL)
bd0d7896 222 {
29b0ed46 223 /* Use last next_mode as current mode. */
224 tmp = next_mode;
225
226 /* Reset video mode settings. */
227 width = DEFAULT_VIDEO_WIDTH;
228 height = DEFAULT_VIDEO_HEIGHT;
229 depth = -1;
230 flags = DEFAULT_VIDEO_FLAGS;
231
232 /* Save position of next mode and separate modes. */
233 next_mode = grub_strchr(next_mode, ';');
234 if (next_mode)
235 {
236 *next_mode = 0;
237 next_mode++;
238 }
ad2a06ed 239
29b0ed46 240 /* Skip whitespace. */
241 while (grub_isspace (*tmp))
242 tmp++;
ad2a06ed 243
29b0ed46 244 /* Initialize token holders. */
245 current_mode = tmp;
246 param = tmp;
247 value = NULL;
bd0d7896 248
29b0ed46 249 /* Parse <width>x<height>[x<depth>]*/
250
251 /* Find width value. */
252 value = param;
253 param = grub_strchr(param, 'x');
254 if (param == NULL)
bd0d7896 255 {
29b0ed46 256 grub_err_t rc;
257
258 /* First setup error message. */
259 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
d6b392bd 260 "Invalid mode: %s\n",
261 current_mode);
29b0ed46 262
bd0d7896 263 /* Free memory before returning. */
264 grub_free (modevar);
29b0ed46 265
266 return rc;
bd0d7896 267 }
29b0ed46 268
bd0d7896 269 *param = 0;
270 param++;
ad2a06ed 271
29b0ed46 272 width = grub_strtoul (value, 0, 0);
bd0d7896 273 if (grub_errno != GRUB_ERR_NONE)
274 {
29b0ed46 275 grub_err_t rc;
276
277 /* First setup error message. */
278 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
279 "Invalid mode: %s\n",
280 current_mode);
281
bd0d7896 282 /* Free memory before returning. */
283 grub_free (modevar);
29b0ed46 284
285 return rc;
bd0d7896 286 }
ad2a06ed 287
29b0ed46 288 /* Find height value. */
bd0d7896 289 value = param;
29b0ed46 290 param = grub_strchr(param, 'x');
291 if (param == NULL)
bd0d7896 292 {
29b0ed46 293 height = grub_strtoul (value, 0, 0);
294 if (grub_errno != GRUB_ERR_NONE)
295 {
296 grub_err_t rc;
297
298 /* First setup error message. */
299 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
300 "Invalid mode: %s\n",
301 current_mode);
302
303 /* Free memory before returning. */
304 grub_free (modevar);
305
306 return rc;
307 }
308 }
309 else
310 {
311 /* We have optional color depth value. */
312 *param = 0;
313 param++;
314
315 height = grub_strtoul (value, 0, 0);
316 if (grub_errno != GRUB_ERR_NONE)
317 {
318 grub_err_t rc;
319
320 /* First setup error message. */
321 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
322 "Invalid mode: %s\n",
323 current_mode);
324
325 /* Free memory before returning. */
326 grub_free (modevar);
327
328 return rc;
329 }
330
331 /* Convert color depth value. */
332 value = param;
333 depth = grub_strtoul (value, 0, 0);
334 if (grub_errno != GRUB_ERR_NONE)
335 {
336 grub_err_t rc;
337
338 /* First setup error message. */
339 rc = grub_error (GRUB_ERR_BAD_ARGUMENT,
340 "Invalid mode: %s\n",
341 current_mode);
342
343 /* Free memory before returning. */
344 grub_free (modevar);
345
346 return rc;
347 }
348 }
349
350 /* Try out video mode. */
351
352 /* If we have 8 or less bits, then assuem that it is indexed color mode. */
353 if ((depth <= 8) && (depth != -1))
354 flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
355
356 /* We have more than 8 bits, then assume that it is RGB color mode. */
357 if (depth > 8)
358 flags |= GRUB_VIDEO_MODE_TYPE_RGB;
359
360 /* If user requested specific depth, forward that information to driver. */
361 if (depth != -1)
362 flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
363 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
364
365 /* Try to initialize requested mode. Ignore any errors. */
366 grub_error_push ();
367 if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
368 {
369 grub_error_pop ();
370 continue;
bd0d7896 371 }
29b0ed46 372
373 /* Figure out what mode we ended up. */
374 if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
375 {
376 /* Couldn't get video mode info, restore old mode and continue to next one. */
377 grub_error_pop ();
378
379 grub_video_restore ();
380 continue;
381 }
382
383 /* Restore state of error stack. */
384 grub_error_pop ();
385
386 /* Mode found! Exit loop. */
387 mode_found = 1;
388 break;
bd0d7896 389 }
ad2a06ed 390
bd0d7896 391 /* Free memory. */
392 grub_free (modevar);
29b0ed46 393
394 if (!mode_found)
395 return grub_error (GRUB_ERR_BAD_ARGUMENT,
396 "No suitable mode found.");
bd0d7896 397 }
29b0ed46 398 else
399 {
400 /* No gfxmode variable set, use defaults. */
401
402 /* If we have 8 or less bits, then assuem that it is indexed color mode. */
403 if ((depth <= 8) && (depth != -1))
404 flags |= GRUB_VIDEO_MODE_TYPE_INDEX_COLOR;
405
406 /* We have more than 8 bits, then assume that it is RGB color mode. */
407 if (depth > 8)
408 flags |= GRUB_VIDEO_MODE_TYPE_RGB;
409
410 /* If user requested specific depth, forward that information to driver. */
411 if (depth != -1)
412 flags |= (depth << GRUB_VIDEO_MODE_TYPE_DEPTH_POS)
413 & GRUB_VIDEO_MODE_TYPE_DEPTH_MASK;
414
415 /* Initialize user requested mode. */
416 if (grub_video_setup (width, height, flags) != GRUB_ERR_NONE)
417 return grub_errno;
bd0d7896 418
29b0ed46 419 /* Figure out what mode we ended up. */
420 if (grub_video_get_info (&mode_info) != GRUB_ERR_NONE)
421 {
422 grub_video_restore ();
423 return grub_errno;
424 }
425 }
bd0d7896 426
427 /* Make sure screen is black. */
428 color = grub_video_map_rgb (0, 0, 0);
429 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
430
431 /* Leave borders for virtual screen. */
432 width = mode_info.width - (2 * DEFAULT_BORDER_WIDTH);
433 height = mode_info.height - (2 * DEFAULT_BORDER_WIDTH);
ad2a06ed 434
bd0d7896 435 /* Create virtual screen. */
436 if (grub_virtual_screen_setup (DEFAULT_BORDER_WIDTH, DEFAULT_BORDER_WIDTH,
437 width, height) != GRUB_ERR_NONE)
438 {
439 grub_video_restore ();
440 return grub_errno;
441 }
442
443 /* Mark whole screen as dirty. */
ad2a06ed 444 dirty_region_reset ();
bd0d7896 445 dirty_region_add (0, 0, mode_info.width, mode_info.height);
446
447 return (grub_errno = GRUB_ERR_NONE);
448}
449
450static grub_err_t
451grub_gfxterm_fini (void)
452{
453 grub_virtual_screen_free ();
454
455 grub_video_restore ();
456
457 return GRUB_ERR_NONE;
458}
459
460static void
461redraw_screen_rect (unsigned int x, unsigned int y,
462 unsigned int width, unsigned int height)
463{
464 grub_video_color_t color;
ad2a06ed 465
bd0d7896 466 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
467
468 /* Render background layer. */
469 color = virtual_screen.bg_color;
470 grub_video_fill_rect (color, x, y, width, height);
ad2a06ed 471
bd0d7896 472 /* Render text layer. */
ad2a06ed 473 grub_video_blit_render_target (text_layer, GRUB_VIDEO_BLIT_BLEND, x, y,
bd0d7896 474 x - virtual_screen.offset_x,
475 y - virtual_screen.offset_y,
476 width, height);
477}
478
479static void
480dirty_region_reset (void)
481{
482 dirty_region.top_left_x = -1;
483 dirty_region.top_left_y = -1;
484 dirty_region.bottom_right_x = -1;
485 dirty_region.bottom_right_y = -1;
486}
487
488static int
489dirty_region_is_empty (void)
490{
491 if ((dirty_region.top_left_x == -1)
492 || (dirty_region.top_left_y == -1)
493 || (dirty_region.bottom_right_x == -1)
494 || (dirty_region.bottom_right_y == -1))
495 return 1;
496 return 0;
497}
498
499static void
500dirty_region_add (int x, int y, unsigned int width, unsigned int height)
501{
502 if ((width == 0) || (height == 0))
503 return;
ad2a06ed 504
bd0d7896 505 if (dirty_region_is_empty ())
506 {
507 dirty_region.top_left_x = x;
508 dirty_region.top_left_y = y;
509 dirty_region.bottom_right_x = x + width - 1;
510 dirty_region.bottom_right_y = y + height - 1;
511 }
512 else
513 {
514 if (x < dirty_region.top_left_x)
515 dirty_region.top_left_x = x;
516 if (y < dirty_region.top_left_y)
517 dirty_region.top_left_y = y;
518 if ((x + (int)width - 1) > dirty_region.bottom_right_x)
519 dirty_region.bottom_right_x = x + width - 1;
520 if ((y + (int)height - 1) > dirty_region.bottom_right_y)
521 dirty_region.bottom_right_y = y + height - 1;
522 }
523}
524
525static void
526dirty_region_add_virtualscreen (void)
527{
528 /* Mark virtual screen as dirty. */
529 dirty_region_add (virtual_screen.offset_x, virtual_screen.offset_y,
530 virtual_screen.width, virtual_screen.height);
531}
532
533
534static void
535dirty_region_redraw (void)
536{
537 int x;
538 int y;
539 int width;
540 int height;
ad2a06ed 541
bd0d7896 542 if (dirty_region_is_empty ())
543 return;
ad2a06ed 544
bd0d7896 545 x = dirty_region.top_left_x;
546 y = dirty_region.top_left_y;
ad2a06ed 547
bd0d7896 548 width = dirty_region.bottom_right_x - x + 1;
549 height = dirty_region.bottom_right_y - y + 1;
ad2a06ed 550
bd0d7896 551 redraw_screen_rect (x, y, width, height);
ad2a06ed 552
bd0d7896 553 dirty_region_reset ();
554}
555
556static void
557write_char (void)
558{
559 struct grub_colored_char *p;
560 struct grub_font_glyph glyph;
561 grub_video_color_t color;
ad2a06ed 562 grub_video_color_t bgcolor;
bd0d7896 563 unsigned int x;
564 unsigned int y;
565
566 /* Find out active character. */
567 p = (virtual_screen.text_buffer
568 + virtual_screen.cursor_x
569 + (virtual_screen.cursor_y * virtual_screen.columns));
570
571 p -= p->index;
572
573 /* Get glyph for character. */
574 grub_font_get_glyph (p->code, &glyph);
575
576 color = p->fg_color;
577 bgcolor = p->bg_color;
578
579 x = virtual_screen.cursor_x * virtual_screen.char_width;
580 y = virtual_screen.cursor_y * virtual_screen.char_height;
581
582 /* Render glyph to text layer. */
583 grub_video_set_active_render_target (text_layer);
584 grub_video_fill_rect (bgcolor, x, y, glyph.width, glyph.height);
ad2a06ed 585 grub_video_blit_glyph (&glyph, color, x, y);
bd0d7896 586 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
587
588 /* Mark character to be drawn. */
589 dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
590 glyph.width, glyph.height);
591}
592
593static void
594write_cursor (void)
595{
596 unsigned int x;
597 unsigned int y;
598 unsigned int width;
599 unsigned int height;
600 grub_video_color_t color;
601
602 /* Determine cursor properties and position on text layer. */
603 x = virtual_screen.cursor_x * virtual_screen.char_width;
604 y = ((virtual_screen.cursor_y + 1) * virtual_screen.char_height) - 3;
605 width = virtual_screen.char_width;
606 height = 2;
607
608 color = virtual_screen.cursor_color;
609
610 /* Render cursor to text layer. */
611 grub_video_set_active_render_target (text_layer);
612 grub_video_fill_rect (color, x, y, width, height);
613 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
614
615 /* Mark cursor to be redrawn. */
616 dirty_region_add (virtual_screen.offset_x + x, virtual_screen.offset_y + y,
617 width, height);
618}
619
620static void
621scroll_up (void)
622{
623 unsigned int i;
624 grub_video_color_t color;
625
626 /* Scroll text buffer with one line to up. */
627 grub_memmove (virtual_screen.text_buffer,
ad2a06ed 628 virtual_screen.text_buffer + virtual_screen.columns,
bd0d7896 629 sizeof (*virtual_screen.text_buffer)
630 * virtual_screen.columns
631 * (virtual_screen.rows - 1));
632
633 /* Clear last line in text buffer. */
634 for (i = virtual_screen.columns * (virtual_screen.rows - 1);
635 i < virtual_screen.columns * virtual_screen.rows;
636 i++)
637 {
638 virtual_screen.text_buffer[i].code = ' ';
639 virtual_screen.text_buffer[i].fg_color = virtual_screen.fg_color;
640 virtual_screen.text_buffer[i].bg_color = virtual_screen.bg_color;
641 virtual_screen.text_buffer[i].width = 0;
642 virtual_screen.text_buffer[i].index = 0;
643 }
ad2a06ed 644
bd0d7896 645 /* Scroll physical screen. */
646 grub_video_set_active_render_target (text_layer);
647 color = virtual_screen.bg_color;
648 grub_video_scroll (color, 0, -virtual_screen.char_height);
649 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
ad2a06ed 650
bd0d7896 651 /* Mark virtual screen to be redrawn. */
652 dirty_region_add_virtualscreen ();
653}
654
655static void
656grub_gfxterm_putchar (grub_uint32_t c)
657{
658 if (c == '\a')
659 /* FIXME */
660 return;
661
662 if (c == '\b' || c == '\n' || c == '\r')
663 {
664 /* Erase current cursor, if any. */
665 if (virtual_screen.cursor_state)
ad2a06ed 666 write_char ();
bd0d7896 667
668 switch (c)
ad2a06ed 669 {
670 case '\b':
671 if (virtual_screen.cursor_x > 0)
672 virtual_screen.cursor_x--;
673 break;
674
675 case '\n':
676 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
677 scroll_up ();
678 else
679 virtual_screen.cursor_y++;
680 break;
681
682 case '\r':
683 virtual_screen.cursor_x = 0;
684 break;
685 }
bd0d7896 686
687 /* Redraw cursor if visible. */
688 if (virtual_screen.cursor_state)
ad2a06ed 689 write_cursor ();
bd0d7896 690 }
691 else
692 {
693 struct grub_font_glyph glyph;
694 struct grub_colored_char *p;
ad2a06ed 695
bd0d7896 696 /* Get properties of the character. */
697 grub_font_get_glyph (c, &glyph);
698
699 /* If we are about to exceed line length, wrap to next line. */
700 if (virtual_screen.cursor_x + glyph.char_width > virtual_screen.columns)
ad2a06ed 701 grub_putchar ('\n');
bd0d7896 702
703 /* Find position on virtual screen, and fill information. */
704 p = (virtual_screen.text_buffer +
ad2a06ed 705 virtual_screen.cursor_x +
706 virtual_screen.cursor_y * virtual_screen.columns);
bd0d7896 707 p->code = c;
708 p->fg_color = virtual_screen.fg_color;
709 p->bg_color = virtual_screen.bg_color;
710 p->width = glyph.char_width - 1;
711 p->index = 0;
712
713 /* If we have large glyph, add fixup info. */
714 if (glyph.char_width > 1)
ad2a06ed 715 {
716 unsigned i;
717
718 for (i = 1; i < glyph.char_width; i++)
719 {
720 p[i].code = ' ';
721 p[i].width = glyph.char_width - 1;
722 p[i].index = i;
723 }
724 }
725
bd0d7896 726 /* Draw glyph. */
727 write_char ();
ad2a06ed 728
bd0d7896 729 /* Make sure we scroll screen when needed and wrap line correctly. */
730 virtual_screen.cursor_x += glyph.char_width;
731 if (virtual_screen.cursor_x >= virtual_screen.columns)
ad2a06ed 732 {
733 virtual_screen.cursor_x = 0;
734
735 if (virtual_screen.cursor_y >= virtual_screen.rows - 1)
736 scroll_up ();
737 else
738 virtual_screen.cursor_y++;
739 }
bd0d7896 740
741 /* Draw cursor if visible. */
742 if (virtual_screen.cursor_state)
ad2a06ed 743 write_cursor ();
bd0d7896 744 }
745}
746
747static grub_ssize_t
748grub_gfxterm_getcharwidth (grub_uint32_t c)
749{
750 struct grub_font_glyph glyph;
ad2a06ed 751
37e5e1a4 752 grub_font_get_glyph (c, &glyph);
bd0d7896 753
754 return glyph.char_width;
755}
756
757static grub_uint16_t
758grub_virtual_screen_getwh (void)
759{
760 return (virtual_screen.columns << 8) | virtual_screen.rows;
761}
762
763static grub_uint16_t
764grub_virtual_screen_getxy (void)
765{
766 return ((virtual_screen.cursor_x << 8) | virtual_screen.cursor_y);
767}
768
769static void
770grub_gfxterm_gotoxy (grub_uint8_t x, grub_uint8_t y)
771{
772 if (x >= virtual_screen.columns)
773 x = virtual_screen.columns - 1;
ad2a06ed 774
bd0d7896 775 if (y >= virtual_screen.rows)
776 y = virtual_screen.rows - 1;
777
778 if (virtual_screen.cursor_state)
779 write_char ();
780
781 virtual_screen.cursor_x = x;
782 virtual_screen.cursor_y = y;
783
784 if (virtual_screen.cursor_state)
785 write_cursor ();
786}
787
788static void
789grub_virtual_screen_cls (void)
790{
791 grub_uint32_t i;
792
793 for (i = 0; i < virtual_screen.columns * virtual_screen.rows; i++)
794 {
795 virtual_screen.text_buffer[i].code = ' ';
796 virtual_screen.text_buffer[i].fg_color = virtual_screen.fg_color;
797 virtual_screen.text_buffer[i].bg_color = virtual_screen.bg_color;
798 virtual_screen.text_buffer[i].width = 0;
799 virtual_screen.text_buffer[i].index = 0;
800 }
801
802 virtual_screen.cursor_x = virtual_screen.cursor_y = 0;
803}
804
805static void
806grub_gfxterm_cls (void)
807{
808 grub_video_color_t color;
809
810 /* Clear virtual screen. */
811 grub_virtual_screen_cls ();
ad2a06ed 812
bd0d7896 813 /* Clear text layer. */
814 grub_video_set_active_render_target (text_layer);
815 color = virtual_screen.bg_color_setting;
816 grub_video_fill_rect (color, 0, 0, mode_info.width, mode_info.height);
817 grub_video_set_active_render_target (GRUB_VIDEO_RENDER_TARGET_DISPLAY);
ad2a06ed 818
bd0d7896 819 /* Mark virtual screen to be redrawn. */
820 dirty_region_add_virtualscreen ();
821}
822
823static void
824grub_virtual_screen_setcolorstate (grub_term_color_state state)
825{
826 switch (state)
827 {
828 case GRUB_TERM_COLOR_STANDARD:
829 case GRUB_TERM_COLOR_NORMAL:
830 virtual_screen.fg_color = virtual_screen.fg_color_setting;
831 virtual_screen.bg_color = virtual_screen.bg_color_setting;
832 break;
833 case GRUB_TERM_COLOR_HIGHLIGHT:
834 virtual_screen.fg_color = virtual_screen.bg_color_setting;
835 virtual_screen.bg_color = virtual_screen.fg_color_setting;
836 break;
837 default:
838 break;
839 }
840}
841
842static void
843grub_virtual_screen_setcolor (grub_uint8_t normal_color,
844 grub_uint8_t highlight_color)
845{
846 virtual_screen.fg_color_setting = grub_video_map_color (normal_color);
847 virtual_screen.bg_color_setting = grub_video_map_color (highlight_color);
848}
849
850static void
851grub_gfxterm_setcursor (int on)
852{
853 if (virtual_screen.cursor_state != on)
854 {
855 if (virtual_screen.cursor_state)
ad2a06ed 856 write_char ();
bd0d7896 857 else
ad2a06ed 858 write_cursor ();
bd0d7896 859
860 virtual_screen.cursor_state = on;
861 }
862}
863
864static void
865grub_gfxterm_refresh (void)
866{
867 /* Redraw only changed regions. */
868 dirty_region_redraw ();
869}
870
871static struct grub_term grub_video_term =
872 {
873 .name = "gfxterm",
874 .init = grub_gfxterm_init,
875 .fini = grub_gfxterm_fini,
876 .putchar = grub_gfxterm_putchar,
877 .getcharwidth = grub_gfxterm_getcharwidth,
878 .checkkey = grub_console_checkkey,
879 .getkey = grub_console_getkey,
880 .getwh = grub_virtual_screen_getwh,
881 .getxy = grub_virtual_screen_getxy,
882 .gotoxy = grub_gfxterm_gotoxy,
883 .cls = grub_gfxterm_cls,
884 .setcolorstate = grub_virtual_screen_setcolorstate,
885 .setcolor = grub_virtual_screen_setcolor,
886 .setcursor = grub_gfxterm_setcursor,
ad2a06ed 887 .refresh = grub_gfxterm_refresh,
bd0d7896 888 .flags = 0,
889 .next = 0
890 };
891
892GRUB_MOD_INIT(term_gfxterm)
893{
894 my_mod = mod;
895 grub_term_register (&grub_video_term);
896}
897
898GRUB_MOD_FINI(term_gfxterm)
899{
900 grub_term_unregister (&grub_video_term);
901}