source: mainline/uspace/srv/hid/fb/fb.c@ 1a5b252

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1a5b252 was c6f08726, checked in by Martin Decky <martin@…>, 14 years ago

eradicate PPMs and pixmaps completely
make TGA and image map code more robust

  • Property mode set to 100644
File size: 42.9 KB
Line 
1/*
2 * Copyright (c) 2008 Martin Decky
3 * Copyright (c) 2006 Jakub Vana
4 * Copyright (c) 2006 Ondrej Palkovsky
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * @defgroup fb Graphical framebuffer
33 * @brief HelenOS graphical framebuffer.
34 * @ingroup fbs
35 * @{
36 */
37
38/** @file
39 */
40
41#include <stdlib.h>
42#include <unistd.h>
43#include <str.h>
44#include <ddi.h>
45#include <sysinfo.h>
46#include <align.h>
47#include <as.h>
48#include <ipc/fb.h>
49#include <ipc/ns.h>
50#include <ipc/services.h>
51#include <errno.h>
52#include <abi/fb/visuals.h>
53#include <io/color.h>
54#include <io/style.h>
55#include <async.h>
56#include <fibril.h>
57#include <bool.h>
58#include <stdio.h>
59#include <byteorder.h>
60#include <io/screenbuffer.h>
61#include <imgmap.h>
62#include "font-8x16.h"
63#include "fb.h"
64#include "main.h"
65#include "pointer.xbm"
66#include "pointer_mask.xbm"
67
68// FIXME: remove this header
69#include <abi/ipc/methods.h>
70
71#define DEFAULT_BGCOLOR 0xf0f0f0
72#define DEFAULT_FGCOLOR 0x000000
73
74#define GLYPH_UNAVAIL '?'
75
76#define MAX_ANIM_LEN 8
77#define MAX_ANIMATIONS 4
78#define MAX_IMGMAPS 256 /**< Maximum number of saved image maps */
79#define MAX_VIEWPORTS 128 /**< Viewport is a rectangular area on the screen */
80
81/** Function to render a pixel from a RGB value. */
82typedef void (*rgb_conv_t)(void *, uint32_t);
83
84/** Function to render a bit mask. */
85typedef void (*mask_conv_t)(void *, bool);
86
87/** Function to draw a glyph. */
88typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor,
89 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
90
91struct {
92 uint8_t *fb_addr;
93
94 unsigned int xres;
95 unsigned int yres;
96
97 unsigned int scanline;
98 unsigned int glyphscanline;
99
100 unsigned int pixelbytes;
101 unsigned int glyphbytes;
102
103 /** Pre-rendered mask for rendering glyphs. Specific for the visual. */
104 uint8_t *glyphs;
105
106 rgb_conv_t rgb_conv;
107 mask_conv_t mask_conv;
108} screen;
109
110/** Backbuffer character cell. */
111typedef struct {
112 uint32_t glyph;
113 uint32_t fg_color;
114 uint32_t bg_color;
115} bb_cell_t;
116
117typedef struct {
118 bool initialized;
119 unsigned int x;
120 unsigned int y;
121 unsigned int width;
122 unsigned int height;
123
124 /* Text support in window */
125 unsigned int cols;
126 unsigned int rows;
127
128 /*
129 * Style and glyphs for text printing
130 */
131
132 /** Current attributes. */
133 attr_rgb_t attr;
134
135 uint8_t *bgpixel;
136
137 /**
138 * Glyph drawing function for this viewport. Different viewports
139 * might use different drawing functions depending on whether their
140 * scanlines are aligned on a word boundary.
141 */
142 dg_t dglyph;
143
144 /* Auto-cursor position */
145 bool cursor_active;
146 unsigned int cur_col;
147 unsigned int cur_row;
148 bool cursor_shown;
149
150 /* Back buffer */
151 bb_cell_t *backbuf;
152 unsigned int bbsize;
153} viewport_t;
154
155typedef struct {
156 bool initialized;
157 bool enabled;
158 unsigned int vp;
159
160 unsigned int pos;
161 unsigned int animlen;
162 unsigned int imgmaps[MAX_ANIM_LEN];
163} animation_t;
164
165static animation_t animations[MAX_ANIMATIONS];
166static bool anims_enabled;
167
168static imgmap_t *imgmaps[MAX_IMGMAPS];
169static viewport_t viewports[128];
170
171static bool client_connected = false; /**< Allow only 1 connection */
172
173static uint32_t color_table[16] = {
174 [COLOR_BLACK] = 0x000000,
175 [COLOR_BLUE] = 0x0000f0,
176 [COLOR_GREEN] = 0x00f000,
177 [COLOR_CYAN] = 0x00f0f0,
178 [COLOR_RED] = 0xf00000,
179 [COLOR_MAGENTA] = 0xf000f0,
180 [COLOR_YELLOW] = 0xf0f000,
181 [COLOR_WHITE] = 0xf0f0f0,
182
183 [8 + COLOR_BLACK] = 0x000000,
184 [8 + COLOR_BLUE] = 0x0000ff,
185 [8 + COLOR_GREEN] = 0x00ff00,
186 [8 + COLOR_CYAN] = 0x00ffff,
187 [8 + COLOR_RED] = 0xff0000,
188 [8 + COLOR_MAGENTA] = 0xff00ff,
189 [8 + COLOR_YELLOW] = 0xffff00,
190 [8 + COLOR_WHITE] = 0xffffff,
191};
192
193static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a);
194static int rgb_from_style(attr_rgb_t *rgb, int style);
195static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color,
196 sysarg_t bg_color, sysarg_t flags);
197
198static int fb_set_color(viewport_t *vport, sysarg_t fg_color,
199 sysarg_t bg_color, sysarg_t attr);
200
201static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
202 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
203static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
204 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
205
206static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
207 unsigned int row);
208
209#define RED(x, bits) (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
210#define GREEN(x, bits) (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
211#define BLUE(x, bits) (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
212
213#define COL2X(col) ((col) * FONT_WIDTH)
214#define ROW2Y(row) ((row) * FONT_SCANLINES)
215
216#define X2COL(x) ((x) / FONT_WIDTH)
217#define Y2ROW(y) ((y) / FONT_SCANLINES)
218
219#define FB_POS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
220#define BB_POS(vport, col, row) ((row) * vport->cols + (col))
221#define GLYPH_POS(glyph, y, cursor) (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline)
222
223/*
224 * RGB conversion and mask functions.
225 *
226 * These functions write an RGB value to some memory in some predefined format.
227 * The naming convention corresponds to the format created by these functions.
228 * The functions use the so called network order (i.e. big endian) with respect
229 * to their names.
230 */
231
232static void rgb_0888(void *dst, uint32_t rgb)
233{
234 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
235 (RED(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (BLUE(rgb, 8)));
236}
237
238static void bgr_0888(void *dst, uint32_t rgb)
239{
240 *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
241 (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (RED(rgb, 8)));
242}
243
244static void mask_0888(void *dst, bool mask)
245{
246 bgr_0888(dst, mask ? 0xffffff : 0);
247}
248
249static void rgb_8880(void *dst, uint32_t rgb)
250{
251 *((uint32_t *) dst) = host2uint32_t_be((RED(rgb, 8) << 24) |
252 (GREEN(rgb, 8) << 16) | (BLUE(rgb, 8) << 8) | 0);
253}
254
255static void bgr_8880(void *dst, uint32_t rgb)
256{
257 *((uint32_t *) dst) = host2uint32_t_be((BLUE(rgb, 8) << 24) |
258 (GREEN(rgb, 8) << 16) | (RED(rgb, 8) << 8) | 0);
259}
260
261static void mask_8880(void *dst, bool mask)
262{
263 bgr_8880(dst, mask ? 0xffffff : 0);
264}
265
266static void rgb_888(void *dst, uint32_t rgb)
267{
268 ((uint8_t *) dst)[0] = RED(rgb, 8);
269 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
270 ((uint8_t *) dst)[2] = BLUE(rgb, 8);
271}
272
273static void bgr_888(void *dst, uint32_t rgb)
274{
275 ((uint8_t *) dst)[0] = BLUE(rgb, 8);
276 ((uint8_t *) dst)[1] = GREEN(rgb, 8);
277 ((uint8_t *) dst)[2] = RED(rgb, 8);
278}
279
280static void mask_888(void *dst, bool mask)
281{
282 bgr_888(dst, mask ? 0xffffff : 0);
283}
284
285static void rgb_555_be(void *dst, uint32_t rgb)
286{
287 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 10 |
288 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
289}
290
291static void rgb_555_le(void *dst, uint32_t rgb)
292{
293 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 10 |
294 GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
295}
296
297static void rgb_565_be(void *dst, uint32_t rgb)
298{
299 *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 11 |
300 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
301}
302
303static void rgb_565_le(void *dst, uint32_t rgb)
304{
305 *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 11 |
306 GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
307}
308
309static void mask_555(void *dst, bool mask)
310{
311 rgb_555_be(dst, mask ? 0xffffff : 0);
312}
313
314static void mask_565(void *dst, bool mask)
315{
316 rgb_565_be(dst, mask ? 0xffffff : 0);
317}
318
319static void bgr_323(void *dst, uint32_t rgb)
320{
321 *((uint8_t *) dst)
322 = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
323}
324
325static void mask_323(void *dst, bool mask)
326{
327 bgr_323(dst, mask ? 0x0 : ~0x0);
328}
329
330/** Draw a filled rectangle.
331 *
332 * @note Need real implementation that does not access VRAM twice.
333 *
334 */
335static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
336 unsigned int y1, uint32_t color)
337{
338 unsigned int x;
339 unsigned int y;
340 unsigned int copy_bytes;
341
342 uint8_t *sp;
343 uint8_t *dp;
344 uint8_t cbuf[4];
345
346 if ((y0 >= y1) || (x0 >= x1))
347 return;
348
349 screen.rgb_conv(cbuf, color);
350
351 sp = &screen.fb_addr[FB_POS(x0, y0)];
352 dp = sp;
353
354 /* Draw the first line. */
355 for (x = x0; x < x1; x++) {
356 memcpy(dp, cbuf, screen.pixelbytes);
357 dp += screen.pixelbytes;
358 }
359
360 dp = sp + screen.scanline;
361 copy_bytes = (x1 - x0) * screen.pixelbytes;
362
363 /* Draw the remaining lines by copying. */
364 for (y = y0 + 1; y < y1; y++) {
365 memcpy(dp, sp, copy_bytes);
366 dp += screen.scanline;
367 }
368}
369
370/** Redraw viewport.
371 *
372 * @param vport Viewport to redraw
373 *
374 */
375static void vport_redraw(viewport_t *vport)
376{
377 unsigned int col;
378 unsigned int row;
379
380 for (row = 0; row < vport->rows; row++) {
381 for (col = 0; col < vport->cols; col++) {
382 draw_vp_glyph(vport, false, col, row);
383 }
384 }
385
386 if (COL2X(vport->cols) < vport->width) {
387 draw_filled_rect(
388 vport->x + COL2X(vport->cols), vport->y,
389 vport->x + vport->width, vport->y + vport->height,
390 vport->attr.bg_color);
391 }
392
393 if (ROW2Y(vport->rows) < vport->height) {
394 draw_filled_rect(
395 vport->x, vport->y + ROW2Y(vport->rows),
396 vport->x + vport->width, vport->y + vport->height,
397 vport->attr.bg_color);
398 }
399}
400
401static void backbuf_clear(bb_cell_t *backbuf, size_t len, uint32_t fg_color,
402 uint32_t bg_color)
403{
404 size_t i;
405
406 for (i = 0; i < len; i++) {
407 backbuf[i].glyph = 0;
408 backbuf[i].fg_color = fg_color;
409 backbuf[i].bg_color = bg_color;
410 }
411}
412
413/** Clear viewport.
414 *
415 * @param vport Viewport to clear
416 *
417 */
418static void vport_clear(viewport_t *vport)
419{
420 backbuf_clear(vport->backbuf, vport->cols * vport->rows,
421 vport->attr.fg_color, vport->attr.bg_color);
422 vport_redraw(vport);
423}
424
425/** Scroll viewport by the specified number of lines.
426 *
427 * @param vport Viewport to scroll
428 * @param lines Number of lines to scroll
429 *
430 */
431static void vport_scroll(viewport_t *vport, int lines)
432{
433 unsigned int col;
434 unsigned int row;
435 unsigned int x;
436 unsigned int y;
437 uint32_t glyph;
438 uint32_t fg_color;
439 uint32_t bg_color;
440 bb_cell_t *bbp;
441 bb_cell_t *xbp;
442
443 /*
444 * Redraw.
445 */
446
447 y = vport->y;
448 for (row = 0; row < vport->rows; row++) {
449 x = vport->x;
450 for (col = 0; col < vport->cols; col++) {
451 if (((int) row + lines >= 0) &&
452 ((int) row + lines < (int) vport->rows)) {
453 xbp = &vport->backbuf[BB_POS(vport, col, row + lines)];
454 bbp = &vport->backbuf[BB_POS(vport, col, row)];
455
456 glyph = xbp->glyph;
457 fg_color = xbp->fg_color;
458 bg_color = xbp->bg_color;
459
460 if ((bbp->glyph == glyph)
461 && (bbp->fg_color == xbp->fg_color)
462 && (bbp->bg_color == xbp->bg_color)) {
463 x += FONT_WIDTH;
464 continue;
465 }
466 } else {
467 glyph = 0;
468 fg_color = vport->attr.fg_color;
469 bg_color = vport->attr.bg_color;
470 }
471
472 (*vport->dglyph)(x, y, false, screen.glyphs, glyph,
473 fg_color, bg_color);
474 x += FONT_WIDTH;
475 }
476 y += FONT_SCANLINES;
477 }
478
479 /*
480 * Scroll backbuffer.
481 */
482
483 if (lines > 0) {
484 memmove(vport->backbuf, vport->backbuf + vport->cols * lines,
485 vport->cols * (vport->rows - lines) * sizeof(bb_cell_t));
486 backbuf_clear(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
487 vport->cols * lines, vport->attr.fg_color, vport->attr.bg_color);
488 } else {
489 memmove(vport->backbuf - vport->cols * lines, vport->backbuf,
490 vport->cols * (vport->rows + lines) * sizeof(bb_cell_t));
491 backbuf_clear(vport->backbuf, - vport->cols * lines,
492 vport->attr.fg_color, vport->attr.bg_color);
493 }
494}
495
496/** Render glyphs
497 *
498 * Convert glyphs from device independent font
499 * description to current visual representation.
500 *
501 */
502static void render_glyphs(void)
503{
504 unsigned int glyph;
505
506 for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
507 unsigned int y;
508
509 for (y = 0; y < FONT_SCANLINES; y++) {
510 unsigned int x;
511
512 for (x = 0; x < FONT_WIDTH; x++) {
513 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
514 (fb_font[glyph][y] & (1 << (7 - x))) ? true : false);
515
516 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes],
517 (fb_font[glyph][y] & (1 << (7 - x))) ? false : true);
518 }
519 }
520 }
521}
522
523/** Create new viewport
524 *
525 * @param x Origin of the viewport (x).
526 * @param y Origin of the viewport (y).
527 * @param width Width of the viewport.
528 * @param height Height of the viewport.
529 *
530 * @return New viewport number.
531 *
532 */
533static int vport_create(unsigned int x, unsigned int y,
534 unsigned int width, unsigned int height)
535{
536 unsigned int i;
537
538 for (i = 0; i < MAX_VIEWPORTS; i++) {
539 if (!viewports[i].initialized)
540 break;
541 }
542
543 if (i == MAX_VIEWPORTS)
544 return ELIMIT;
545
546 unsigned int cols = width / FONT_WIDTH;
547 unsigned int rows = height / FONT_SCANLINES;
548 unsigned int bbsize = cols * rows * sizeof(bb_cell_t);
549 unsigned int word_size = sizeof(unsigned long);
550
551 bb_cell_t *backbuf = (bb_cell_t *) malloc(bbsize);
552 if (!backbuf)
553 return ENOMEM;
554
555 uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);
556 if (!bgpixel) {
557 free(backbuf);
558 return ENOMEM;
559 }
560
561 backbuf_clear(backbuf, cols * rows, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR);
562 memset(bgpixel, 0, screen.pixelbytes);
563
564 viewports[i].x = x;
565 viewports[i].y = y;
566 viewports[i].width = width;
567 viewports[i].height = height;
568
569 viewports[i].cols = cols;
570 viewports[i].rows = rows;
571
572 viewports[i].attr.bg_color = DEFAULT_BGCOLOR;
573 viewports[i].attr.fg_color = DEFAULT_FGCOLOR;
574
575 viewports[i].bgpixel = bgpixel;
576
577 /*
578 * Conditions necessary to select aligned version:
579 * - word size is divisible by pixelbytes
580 * - cell scanline size is divisible by word size
581 * - cell scanlines are word-aligned
582 *
583 */
584 if (((word_size % screen.pixelbytes) == 0)
585 && ((FONT_WIDTH * screen.pixelbytes) % word_size == 0)
586 && ((x * screen.pixelbytes) % word_size == 0)
587 && (screen.scanline % word_size == 0)) {
588 viewports[i].dglyph = draw_glyph_aligned;
589 } else {
590 viewports[i].dglyph = draw_glyph_fallback;
591 }
592
593 viewports[i].cur_col = 0;
594 viewports[i].cur_row = 0;
595 viewports[i].cursor_active = false;
596 viewports[i].cursor_shown = false;
597
598 viewports[i].bbsize = bbsize;
599 viewports[i].backbuf = backbuf;
600
601 viewports[i].initialized = true;
602
603 screen.rgb_conv(viewports[i].bgpixel, viewports[i].attr.bg_color);
604
605 return i;
606}
607
608
609/** Initialize framebuffer as a chardev output device
610 *
611 * @param addr Address of the framebuffer
612 * @param xres Screen width in pixels
613 * @param yres Screen height in pixels
614 * @param visual Bits per pixel (8, 16, 24, 32)
615 * @param scan Bytes per one scanline
616 *
617 */
618static bool screen_init(void *addr, unsigned int xres, unsigned int yres,
619 unsigned int scan, unsigned int visual)
620{
621 switch (visual) {
622 case VISUAL_INDIRECT_8:
623 screen.rgb_conv = bgr_323;
624 screen.mask_conv = mask_323;
625 screen.pixelbytes = 1;
626 break;
627 case VISUAL_RGB_5_5_5_LE:
628 screen.rgb_conv = rgb_555_le;
629 screen.mask_conv = mask_555;
630 screen.pixelbytes = 2;
631 break;
632 case VISUAL_RGB_5_5_5_BE:
633 screen.rgb_conv = rgb_555_be;
634 screen.mask_conv = mask_555;
635 screen.pixelbytes = 2;
636 break;
637 case VISUAL_RGB_5_6_5_LE:
638 screen.rgb_conv = rgb_565_le;
639 screen.mask_conv = mask_565;
640 screen.pixelbytes = 2;
641 break;
642 case VISUAL_RGB_5_6_5_BE:
643 screen.rgb_conv = rgb_565_be;
644 screen.mask_conv = mask_565;
645 screen.pixelbytes = 2;
646 break;
647 case VISUAL_RGB_8_8_8:
648 screen.rgb_conv = rgb_888;
649 screen.mask_conv = mask_888;
650 screen.pixelbytes = 3;
651 break;
652 case VISUAL_BGR_8_8_8:
653 screen.rgb_conv = bgr_888;
654 screen.mask_conv = mask_888;
655 screen.pixelbytes = 3;
656 break;
657 case VISUAL_RGB_8_8_8_0:
658 screen.rgb_conv = rgb_8880;
659 screen.mask_conv = mask_8880;
660 screen.pixelbytes = 4;
661 break;
662 case VISUAL_RGB_0_8_8_8:
663 screen.rgb_conv = rgb_0888;
664 screen.mask_conv = mask_0888;
665 screen.pixelbytes = 4;
666 break;
667 case VISUAL_BGR_0_8_8_8:
668 screen.rgb_conv = bgr_0888;
669 screen.mask_conv = mask_0888;
670 screen.pixelbytes = 4;
671 break;
672 case VISUAL_BGR_8_8_8_0:
673 screen.rgb_conv = bgr_8880;
674 screen.mask_conv = mask_8880;
675 screen.pixelbytes = 4;
676 break;
677 default:
678 return false;
679 }
680
681 screen.fb_addr = (unsigned char *) addr;
682 screen.xres = xres;
683 screen.yres = yres;
684 screen.scanline = scan;
685
686 screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;
687 screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;
688
689 size_t glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
690 uint8_t *glyphs = (uint8_t *) malloc(glyphsize);
691 if (!glyphs)
692 return false;
693
694 memset(glyphs, 0, glyphsize);
695 screen.glyphs = glyphs;
696
697 render_glyphs();
698
699 /* Create first viewport */
700 vport_create(0, 0, xres, yres);
701
702 return true;
703}
704
705
706/** Draw a glyph, takes advantage of alignment.
707 *
708 * This version can only be used if the following conditions are met:
709 *
710 * - word size is divisible by pixelbytes
711 * - cell scanline size is divisible by word size
712 * - cell scanlines are word-aligned
713 *
714 * It makes use of the pre-rendered mask to process (possibly) several
715 * pixels at once (word size / pixelbytes pixels at a time are processed)
716 * making it very fast. Most notably this version is not applicable at 24 bits
717 * per pixel.
718 *
719 * @param x x coordinate of top-left corner on screen.
720 * @param y y coordinate of top-left corner on screen.
721 * @param cursor Draw glyph with cursor
722 * @param glyphs Pointer to font bitmap.
723 * @param glyph Code of the glyph to draw.
724 * @param fg_color Foreground color.
725 * @param bg_color Backgroudn color.
726 *
727 */
728static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
729 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
730{
731 unsigned int i;
732 unsigned int yd;
733 unsigned long fg_buf;
734 unsigned long bg_buf;
735 unsigned long mask;
736
737 /*
738 * Prepare a pair of words, one filled with foreground-color
739 * pattern and the other filled with background-color pattern.
740 */
741 for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {
742 screen.rgb_conv(&((uint8_t *) &fg_buf)[i * screen.pixelbytes],
743 fg_color);
744 screen.rgb_conv(&((uint8_t *) &bg_buf)[i * screen.pixelbytes],
745 bg_color);
746 }
747
748 /* Pointer to the current position in the mask. */
749 unsigned long *maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];
750
751 /* Pointer to the current position on the screen. */
752 unsigned long *dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];
753
754 /* Width of the character cell in words. */
755 unsigned int ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);
756
757 /* Offset to add when moving to another screen scanline. */
758 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
759
760 for (yd = 0; yd < FONT_SCANLINES; yd++) {
761 /*
762 * Now process the cell scanline, combining foreground
763 * and background color patters using the pre-rendered mask.
764 */
765 for (i = 0; i < ww; i++) {
766 mask = *maskp++;
767 *dp++ = (fg_buf & mask) | (bg_buf & ~mask);
768 }
769
770 /* Move to the beginning of the next scanline of the cell. */
771 dp = (unsigned long *) ((uint8_t *) dp + d_add);
772 }
773}
774
775/** Draw a glyph, fallback version.
776 *
777 * This version does not make use of the pre-rendered mask, it uses
778 * the font bitmap directly. It works always, but it is slower.
779 *
780 * @param x x coordinate of top-left corner on screen.
781 * @param y y coordinate of top-left corner on screen.
782 * @param cursor Draw glyph with cursor
783 * @param glyphs Pointer to font bitmap.
784 * @param glyph Code of the glyph to draw.
785 * @param fg_color Foreground color.
786 * @param bg_color Backgroudn color.
787 *
788 */
789void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
790 uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
791{
792 unsigned int i;
793 unsigned int j;
794 unsigned int yd;
795 uint8_t fg_buf[4];
796 uint8_t bg_buf[4];
797 uint8_t *sp;
798 uint8_t b;
799
800 /* Pre-render 1x the foreground and background color pixels. */
801 if (cursor) {
802 screen.rgb_conv(fg_buf, bg_color);
803 screen.rgb_conv(bg_buf, fg_color);
804 } else {
805 screen.rgb_conv(fg_buf, fg_color);
806 screen.rgb_conv(bg_buf, bg_color);
807 }
808
809 /* Pointer to the current position on the screen. */
810 uint8_t *dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];
811
812 /* Offset to add when moving to another screen scanline. */
813 unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
814
815 for (yd = 0; yd < FONT_SCANLINES; yd++) {
816 /* Byte containing bits of the glyph scanline. */
817 b = fb_font[glyph][yd];
818
819 for (i = 0; i < FONT_WIDTH; i++) {
820 /* Choose color based on the current bit. */
821 sp = (b & 0x80) ? fg_buf : bg_buf;
822
823 /* Copy the pixel. */
824 for (j = 0; j < screen.pixelbytes; j++) {
825 *dp++ = *sp++;
826 }
827
828 /* Move to the next bit. */
829 b = b << 1;
830 }
831
832 /* Move to the beginning of the next scanline of the cell. */
833 dp += d_add;
834 }
835}
836
837/** Draw glyph at specified position in viewport.
838 *
839 * @param vport Viewport identification
840 * @param cursor Draw glyph with cursor
841 * @param col Screen position relative to viewport
842 * @param row Screen position relative to viewport
843 *
844 */
845static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
846 unsigned int row)
847{
848 unsigned int x = vport->x + COL2X(col);
849 unsigned int y = vport->y + ROW2Y(row);
850
851 uint32_t glyph = vport->backbuf[BB_POS(vport, col, row)].glyph;
852 uint32_t fg_color = vport->backbuf[BB_POS(vport, col, row)].fg_color;
853 uint32_t bg_color = vport->backbuf[BB_POS(vport, col, row)].bg_color;
854
855 (*vport->dglyph)(x, y, cursor, screen.glyphs, glyph,
856 fg_color, bg_color);
857}
858
859/** Hide cursor if it is shown
860 *
861 */
862static void cursor_hide(viewport_t *vport)
863{
864 if ((vport->cursor_active) && (vport->cursor_shown)) {
865 draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);
866 vport->cursor_shown = false;
867 }
868}
869
870/** Show cursor if cursor showing is enabled
871 *
872 */
873static void cursor_show(viewport_t *vport)
874{
875 /* Do not check for cursor_shown */
876 if (vport->cursor_active) {
877 draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);
878 vport->cursor_shown = true;
879 }
880}
881
882/** Invert cursor, if it is enabled
883 *
884 */
885static void cursor_blink(viewport_t *vport)
886{
887 if (vport->cursor_shown)
888 cursor_hide(vport);
889 else
890 cursor_show(vport);
891}
892
893/** Draw character at given position relative to viewport
894 *
895 * @param vport Viewport identification
896 * @param c Character to draw
897 * @param col Screen position relative to viewport
898 * @param row Screen position relative to viewport
899 *
900 */
901static void draw_char(viewport_t *vport, wchar_t c, unsigned int col, unsigned int row)
902{
903 bb_cell_t *bbp;
904
905 /* Do not hide cursor if we are going to overwrite it */
906 if ((vport->cursor_active) && (vport->cursor_shown) &&
907 ((vport->cur_col != col) || (vport->cur_row != row)))
908 cursor_hide(vport);
909
910 bbp = &vport->backbuf[BB_POS(vport, col, row)];
911 bbp->glyph = fb_font_glyph(c);
912 bbp->fg_color = vport->attr.fg_color;
913 bbp->bg_color = vport->attr.bg_color;
914
915 draw_vp_glyph(vport, false, col, row);
916
917 vport->cur_col = col;
918 vport->cur_row = row;
919
920 vport->cur_col++;
921 if (vport->cur_col >= vport->cols) {
922 vport->cur_col = 0;
923 vport->cur_row++;
924 if (vport->cur_row >= vport->rows)
925 vport->cur_row--;
926 }
927
928 cursor_show(vport);
929}
930
931/** Draw text data to viewport.
932 *
933 * @param vport Viewport id
934 * @param data Text data.
935 * @param x Leftmost column of the area.
936 * @param y Topmost row of the area.
937 * @param w Number of rows.
938 * @param h Number of columns.
939 *
940 */
941static void draw_text_data(viewport_t *vport, keyfield_t *data, unsigned int x,
942 unsigned int y, unsigned int w, unsigned int h)
943{
944 unsigned int i;
945 unsigned int j;
946 bb_cell_t *bbp;
947 attrs_t *a;
948
949 for (j = 0; j < h; j++) {
950 for (i = 0; i < w; i++) {
951 unsigned int col = x + i;
952 unsigned int row = y + j;
953
954 bbp = &vport->backbuf[BB_POS(vport, col, row)];
955
956 a = &data[j * w + i].attrs;
957
958 attr_rgb_t rgb;
959 rgb.fg_color = 0;
960 rgb.bg_color = 0;
961 rgb_from_attr(&rgb, a);
962
963 bbp->glyph = fb_font_glyph(data[j * w + i].character);
964 bbp->fg_color = rgb.fg_color;
965 bbp->bg_color = rgb.bg_color;
966
967 draw_vp_glyph(vport, false, col, row);
968 }
969 }
970 cursor_show(vport);
971}
972
973static void putpixel(viewport_t *vport, unsigned int x, unsigned int y,
974 uint32_t color)
975{
976 unsigned int dx = vport->x + x;
977 unsigned int dy = vport->y + y;
978
979 screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);
980}
981
982/** Draw image map
983 *
984 * @param[in] img Image map.
985 * @param[in] sx Coordinate of upper left corner.
986 * @param[in] sy Coordinate of upper left corner.
987 * @param[in] maxwidth Maximum allowed width for picture.
988 * @param[in] maxheight Maximum allowed height for picture.
989 * @param[in] vport Viewport.
990 *
991 * @return EOK on success.
992 *
993 */
994static int imgmap_draw(imgmap_t *img, unsigned int sx, unsigned int sy,
995 unsigned int maxwidth, unsigned int maxheight, void *vport)
996{
997 if (img->visual != VISUAL_BGR_8_8_8)
998 return EINVAL;
999
1000 uint8_t *data = (uint8_t *) img->data;
1001
1002 for (sysarg_t y = 0; y < img->height; y++) {
1003 for (sysarg_t x = 0; x < img->width; x++) {
1004 if ((x > maxwidth) || (y > maxheight)) {
1005 data += 3;
1006 continue;
1007 }
1008
1009 uint32_t color = (data[2] << 16) + (data[1] << 8) + data[0];
1010
1011 putpixel(vport, sx + x, sy + y, color);
1012 data += 3;
1013 }
1014 }
1015
1016 return EOK;
1017}
1018
1019/** Return first free image map
1020 *
1021 */
1022static int find_free_imgmap(void)
1023{
1024 unsigned int i;
1025
1026 for (i = 0; i < MAX_IMGMAPS; i++)
1027 if (!imgmaps[i])
1028 return i;
1029
1030 return -1;
1031}
1032
1033/** Create a new image map and return appropriate ID
1034 *
1035 */
1036static int shm2imgmap(imgmap_t *shm, size_t size)
1037{
1038 int im = find_free_imgmap();
1039 if (im == -1)
1040 return ELIMIT;
1041
1042 imgmap_t *imap = malloc(size);
1043 if (!imap)
1044 return ENOMEM;
1045
1046 memcpy(imap, shm, size);
1047 imgmaps[im] = imap;
1048 return im;
1049}
1050
1051/** Handle shared memory communication calls
1052 *
1053 * Protocol for drawing image maps:
1054 * - FB_PREPARE_SHM(client shm identification)
1055 * - IPC_M_AS_AREA_SEND
1056 * - FB_DRAW_IMGMAP(startx, starty)
1057 * - FB_DROP_SHM
1058 *
1059 * Protocol for text drawing
1060 * - IPC_M_AS_AREA_SEND
1061 * - FB_DRAW_TEXT_DATA
1062 *
1063 * @param callid Callid of the current call
1064 * @param call Current call data
1065 * @param vp Active viewport
1066 *
1067 * @return false if the call was not handled byt this function, true otherwise
1068 *
1069 * Note: this function is not thread-safe, you would have
1070 * to redefine static variables with fibril_local.
1071 *
1072 */
1073static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1074{
1075 static keyfield_t *interbuffer = NULL;
1076 static size_t intersize = 0;
1077
1078 static imgmap_t *shm = NULL;
1079 static sysarg_t shm_id = 0;
1080 static size_t shm_size;
1081
1082 bool handled = true;
1083 int retval = EOK;
1084 viewport_t *vport = &viewports[vp];
1085 unsigned int x;
1086 unsigned int y;
1087 unsigned int w;
1088 unsigned int h;
1089
1090 switch (IPC_GET_IMETHOD(*call)) {
1091 case IPC_M_SHARE_OUT:
1092 /* We accept one area for data interchange */
1093 if (IPC_GET_ARG1(*call) == shm_id) {
1094 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
1095 shm_size = IPC_GET_ARG2(*call);
1096 if (async_answer_1(callid, EOK, (sysarg_t) dest)) {
1097 shm_id = 0;
1098 return false;
1099 }
1100
1101 shm = dest;
1102 return true;
1103 } else {
1104 intersize = IPC_GET_ARG2(*call);
1105 receive_comm_area(callid, call, (void *) &interbuffer);
1106 }
1107 return true;
1108 case FB_PREPARE_SHM:
1109 if (shm_id)
1110 retval = EBUSY;
1111 else
1112 shm_id = IPC_GET_ARG1(*call);
1113 break;
1114 case FB_DROP_SHM:
1115 if (shm) {
1116 as_area_destroy(shm);
1117 shm = NULL;
1118 }
1119 shm_id = 0;
1120 break;
1121 case FB_SHM2IMGMAP:
1122 if (!shm) {
1123 retval = EINVAL;
1124 break;
1125 }
1126 retval = shm2imgmap(shm, shm_size);
1127 break;
1128 case FB_DRAW_IMGMAP:
1129 if (!shm) {
1130 retval = EINVAL;
1131 break;
1132 }
1133
1134 x = IPC_GET_ARG1(*call);
1135 y = IPC_GET_ARG2(*call);
1136
1137 if ((x > vport->width) || (y > vport->height)) {
1138 retval = EINVAL;
1139 break;
1140 }
1141
1142 imgmap_draw(shm, IPC_GET_ARG1(*call), IPC_GET_ARG2(*call),
1143 vport->width - x, vport->height - y, vport);
1144 break;
1145 case FB_DRAW_TEXT_DATA:
1146 x = IPC_GET_ARG1(*call);
1147 y = IPC_GET_ARG2(*call);
1148 w = IPC_GET_ARG3(*call);
1149 h = IPC_GET_ARG4(*call);
1150 if (!interbuffer) {
1151 retval = EINVAL;
1152 break;
1153 }
1154 if (x + w > vport->cols || y + h > vport->rows) {
1155 retval = EINVAL;
1156 break;
1157 }
1158 if (intersize < w * h * sizeof(*interbuffer)) {
1159 retval = EINVAL;
1160 break;
1161 }
1162 draw_text_data(vport, interbuffer, x, y, w, h);
1163 break;
1164 default:
1165 handled = false;
1166 }
1167
1168 if (handled)
1169 async_answer_0(callid, retval);
1170
1171 return handled;
1172}
1173
1174static void copy_vp_to_imgmap(viewport_t *vport, imgmap_t *imap)
1175{
1176 unsigned int width = vport->width;
1177 unsigned int height = vport->height;
1178
1179 if (width + vport->x > screen.xres)
1180 width = screen.xres - vport->x;
1181
1182 if (height + vport->y > screen.yres)
1183 height = screen.yres - vport->y;
1184
1185 unsigned int realwidth = imap->width <= width ? imap->width : width;
1186 unsigned int realheight = imap->height <= height ? imap->height : height;
1187
1188 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1189 unsigned int realrowsize = realwidth * screen.pixelbytes;
1190
1191 unsigned int y;
1192 for (y = 0; y < realheight; y++) {
1193 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1194 memcpy(imap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);
1195 }
1196}
1197
1198/** Save viewport to image map
1199 *
1200 */
1201static int save_vp_to_imgmap(viewport_t *vport)
1202{
1203 int im = find_free_imgmap();
1204 if (im == -1)
1205 return ELIMIT;
1206
1207 size_t size = screen.pixelbytes * vport->width * vport->height;
1208 imgmap_t *imap = malloc(sizeof(imgmap_t) + size);
1209 if (!imap)
1210 return ENOMEM;
1211
1212 imap->size = sizeof(imgmap_t) + size;
1213 imap->width = vport->width;
1214 imap->height = vport->height;
1215 imap->visual = (visual_t) -1;
1216
1217 copy_vp_to_imgmap(vport, imap);
1218 imgmaps[im] = imap;
1219 return im;
1220}
1221
1222/** Draw image map to screen
1223 *
1224 * @param vp Viewport to draw to
1225 * @param im Image map identifier
1226 *
1227 */
1228static int draw_imgmap(int vp, int im)
1229{
1230 imgmap_t *imap = imgmaps[im];
1231 if (!imap)
1232 return EINVAL;
1233
1234 viewport_t *vport = &viewports[vp];
1235
1236 unsigned int width = vport->width;
1237 unsigned int height = vport->height;
1238
1239 if (width + vport->x > screen.xres)
1240 width = screen.xres - vport->x;
1241
1242 if (height + vport->y > screen.yres)
1243 height = screen.yres - vport->y;
1244
1245 unsigned int realwidth = imap->width <= width ? imap->width : width;
1246 unsigned int realheight = imap->height <= height ? imap->height : height;
1247
1248 if (imap->visual == (visual_t) -1) {
1249 unsigned int srcrowsize = vport->width * screen.pixelbytes;
1250 unsigned int realrowsize = realwidth * screen.pixelbytes;
1251
1252 unsigned int y;
1253 for (y = 0; y < realheight; y++) {
1254 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
1255 memcpy(screen.fb_addr + tmp, imap->data + y * srcrowsize, realrowsize);
1256 }
1257 } else
1258 imgmap_draw(imap, 0, 0, realwidth, realheight, vport);
1259
1260 return EOK;
1261}
1262
1263/** Tick animation one step forward
1264 *
1265 */
1266static void anims_tick(void)
1267{
1268 unsigned int i;
1269 static int counts = 0;
1270
1271 /* Limit redrawing */
1272 counts = (counts + 1) % 8;
1273 if (counts)
1274 return;
1275
1276 for (i = 0; i < MAX_ANIMATIONS; i++) {
1277 if ((!animations[i].animlen) || (!animations[i].initialized) ||
1278 (!animations[i].enabled))
1279 continue;
1280
1281 draw_imgmap(animations[i].vp, animations[i].imgmaps[animations[i].pos]);
1282 animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;
1283 }
1284}
1285
1286
1287static unsigned int pointer_x;
1288static unsigned int pointer_y;
1289static bool pointer_shown, pointer_enabled;
1290static int pointer_vport = -1;
1291static int pointer_imgmap = -1;
1292
1293
1294static void mouse_show(void)
1295{
1296 int i, j;
1297 int visibility;
1298 int color;
1299 int bytepos;
1300
1301 if ((pointer_shown) || (!pointer_enabled))
1302 return;
1303
1304 /* Save image under the pointer. */
1305 if (pointer_vport == -1) {
1306 pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
1307 if (pointer_vport < 0)
1308 return;
1309 } else {
1310 viewports[pointer_vport].x = pointer_x;
1311 viewports[pointer_vport].y = pointer_y;
1312 }
1313
1314 if (pointer_imgmap == -1)
1315 pointer_imgmap = save_vp_to_imgmap(&viewports[pointer_vport]);
1316 else
1317 copy_vp_to_imgmap(&viewports[pointer_vport], imgmaps[pointer_imgmap]);
1318
1319 /* Draw mouse pointer. */
1320 for (i = 0; i < pointer_height; i++)
1321 for (j = 0; j < pointer_width; j++) {
1322 bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
1323 visibility = pointer_mask_bits[bytepos] &
1324 (1 << (j % 8));
1325 if (visibility) {
1326 color = pointer_bits[bytepos] &
1327 (1 << (j % 8)) ? 0 : 0xffffff;
1328 if (pointer_x + j < screen.xres && pointer_y +
1329 i < screen.yres)
1330 putpixel(&viewports[0], pointer_x + j,
1331 pointer_y + i, color);
1332 }
1333 }
1334 pointer_shown = 1;
1335}
1336
1337
1338static void mouse_hide(void)
1339{
1340 /* Restore image under the pointer. */
1341 if (pointer_shown) {
1342 draw_imgmap(pointer_vport, pointer_imgmap);
1343 pointer_shown = 0;
1344 }
1345}
1346
1347
1348static void mouse_move(unsigned int x, unsigned int y)
1349{
1350 mouse_hide();
1351 pointer_x = x % screen.xres;
1352 pointer_y = y % screen.yres;
1353 mouse_show();
1354}
1355
1356
1357static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1358{
1359 bool handled = true;
1360 int retval = EOK;
1361 int i, nvp;
1362 int newval;
1363
1364 switch (IPC_GET_IMETHOD(*call)) {
1365 case FB_ANIM_CREATE:
1366 nvp = IPC_GET_ARG1(*call);
1367 if (nvp == -1)
1368 nvp = vp;
1369 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1370 !viewports[nvp].initialized) {
1371 retval = EINVAL;
1372 break;
1373 }
1374 for (i = 0; i < MAX_ANIMATIONS; i++) {
1375 if (!animations[i].initialized)
1376 break;
1377 }
1378 if (i == MAX_ANIMATIONS) {
1379 retval = ELIMIT;
1380 break;
1381 }
1382 animations[i].initialized = 1;
1383 animations[i].animlen = 0;
1384 animations[i].pos = 0;
1385 animations[i].enabled = 0;
1386 animations[i].vp = nvp;
1387 retval = i;
1388 break;
1389 case FB_ANIM_DROP:
1390 i = IPC_GET_ARG1(*call);
1391 if (i >= MAX_ANIMATIONS || i < 0) {
1392 retval = EINVAL;
1393 break;
1394 }
1395 animations[i].initialized = 0;
1396 break;
1397 case FB_ANIM_ADDIMGMAP:
1398 i = IPC_GET_ARG1(*call);
1399 if (i >= MAX_ANIMATIONS || i < 0 ||
1400 !animations[i].initialized) {
1401 retval = EINVAL;
1402 break;
1403 }
1404 if (animations[i].animlen == MAX_ANIM_LEN) {
1405 retval = ELIMIT;
1406 break;
1407 }
1408 newval = IPC_GET_ARG2(*call);
1409 if (newval < 0 || newval > MAX_IMGMAPS ||
1410 !imgmaps[newval]) {
1411 retval = EINVAL;
1412 break;
1413 }
1414 animations[i].imgmaps[animations[i].animlen++] = newval;
1415 break;
1416 case FB_ANIM_CHGVP:
1417 i = IPC_GET_ARG1(*call);
1418 if (i >= MAX_ANIMATIONS || i < 0) {
1419 retval = EINVAL;
1420 break;
1421 }
1422 nvp = IPC_GET_ARG2(*call);
1423 if (nvp == -1)
1424 nvp = vp;
1425 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1426 !viewports[nvp].initialized) {
1427 retval = EINVAL;
1428 break;
1429 }
1430 animations[i].vp = nvp;
1431 break;
1432 case FB_ANIM_START:
1433 case FB_ANIM_STOP:
1434 i = IPC_GET_ARG1(*call);
1435 if (i >= MAX_ANIMATIONS || i < 0) {
1436 retval = EINVAL;
1437 break;
1438 }
1439 newval = (IPC_GET_IMETHOD(*call) == FB_ANIM_START);
1440 if (newval ^ animations[i].enabled) {
1441 animations[i].enabled = newval;
1442 anims_enabled += newval ? 1 : -1;
1443 }
1444 break;
1445 default:
1446 handled = 0;
1447 }
1448 if (handled)
1449 async_answer_0(callid, retval);
1450 return handled;
1451}
1452
1453/** Handler for messages concerning image map handling
1454 *
1455 */
1456static int imgmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1457{
1458 bool handled = true;
1459 int retval = EOK;
1460 int i, nvp;
1461
1462 switch (IPC_GET_IMETHOD(*call)) {
1463 case FB_VP_DRAW_IMGMAP:
1464 nvp = IPC_GET_ARG1(*call);
1465 if (nvp == -1)
1466 nvp = vp;
1467
1468 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1469 !viewports[nvp].initialized) {
1470 retval = EINVAL;
1471 break;
1472 }
1473
1474 i = IPC_GET_ARG2(*call);
1475 retval = draw_imgmap(nvp, i);
1476 break;
1477 case FB_VP2IMGMAP:
1478 nvp = IPC_GET_ARG1(*call);
1479 if (nvp == -1)
1480 nvp = vp;
1481
1482 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1483 !viewports[nvp].initialized) {
1484 retval = EINVAL;
1485 break;
1486 }
1487
1488 retval = save_vp_to_imgmap(&viewports[nvp]);
1489 break;
1490 case FB_DROP_IMGMAP:
1491 i = IPC_GET_ARG1(*call);
1492 if (i >= MAX_IMGMAPS) {
1493 retval = EINVAL;
1494 break;
1495 }
1496
1497 if (imgmaps[i]) {
1498 free(imgmaps[i]);
1499 imgmaps[i] = NULL;
1500 }
1501
1502 break;
1503 default:
1504 handled = 0;
1505 }
1506
1507 if (handled)
1508 async_answer_0(callid, retval);
1509 return handled;
1510
1511}
1512
1513static int rgb_from_style(attr_rgb_t *rgb, int style)
1514{
1515 switch (style) {
1516 case STYLE_NORMAL:
1517 rgb->fg_color = color_table[COLOR_BLACK];
1518 rgb->bg_color = color_table[COLOR_WHITE];
1519 break;
1520 case STYLE_EMPHASIS:
1521 rgb->fg_color = color_table[COLOR_RED];
1522 rgb->bg_color = color_table[COLOR_WHITE];
1523 break;
1524 case STYLE_INVERTED:
1525 rgb->fg_color = color_table[COLOR_WHITE];
1526 rgb->bg_color = color_table[COLOR_BLACK];
1527 break;
1528 case STYLE_SELECTED:
1529 rgb->fg_color = color_table[COLOR_WHITE];
1530 rgb->bg_color = color_table[COLOR_RED];
1531 break;
1532 default:
1533 return EINVAL;
1534 }
1535
1536 return EOK;
1537}
1538
1539static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color,
1540 sysarg_t bg_color, sysarg_t flags)
1541{
1542 fg_color = (fg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1543 bg_color = (bg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
1544
1545 rgb->fg_color = color_table[fg_color];
1546 rgb->bg_color = color_table[bg_color];
1547
1548 return EOK;
1549}
1550
1551static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a)
1552{
1553 int rc;
1554
1555 switch (a->t) {
1556 case at_style:
1557 rc = rgb_from_style(rgb, a->a.s.style);
1558 break;
1559 case at_idx:
1560 rc = rgb_from_idx(rgb, a->a.i.fg_color,
1561 a->a.i.bg_color, a->a.i.flags);
1562 break;
1563 case at_rgb:
1564 *rgb = a->a.r;
1565 rc = EOK;
1566 break;
1567 }
1568
1569 return rc;
1570}
1571
1572static int fb_set_style(viewport_t *vport, sysarg_t style)
1573{
1574 return rgb_from_style(&vport->attr, (int) style);
1575}
1576
1577static int fb_set_color(viewport_t *vport, sysarg_t fg_color,
1578 sysarg_t bg_color, sysarg_t flags)
1579{
1580 return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);
1581}
1582
1583/** Function for handling connections to FB
1584 *
1585 */
1586static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall,
1587 void *arg)
1588{
1589 unsigned int vp = 0;
1590 viewport_t *vport = &viewports[vp];
1591
1592 if (client_connected) {
1593 async_answer_0(iid, ELIMIT);
1594 return;
1595 }
1596
1597 /* Accept connection */
1598 client_connected = true;
1599 async_answer_0(iid, EOK);
1600
1601 while (true) {
1602 ipc_callid_t callid;
1603 ipc_call_t call;
1604 int retval;
1605 unsigned int i;
1606 int scroll;
1607 wchar_t ch;
1608 unsigned int col, row;
1609
1610 if ((vport->cursor_active) || (anims_enabled))
1611 callid = async_get_call_timeout(&call, 250000);
1612 else
1613 callid = async_get_call(&call);
1614
1615 mouse_hide();
1616 if (!callid) {
1617 cursor_blink(vport);
1618 anims_tick();
1619 mouse_show();
1620 continue;
1621 }
1622
1623 if (shm_handle(callid, &call, vp))
1624 continue;
1625
1626 if (imgmap_handle(callid, &call, vp))
1627 continue;
1628
1629 if (anim_handle(callid, &call, vp))
1630 continue;
1631
1632 if (!IPC_GET_IMETHOD(call)) {
1633 client_connected = false;
1634
1635 /* Cleanup other viewports */
1636 for (i = 1; i < MAX_VIEWPORTS; i++)
1637 vport->initialized = false;
1638
1639 /* Exit thread */
1640 return;
1641 }
1642
1643 switch (IPC_GET_IMETHOD(call)) {
1644 case FB_PUTCHAR:
1645 ch = IPC_GET_ARG1(call);
1646 col = IPC_GET_ARG2(call);
1647 row = IPC_GET_ARG3(call);
1648
1649 if ((col >= vport->cols) || (row >= vport->rows)) {
1650 retval = EINVAL;
1651 break;
1652 }
1653 async_answer_0(callid, EOK);
1654
1655 draw_char(vport, ch, col, row);
1656
1657 /* Message already answered */
1658 continue;
1659 case FB_CLEAR:
1660 vport_clear(vport);
1661 cursor_show(vport);
1662 retval = EOK;
1663 break;
1664 case FB_CURSOR_GOTO:
1665 col = IPC_GET_ARG1(call);
1666 row = IPC_GET_ARG2(call);
1667
1668 if ((col >= vport->cols) || (row >= vport->rows)) {
1669 retval = EINVAL;
1670 break;
1671 }
1672 retval = EOK;
1673
1674 cursor_hide(vport);
1675 vport->cur_col = col;
1676 vport->cur_row = row;
1677 cursor_show(vport);
1678 break;
1679 case FB_CURSOR_VISIBILITY:
1680 cursor_hide(vport);
1681 vport->cursor_active = IPC_GET_ARG1(call);
1682 cursor_show(vport);
1683 retval = EOK;
1684 break;
1685 case FB_GET_CSIZE:
1686 async_answer_2(callid, EOK, vport->cols, vport->rows);
1687 continue;
1688 case FB_GET_COLOR_CAP:
1689 async_answer_1(callid, EOK, FB_CCAP_RGB);
1690 continue;
1691 case FB_SCROLL:
1692 scroll = IPC_GET_ARG1(call);
1693 if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) {
1694 retval = EINVAL;
1695 break;
1696 }
1697 cursor_hide(vport);
1698 vport_scroll(vport, scroll);
1699 cursor_show(vport);
1700 retval = EOK;
1701 break;
1702 case FB_VIEWPORT_SWITCH:
1703 i = IPC_GET_ARG1(call);
1704 if (i >= MAX_VIEWPORTS) {
1705 retval = EINVAL;
1706 break;
1707 }
1708 if (!viewports[i].initialized) {
1709 retval = EADDRNOTAVAIL;
1710 break;
1711 }
1712 cursor_hide(vport);
1713 vp = i;
1714 vport = &viewports[vp];
1715 cursor_show(vport);
1716 retval = EOK;
1717 break;
1718 case FB_VIEWPORT_CREATE:
1719 retval = vport_create(IPC_GET_ARG1(call) >> 16,
1720 IPC_GET_ARG1(call) & 0xffff,
1721 IPC_GET_ARG2(call) >> 16,
1722 IPC_GET_ARG2(call) & 0xffff);
1723 break;
1724 case FB_VIEWPORT_DELETE:
1725 i = IPC_GET_ARG1(call);
1726 if (i >= MAX_VIEWPORTS) {
1727 retval = EINVAL;
1728 break;
1729 }
1730 if (!viewports[i].initialized) {
1731 retval = EADDRNOTAVAIL;
1732 break;
1733 }
1734 viewports[i].initialized = false;
1735 if (viewports[i].bgpixel)
1736 free(viewports[i].bgpixel);
1737 if (viewports[i].backbuf)
1738 free(viewports[i].backbuf);
1739 retval = EOK;
1740 break;
1741 case FB_SET_STYLE:
1742 retval = fb_set_style(vport, IPC_GET_ARG1(call));
1743 break;
1744 case FB_SET_COLOR:
1745 retval = fb_set_color(vport, IPC_GET_ARG1(call),
1746 IPC_GET_ARG2(call), IPC_GET_ARG3(call));
1747 break;
1748 case FB_SET_RGB_COLOR:
1749 vport->attr.fg_color = IPC_GET_ARG1(call);
1750 vport->attr.bg_color = IPC_GET_ARG2(call);
1751 retval = EOK;
1752 break;
1753 case FB_GET_RESOLUTION:
1754 async_answer_2(callid, EOK, screen.xres, screen.yres);
1755 continue;
1756 case FB_POINTER_MOVE:
1757 pointer_enabled = true;
1758 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
1759 retval = EOK;
1760 break;
1761 case FB_SCREEN_YIELD:
1762 case FB_SCREEN_RECLAIM:
1763 retval = EOK;
1764 break;
1765 default:
1766 retval = ENOENT;
1767 }
1768 async_answer_0(callid, retval);
1769 }
1770}
1771
1772/** Initialization of framebuffer
1773 *
1774 */
1775int fb_init(void)
1776{
1777 async_set_client_connection(fb_client_connection);
1778
1779 sysarg_t fb_ph_addr;
1780 if (sysinfo_get_value("fb.address.physical", &fb_ph_addr) != EOK)
1781 return -1;
1782
1783 sysarg_t fb_offset;
1784 if (sysinfo_get_value("fb.offset", &fb_offset) != EOK)
1785 fb_offset = 0;
1786
1787 sysarg_t fb_width;
1788 if (sysinfo_get_value("fb.width", &fb_width) != EOK)
1789 return -1;
1790
1791 sysarg_t fb_height;
1792 if (sysinfo_get_value("fb.height", &fb_height) != EOK)
1793 return -1;
1794
1795 sysarg_t fb_scanline;
1796 if (sysinfo_get_value("fb.scanline", &fb_scanline) != EOK)
1797 return -1;
1798
1799 sysarg_t fb_visual;
1800 if (sysinfo_get_value("fb.visual", &fb_visual) != EOK)
1801 return -1;
1802
1803 sysarg_t fbsize = fb_scanline * fb_height;
1804 void *fb_addr = as_get_mappable_page(fbsize);
1805
1806 if (physmem_map((void *) fb_ph_addr + fb_offset, fb_addr,
1807 ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE) != 0)
1808 return -1;
1809
1810 if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual))
1811 return 0;
1812
1813 return -1;
1814}
1815
1816/**
1817 * @}
1818 */
Note: See TracBrowser for help on using the repository browser.