source: mainline/uspace/srv/fb/fb.c@ 62140db

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 62140db was 0471786, checked in by Jiri Svoboda <jirik.svoboda@…>, 16 years ago

Fix signedness issues and warnings in fb.

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