source: mainline/uspace/srv/fb/fb.c@ fc0110d

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

Use better method names.

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