source: mainline/uspace/srv/hid/fb/fb.c@ cc5908e

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

do not intermix low-level IPC methods with async framework methods

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