Remove notes about automatically generated context_offset.h
[helenos.git] / uspace / fb / fb.c
blob11e8635783255a300d13b6eb0448342795ab3933
1 /*
2 * Copyright (C) 2006 Jakub Vana
3 * Copyright (C) 2006 Ondrej Palkovsky
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 /**
31 * @defgroup fb Graphical framebuffer
32 * @brief HelenOS graphical framebuffer.
33 * @ingroup fbs
34 * @{
35 */
37 /** @file
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <string.h>
43 #include <ddi.h>
44 #include <sysinfo.h>
45 #include <align.h>
46 #include <as.h>
47 #include <ipc/fb.h>
48 #include <ipc/ipc.h>
49 #include <ipc/ns.h>
50 #include <ipc/services.h>
51 #include <kernel/errno.h>
52 #include <async.h>
54 #include "font-8x16.h"
55 #include "fb.h"
56 #include "main.h"
57 #include "../console/screenbuffer.h"
58 #include "ppm.h"
60 #include "pointer.xbm"
61 #include "pointer_mask.xbm"
63 #define DEFAULT_BGCOLOR 0xf0f0f0
64 #define DEFAULT_FGCOLOR 0x0
66 /***************************************************************/
67 /* Pixel specific fuctions */
69 typedef void (*conv2scr_fn_t)(void *, int);
70 typedef int (*conv2rgb_fn_t)(void *);
72 struct {
73 uint8_t *fbaddress;
75 unsigned int xres;
76 unsigned int yres;
77 unsigned int scanline;
78 unsigned int pixelbytes;
79 unsigned int invert_colors;
81 conv2scr_fn_t rgb2scr;
82 conv2rgb_fn_t scr2rgb;
83 } screen;
85 typedef struct {
86 int initialized;
87 unsigned int x, y;
88 unsigned int width, height;
90 /* Text support in window */
91 unsigned int rows, cols;
92 /* Style for text printing */
93 style_t style;
94 /* Auto-cursor position */
95 int cursor_active, cur_col, cur_row;
96 int cursor_shown;
97 /* Double buffering */
98 uint8_t *dbdata;
99 unsigned int dboffset;
100 unsigned int paused;
101 } viewport_t;
103 #define MAX_ANIM_LEN 8
104 #define MAX_ANIMATIONS 4
105 typedef struct {
106 int initialized;
107 int enabled;
108 unsigned int vp;
110 unsigned int pos;
111 unsigned int animlen;
112 unsigned int pixmaps[MAX_ANIM_LEN];
113 } animation_t;
114 static animation_t animations[MAX_ANIMATIONS];
115 static int anims_enabled;
117 /** Maximum number of saved pixmaps
118 * Pixmap is a saved rectangle
120 #define MAX_PIXMAPS 256
121 typedef struct {
122 unsigned int width;
123 unsigned int height;
124 uint8_t *data;
125 } pixmap_t;
126 static pixmap_t pixmaps[MAX_PIXMAPS];
128 /* Viewport is a rectangular area on the screen */
129 #define MAX_VIEWPORTS 128
130 static viewport_t viewports[128];
132 /* Allow only 1 connection */
133 static int client_connected = 0;
135 #define RED(x, bits) ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
136 #define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
137 #define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
139 #define COL_WIDTH 8
140 #define ROW_BYTES (screen.scanline * FONT_SCANLINES)
142 #define POINTPOS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
144 static inline int COLOR(int color)
146 return screen.invert_colors ? ~color : color;
149 /* Conversion routines between different color representations */
150 static void rgb_4byte(void *dst, int rgb)
152 *(int *)dst = rgb;
155 static int byte4_rgb(void *src)
157 return (*(int *)src) & 0xffffff;
160 static void rgb_3byte(void *dst, int rgb)
162 uint8_t *scr = dst;
163 #if defined(FB_INVERT_ENDIAN)
164 scr[0] = RED(rgb, 8);
165 scr[1] = GREEN(rgb, 8);
166 scr[2] = BLUE(rgb, 8);
167 #else
168 scr[2] = RED(rgb, 8);
169 scr[1] = GREEN(rgb, 8);
170 scr[0] = BLUE(rgb, 8);
171 #endif
174 static int byte3_rgb(void *src)
176 uint8_t *scr = src;
177 #if defined(FB_INVERT_ENDIAN)
178 return scr[0] << 16 | scr[1] << 8 | scr[2];
179 #else
180 return scr[2] << 16 | scr[1] << 8 | scr[0];
181 #endif
184 /** 16-bit depth (5:6:5) */
185 static void rgb_2byte(void *dst, int rgb)
187 /* 5-bit, 6-bits, 5-bits */
188 *((uint16_t *)(dst)) = RED(rgb, 5) << 11 | GREEN(rgb, 6) << 5 | BLUE(rgb, 5);
191 /** 16-bit depth (5:6:5) */
192 static int byte2_rgb(void *src)
194 int color = *(uint16_t *)(src);
195 return (((color >> 11) & 0x1f) << (16 + 3)) | (((color >> 5) & 0x3f) << (8 + 2)) | ((color & 0x1f) << 3);
198 /** Put pixel - 8-bit depth (3:2:3) */
199 static void rgb_1byte(void *dst, int rgb)
201 *(uint8_t *)dst = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 | BLUE(rgb, 3);
204 /** Return pixel color - 8-bit depth (3:2:3) */
205 static int byte1_rgb(void *src)
207 int color = *(uint8_t *)src;
208 return (((color >> 5) & 0x7) << (16 + 5)) | (((color >> 3) & 0x3) << (8 + 6)) | ((color & 0x7) << 5);
211 /** Put pixel into viewport
213 * @param vport Viewport identification
214 * @param x X coord relative to viewport
215 * @param y Y coord relative to viewport
216 * @param color RGB color
218 static void putpixel(viewport_t *vport, unsigned int x, unsigned int y, int color)
220 int dx = vport->x + x;
221 int dy = vport->y + y;
223 if (! (vport->paused && vport->dbdata))
224 (*screen.rgb2scr)(&screen.fbaddress[POINTPOS(dx,dy)], COLOR(color));
226 if (vport->dbdata) {
227 int dline = (y + vport->dboffset) % vport->height;
228 int doffset = screen.pixelbytes * (dline * vport->width + x);
229 (*screen.rgb2scr)(&vport->dbdata[doffset], COLOR(color));
233 /** Get pixel from viewport */
234 static int getpixel(viewport_t *vport, unsigned int x, unsigned int y)
236 int dx = vport->x + x;
237 int dy = vport->y + y;
239 return COLOR((*screen.scr2rgb)(&screen.fbaddress[POINTPOS(dx,dy)]));
242 static inline void putpixel_mem(char *mem, unsigned int x, unsigned int y,
243 int color)
245 (*screen.rgb2scr)(&mem[POINTPOS(x,y)], COLOR(color));
248 static void draw_rectangle(viewport_t *vport, unsigned int sx, unsigned int sy,
249 unsigned int width, unsigned int height,
250 int color)
252 unsigned int x, y;
253 static void *tmpline;
255 if (!tmpline)
256 tmpline = malloc(screen.scanline*screen.pixelbytes);
258 /* Clear first line */
259 for (x = 0; x < width; x++)
260 putpixel_mem(tmpline, x, 0, color);
262 if (!vport->paused) {
263 /* Recompute to screen coords */
264 sx += vport->x;
265 sy += vport->y;
266 /* Copy the rest */
267 for (y = sy;y < sy+height; y++)
268 memcpy(&screen.fbaddress[POINTPOS(sx,y)], tmpline,
269 screen.pixelbytes * width);
271 if (vport->dbdata) {
272 for (y=sy;y < sy+height; y++) {
273 int rline = (y + vport->dboffset) % vport->height;
274 int rpos = (rline * vport->width + sx) * screen.pixelbytes;
275 memcpy(&vport->dbdata[rpos], tmpline, screen.pixelbytes * width);
281 /** Fill viewport with background color */
282 static void clear_port(viewport_t *vport)
284 draw_rectangle(vport, 0, 0, vport->width, vport->height, vport->style.bg_color);
287 /** Scroll unbuffered viewport up/down
289 * @param vport Viewport to scroll
290 * @param lines Positive number - scroll up, negative - scroll down
292 static void scroll_port_nodb(viewport_t *vport, int lines)
294 int y;
296 if (lines > 0) {
297 for (y=vport->y; y < vport->y+vport->height - lines; y++)
298 memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
299 &screen.fbaddress[POINTPOS(vport->x,y + lines)],
300 screen.pixelbytes * vport->width);
301 draw_rectangle(vport, 0, vport->height - lines,
302 vport->width, lines, vport->style.bg_color);
303 } else if (lines < 0) {
304 lines = -lines;
305 for (y=vport->y + vport->height-1; y >= vport->y + lines; y--)
306 memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
307 &screen.fbaddress[POINTPOS(vport->x,y - lines)],
308 screen.pixelbytes * vport->width);
309 draw_rectangle(vport, 0, 0, vport->width, lines, vport->style.bg_color);
313 /** Refresh given viewport from double buffer */
314 static void refresh_viewport_db(viewport_t *vport)
316 unsigned int y, srcy, srcoff, dsty, dstx;
318 for (y = 0; y < vport->height; y++) {
319 srcy = (y + vport->dboffset) % vport->height;
320 srcoff = (vport->width * srcy) * screen.pixelbytes;
322 dstx = vport->x;
323 dsty = vport->y + y;
325 memcpy(&screen.fbaddress[POINTPOS(dstx,dsty)],
326 &vport->dbdata[srcoff],
327 vport->width*screen.pixelbytes);
331 /** Scroll viewport that has double buffering enabled */
332 static void scroll_port_db(viewport_t *vport, int lines)
334 ++vport->paused;
335 if (lines > 0) {
336 draw_rectangle(vport, 0, 0, vport->width, lines,
337 vport->style.bg_color);
338 vport->dboffset += lines;
339 vport->dboffset %= vport->height;
340 } else if (lines < 0) {
341 lines = -lines;
342 draw_rectangle(vport, 0, vport->height-lines,
343 vport->width, lines,
344 vport->style.bg_color);
346 if (vport->dboffset < lines)
347 vport->dboffset += vport->height;
348 vport->dboffset -= lines;
351 --vport->paused;
353 refresh_viewport_db(vport);
356 /** Scrolls viewport given number of lines */
357 static void scroll_port(viewport_t *vport, int lines)
359 if (vport->dbdata)
360 scroll_port_db(vport, lines);
361 else
362 scroll_port_nodb(vport, lines);
366 static void invert_pixel(viewport_t *vport, unsigned int x, unsigned int y)
368 putpixel(vport, x, y, ~getpixel(vport, x, y));
372 /***************************************************************/
373 /* Character-console functions */
375 /** Draw character at given position
377 * @param vport Viewport where the character is printed
378 * @param sx Coordinates of top-left of the character
379 * @param sy Coordinates of top-left of the character
380 * @param style Color of the character
381 * @param transparent If false, print background color
383 static void draw_glyph(viewport_t *vport,uint8_t glyph, unsigned int sx, unsigned int sy,
384 style_t style, int transparent)
386 int i;
387 unsigned int y;
388 unsigned int glline;
390 for (y = 0; y < FONT_SCANLINES; y++) {
391 glline = fb_font[glyph * FONT_SCANLINES + y];
392 for (i = 0; i < 8; i++) {
393 if (glline & (1 << (7 - i)))
394 putpixel(vport, sx + i, sy + y, style.fg_color);
395 else if (!transparent)
396 putpixel(vport, sx + i, sy + y, style.bg_color);
401 /** Invert character at given position */
402 static void invert_char(viewport_t *vport,unsigned int row, unsigned int col)
404 unsigned int x;
405 unsigned int y;
407 for (x = 0; x < COL_WIDTH; x++)
408 for (y = 0; y < FONT_SCANLINES; y++)
409 invert_pixel(vport, col * COL_WIDTH + x, row * FONT_SCANLINES + y);
412 /***************************************************************/
413 /* Stdout specific functions */
416 /** Create new viewport
418 * @return New viewport number
420 static int viewport_create(unsigned int x, unsigned int y,unsigned int width,
421 unsigned int height)
423 int i;
425 for (i=0; i < MAX_VIEWPORTS; i++) {
426 if (!viewports[i].initialized)
427 break;
429 if (i == MAX_VIEWPORTS)
430 return ELIMIT;
432 viewports[i].x = x;
433 viewports[i].y = y;
434 viewports[i].width = width;
435 viewports[i].height = height;
437 viewports[i].rows = height / FONT_SCANLINES;
438 viewports[i].cols = width / COL_WIDTH;
440 viewports[i].style.bg_color = DEFAULT_BGCOLOR;
441 viewports[i].style.fg_color = DEFAULT_FGCOLOR;
443 viewports[i].cur_col = 0;
444 viewports[i].cur_row = 0;
445 viewports[i].cursor_active = 0;
447 viewports[i].initialized = 1;
449 return i;
453 /** Initialize framebuffer as a chardev output device
455 * @param addr Address of theframebuffer
456 * @param xres Screen width in pixels
457 * @param yres Screen height in pixels
458 * @param bpp Bits per pixel (8, 16, 24, 32)
459 * @param scan Bytes per one scanline
460 * @param align Alignment for 24bpp mode.
461 * @param invert_colors Inverted colors.
464 static void
465 screen_init(void *addr, unsigned int xres, unsigned int yres, unsigned int bpp, unsigned int scan,
466 int align, int invert_colors)
468 switch (bpp) {
469 case 8:
470 screen.rgb2scr = rgb_1byte;
471 screen.scr2rgb = byte1_rgb;
472 screen.pixelbytes = 1;
473 break;
474 case 16:
475 screen.rgb2scr = rgb_2byte;
476 screen.scr2rgb = byte2_rgb;
477 screen.pixelbytes = 2;
478 break;
479 case 24:
480 screen.rgb2scr = rgb_3byte;
481 screen.scr2rgb = byte3_rgb;
482 if (!align)
483 screen.pixelbytes = 3;
484 else
485 screen.pixelbytes = 4;
486 break;
487 case 32:
488 screen.rgb2scr = rgb_4byte;
489 screen.scr2rgb = byte4_rgb;
490 screen.pixelbytes = 4;
491 break;
494 screen.fbaddress = (unsigned char *) addr;
495 screen.xres = xres;
496 screen.yres = yres;
497 screen.scanline = scan;
498 screen.invert_colors = invert_colors;
500 /* Create first viewport */
501 viewport_create(0,0,xres,yres);
504 /** Hide cursor if it is shown */
505 static void cursor_hide(viewport_t *vport)
507 if (vport->cursor_active && vport->cursor_shown) {
508 invert_char(vport, vport->cur_row, vport->cur_col);
509 vport->cursor_shown = 0;
513 /** Show cursor if cursor showing is enabled */
514 static void cursor_print(viewport_t *vport)
516 /* Do not check for cursor_shown */
517 if (vport->cursor_active) {
518 invert_char(vport, vport->cur_row, vport->cur_col);
519 vport->cursor_shown = 1;
523 /** Invert cursor, if it is enabled */
524 static void cursor_blink(viewport_t *vport)
526 if (vport->cursor_shown)
527 cursor_hide(vport);
528 else
529 cursor_print(vport);
532 /** Draw character at given position relative to viewport
534 * @param vport Viewport identification
535 * @param c Character to print
536 * @param row Screen position relative to viewport
537 * @param col Screen position relative to viewport
538 * @param transparent If false, print background color with character
540 static void draw_char(viewport_t *vport, char c, unsigned int row, unsigned int col,
541 style_t style, int transparent)
543 /* Optimize - do not hide cursor if we are going to overwrite it */
544 if (vport->cursor_active && vport->cursor_shown &&
545 (vport->cur_col != col || vport->cur_row != row))
546 invert_char(vport, vport->cur_row, vport->cur_col);
548 draw_glyph(vport, c, col * COL_WIDTH, row * FONT_SCANLINES, style, transparent);
550 vport->cur_col = col;
551 vport->cur_row = row;
553 vport->cur_col++;
554 if (vport->cur_col>= vport->cols) {
555 vport->cur_col = 0;
556 vport->cur_row++;
557 if (vport->cur_row >= vport->rows)
558 vport->cur_row--;
560 cursor_print(vport);
563 /** Draw text data to viewport
565 * @param vport Viewport id
566 * @param data Text data fitting exactly into viewport
568 static void draw_text_data(viewport_t *vport, keyfield_t *data)
570 int i;
571 int col,row;
573 clear_port(vport);
574 for (i=0; i < vport->cols * vport->rows; i++) {
575 if (data[i].character == ' ' && style_same(data[i].style,vport->style))
576 continue;
577 col = i % vport->cols;
578 row = i / vport->cols;
579 draw_glyph(vport, data[i].character, col * COL_WIDTH, row * FONT_SCANLINES,
580 data[i].style, style_same(data[i].style,vport->style));
582 cursor_print(vport);
586 /** Return first free pixmap */
587 static int find_free_pixmap(void)
589 int i;
591 for (i=0;i < MAX_PIXMAPS;i++)
592 if (!pixmaps[i].data)
593 return i;
594 return -1;
597 static void putpixel_pixmap(int pm, unsigned int x, unsigned int y, int color)
599 pixmap_t *pmap = &pixmaps[pm];
600 int pos = (y * pmap->width + x) * screen.pixelbytes;
602 (*screen.rgb2scr)(&pmap->data[pos],COLOR(color));
605 /** Create a new pixmap and return appropriate ID */
606 static int shm2pixmap(unsigned char *shm, size_t size)
608 int pm;
609 pixmap_t *pmap;
611 pm = find_free_pixmap();
612 if (pm == -1)
613 return ELIMIT;
614 pmap = &pixmaps[pm];
616 if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
617 return EINVAL;
619 pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
620 if (!pmap->data)
621 return ENOMEM;
623 ppm_draw(shm, size, 0, 0, pmap->width, pmap->height,
624 (putpixel_cb_t)putpixel_pixmap, (void *)pm);
626 return pm;
629 /** Handle shared memory communication calls
631 * Protocol for drawing pixmaps:
632 * - FB_PREPARE_SHM(client shm identification)
633 * - IPC_M_SEND_AS_AREA
634 * - FB_DRAW_PPM(startx,starty)
635 * - FB_DROP_SHM
637 * Protocol for text drawing
638 * - IPC_M_SEND_AS_AREA
639 * - FB_DRAW_TEXT_DATA
641 * @param callid Callid of the current call
642 * @param call Current call data
643 * @param vp Active viewport
644 * @return 0 if the call was not handled byt this function, 1 otherwise
646 * note: this function is not threads safe, you would have
647 * to redefine static variables with __thread
649 static int shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
651 static keyfield_t *interbuffer = NULL;
652 static size_t intersize = 0;
654 static unsigned char *shm = NULL;
655 static ipcarg_t shm_id = 0;
656 static size_t shm_size;
658 int handled = 1;
659 int retval = 0;
660 viewport_t *vport = &viewports[vp];
661 unsigned int x,y;
663 switch (IPC_GET_METHOD(*call)) {
664 case IPC_M_AS_AREA_SEND:
665 /* We accept one area for data interchange */
666 if (IPC_GET_ARG1(*call) == shm_id) {
667 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
668 shm_size = IPC_GET_ARG2(*call);
669 if (!ipc_answer_fast(callid, 0, (sysarg_t)dest, 0))
670 shm = dest;
671 else
672 shm_id = 0;
673 if (shm[0] != 'P')
674 while (1)
676 return 1;
677 } else {
678 intersize = IPC_GET_ARG2(*call);
679 receive_comm_area(callid,call,(void *)&interbuffer);
681 return 1;
682 case FB_PREPARE_SHM:
683 if (shm_id)
684 retval = EBUSY;
685 else
686 shm_id = IPC_GET_ARG1(*call);
687 break;
689 case FB_DROP_SHM:
690 if (shm) {
691 as_area_destroy(shm);
692 shm = NULL;
694 shm_id = 0;
695 break;
697 case FB_SHM2PIXMAP:
698 if (!shm) {
699 retval = EINVAL;
700 break;
702 retval = shm2pixmap(shm, shm_size);
703 break;
704 case FB_DRAW_PPM:
705 if (!shm) {
706 retval = EINVAL;
707 break;
709 x = IPC_GET_ARG1(*call);
710 y = IPC_GET_ARG2(*call);
711 if (x > vport->width || y > vport->height) {
712 retval = EINVAL;
713 break;
716 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call), IPC_GET_ARG2(*call),
717 vport->width - x, vport->height - y, (putpixel_cb_t)putpixel, vport);
718 break;
719 case FB_DRAW_TEXT_DATA:
720 if (!interbuffer) {
721 retval = EINVAL;
722 break;
724 if (intersize < vport->cols*vport->rows*sizeof(*interbuffer)) {
725 retval = EINVAL;
726 break;
728 draw_text_data(vport, interbuffer);
729 break;
730 default:
731 handled = 0;
734 if (handled)
735 ipc_answer_fast(callid, retval, 0, 0);
736 return handled;
739 static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
741 int y;
742 int rowsize;
743 int tmp;
744 int width = vport->width;
745 int height = vport->height;
747 if (width + vport->x > screen.xres)
748 width = screen.xres - vport->x;
749 if (height + vport->y > screen.yres)
750 height = screen.yres - vport->y;
752 rowsize = width * screen.pixelbytes;
754 for (y=0;y < height; y++) {
755 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
756 memcpy(pmap->data + rowsize*y, screen.fbaddress + tmp, rowsize);
760 /** Save viewport to pixmap */
761 static int save_vp_to_pixmap(viewport_t *vport)
763 int pm;
764 pixmap_t *pmap;
766 pm = find_free_pixmap();
767 if (pm == -1)
768 return ELIMIT;
770 pmap = &pixmaps[pm];
771 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
772 if (!pmap->data)
773 return ENOMEM;
775 pmap->width = vport->width;
776 pmap->height = vport->height;
778 copy_vp_to_pixmap(vport, pmap);
780 return pm;
783 /** Draw pixmap on screen
785 * @param vp Viewport to draw on
786 * @param pm Pixmap identifier
788 static int draw_pixmap(int vp, int pm)
790 pixmap_t *pmap = &pixmaps[pm];
791 viewport_t *vport = &viewports[vp];
792 int y;
793 int tmp, srcrowsize;
794 int realwidth, realheight, realrowsize;
795 int width = vport->width;
796 int height = vport->height;
798 if (width + vport->x > screen.xres)
799 width = screen.xres - vport->x;
800 if (height + vport->y > screen.yres)
801 height = screen.yres - vport->y;
803 if (!pmap->data)
804 return EINVAL;
806 realwidth = pmap->width <= width ? pmap->width : width;
807 realheight = pmap->height <= height ? pmap->height : height;
809 srcrowsize = vport->width * screen.pixelbytes;
810 realrowsize = realwidth * screen.pixelbytes;
812 for (y=0; y < realheight; y++) {
813 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
814 memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize, realrowsize);
816 return 0;
819 /** Tick animation one step forward */
820 static void anims_tick(void)
822 int i;
823 static int counts = 0;
825 /* Limit redrawing */
826 counts = (counts+1) % 8;
827 if (counts)
828 return;
830 for (i=0; i < MAX_ANIMATIONS; i++) {
831 if (!animations[i].animlen || !animations[i].initialized || !animations[i].enabled)
832 continue;
833 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
834 animations[i].pos = (animations[i].pos+1) % animations[i].animlen;
839 static int pointer_x, pointer_y;
840 static int pointer_shown, pointer_enabled;
841 static int pointer_vport = -1;
842 static int pointer_pixmap = -1;
844 static void mouse_show(void)
846 int i,j;
847 int visibility;
848 int color;
849 int bytepos;
851 if (pointer_shown || !pointer_enabled)
852 return;
854 /* Save image under the cursor */
855 if (pointer_vport == -1) {
856 pointer_vport = viewport_create(pointer_x, pointer_y, pointer_width, pointer_height);
857 if (pointer_vport < 0)
858 return;
859 } else {
860 viewports[pointer_vport].x = pointer_x;
861 viewports[pointer_vport].y = pointer_y;
864 if (pointer_pixmap == -1)
865 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
866 else
867 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
869 /* Draw cursor */
870 for (i=0; i < pointer_height; i++)
871 for (j=0;j < pointer_width; j++) {
872 bytepos = i*((pointer_width-1)/8+1) + j/8;
873 visibility = pointer_mask_bits[bytepos] & (1 << (j % 8));
874 if (visibility) {
875 color = pointer_bits[bytepos] & (1 << (j % 8)) ? 0 : 0xffffff;
876 if (pointer_x+j < screen.xres && pointer_y+i < screen.yres)
877 putpixel(&viewports[0], pointer_x+j, pointer_y+i, color);
880 pointer_shown = 1;
883 static void mouse_hide(void)
885 /* Restore image under the cursor */
886 if (pointer_shown) {
887 draw_pixmap(pointer_vport, pointer_pixmap);
888 pointer_shown = 0;
892 static void mouse_move(unsigned int x, unsigned int y)
894 mouse_hide();
895 pointer_x = x;
896 pointer_y = y;
897 mouse_show();
900 static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
902 int handled = 1;
903 int retval = 0;
904 int i,nvp;
905 int newval;
907 switch (IPC_GET_METHOD(*call)) {
908 case FB_ANIM_CREATE:
909 nvp = IPC_GET_ARG1(*call);
910 if (nvp == -1)
911 nvp = vp;
912 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
913 retval = EINVAL;
914 break;
916 for (i=0; i < MAX_ANIMATIONS; i++) {
917 if (! animations[i].initialized)
918 break;
920 if (i == MAX_ANIMATIONS) {
921 retval = ELIMIT;
922 break;
924 animations[i].initialized = 1;
925 animations[i].animlen = 0;
926 animations[i].pos = 0;
927 animations[i].enabled = 0;
928 animations[i].vp = nvp;
929 retval = i;
930 break;
931 case FB_ANIM_DROP:
932 i = IPC_GET_ARG1(*call);
933 if (i >= MAX_ANIMATIONS || i < 0) {
934 retval = EINVAL;
935 break;
937 animations[i].initialized = 0;
938 break;
939 case FB_ANIM_ADDPIXMAP:
940 i = IPC_GET_ARG1(*call);
941 if (i >= MAX_ANIMATIONS || i < 0 || !animations[i].initialized) {
942 retval = EINVAL;
943 break;
945 if (animations[i].animlen == MAX_ANIM_LEN) {
946 retval = ELIMIT;
947 break;
949 newval = IPC_GET_ARG2(*call);
950 if (newval < 0 || newval > MAX_PIXMAPS || !pixmaps[newval].data) {
951 retval = EINVAL;
952 break;
954 animations[i].pixmaps[animations[i].animlen++] = newval;
955 break;
956 case FB_ANIM_CHGVP:
957 i = IPC_GET_ARG1(*call);
958 if (i >= MAX_ANIMATIONS || i < 0) {
959 retval = EINVAL;
960 break;
962 nvp = IPC_GET_ARG2(*call);
963 if (nvp == -1)
964 nvp = vp;
965 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
966 retval = EINVAL;
967 break;
969 animations[i].vp = nvp;
970 break;
971 case FB_ANIM_START:
972 case FB_ANIM_STOP:
973 i = IPC_GET_ARG1(*call);
974 if (i >= MAX_ANIMATIONS || i < 0) {
975 retval = EINVAL;
976 break;
978 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
979 if (newval ^ animations[i].enabled) {
980 animations[i].enabled = newval;
981 anims_enabled += newval ? 1 : -1;
983 break;
984 default:
985 handled = 0;
987 if (handled)
988 ipc_answer_fast(callid, retval, 0, 0);
989 return handled;
992 /** Handler for messages concerning pixmap handling */
993 static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
995 int handled = 1;
996 int retval = 0;
997 int i,nvp;
999 switch (IPC_GET_METHOD(*call)) {
1000 case FB_VP_DRAW_PIXMAP:
1001 nvp = IPC_GET_ARG1(*call);
1002 if (nvp == -1)
1003 nvp = vp;
1004 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized) {
1005 retval = EINVAL;
1006 break;
1008 i = IPC_GET_ARG2(*call);
1009 retval = draw_pixmap(nvp, i);
1010 break;
1011 case FB_VP2PIXMAP:
1012 nvp = IPC_GET_ARG1(*call);
1013 if (nvp == -1)
1014 nvp = vp;
1015 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized)
1016 retval = EINVAL;
1017 else
1018 retval = save_vp_to_pixmap(&viewports[nvp]);
1019 break;
1020 case FB_DROP_PIXMAP:
1021 i = IPC_GET_ARG1(*call);
1022 if (i >= MAX_PIXMAPS) {
1023 retval = EINVAL;
1024 break;
1026 if (pixmaps[i].data) {
1027 free(pixmaps[i].data);
1028 pixmaps[i].data = NULL;
1030 break;
1031 default:
1032 handled = 0;
1035 if (handled)
1036 ipc_answer_fast(callid, retval, 0, 0);
1037 return handled;
1041 /** Function for handling connections to FB
1044 static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
1046 ipc_callid_t callid;
1047 ipc_call_t call;
1048 int retval;
1049 int i;
1050 unsigned int row,col;
1051 char c;
1053 int vp = 0;
1054 viewport_t *vport = &viewports[0];
1056 if (client_connected) {
1057 ipc_answer_fast(iid, ELIMIT, 0,0);
1058 return;
1060 client_connected = 1;
1061 ipc_answer_fast(iid, 0, 0, 0); /* Accept connection */
1063 while (1) {
1064 if (vport->cursor_active || anims_enabled)
1065 callid = async_get_call_timeout(&call,250000);
1066 else
1067 callid = async_get_call(&call);
1069 mouse_hide();
1070 if (!callid) {
1071 cursor_blink(vport);
1072 anims_tick();
1073 mouse_show();
1074 continue;
1076 if (shm_handle(callid, &call, vp))
1077 continue;
1078 if (pixmap_handle(callid, &call, vp))
1079 continue;
1080 if (anim_handle(callid, &call, vp))
1081 continue;
1083 switch (IPC_GET_METHOD(call)) {
1084 case IPC_M_PHONE_HUNGUP:
1085 client_connected = 0;
1086 /* cleanup other viewports */
1087 for (i=1; i < MAX_VIEWPORTS; i++)
1088 vport->initialized = 0;
1089 return; /* Exit thread */
1091 case FB_PUTCHAR:
1092 case FB_TRANS_PUTCHAR:
1093 c = IPC_GET_ARG1(call);
1094 row = IPC_GET_ARG2(call);
1095 col = IPC_GET_ARG3(call);
1096 if (row >= vport->rows || col >= vport->cols) {
1097 retval = EINVAL;
1098 break;
1100 ipc_answer_fast(callid,0,0,0);
1102 draw_char(vport, c, row, col, vport->style, IPC_GET_METHOD(call) == FB_TRANS_PUTCHAR);
1103 continue; /* msg already answered */
1104 case FB_CLEAR:
1105 clear_port(vport);
1106 cursor_print(vport);
1107 retval = 0;
1108 break;
1109 case FB_CURSOR_GOTO:
1110 row = IPC_GET_ARG1(call);
1111 col = IPC_GET_ARG2(call);
1112 if (row >= vport->rows || col >= vport->cols) {
1113 retval = EINVAL;
1114 break;
1116 retval = 0;
1117 cursor_hide(vport);
1118 vport->cur_col = col;
1119 vport->cur_row = row;
1120 cursor_print(vport);
1121 break;
1122 case FB_CURSOR_VISIBILITY:
1123 cursor_hide(vport);
1124 vport->cursor_active = IPC_GET_ARG1(call);
1125 cursor_print(vport);
1126 retval = 0;
1127 break;
1128 case FB_GET_CSIZE:
1129 ipc_answer_fast(callid, 0, vport->rows, vport->cols);
1130 continue;
1131 case FB_SCROLL:
1132 i = IPC_GET_ARG1(call);
1133 if (i > vport->rows || i < (- (int)vport->rows)) {
1134 retval = EINVAL;
1135 break;
1137 cursor_hide(vport);
1138 scroll_port(vport, i*FONT_SCANLINES);
1139 cursor_print(vport);
1140 retval = 0;
1141 break;
1142 case FB_VIEWPORT_DB:
1143 /* Enable double buffering */
1144 i = IPC_GET_ARG1(call);
1145 if (i == -1)
1146 i = vp;
1147 if (i < 0 || i >= MAX_VIEWPORTS) {
1148 retval = EINVAL;
1149 break;
1151 if (! viewports[i].initialized ) {
1152 retval = EADDRNOTAVAIL;
1153 break;
1155 viewports[i].dboffset = 0;
1156 if (IPC_GET_ARG2(call) == 1 && !viewports[i].dbdata)
1157 viewports[i].dbdata = malloc(screen.pixelbytes*viewports[i].width * viewports[i].height);
1158 else if (IPC_GET_ARG2(call) == 0 && viewports[i].dbdata) {
1159 free(viewports[i].dbdata);
1160 viewports[i].dbdata = NULL;
1162 retval = 0;
1163 break;
1164 case FB_VIEWPORT_SWITCH:
1165 i = IPC_GET_ARG1(call);
1166 if (i < 0 || i >= MAX_VIEWPORTS) {
1167 retval = EINVAL;
1168 break;
1170 if (! viewports[i].initialized ) {
1171 retval = EADDRNOTAVAIL;
1172 break;
1174 cursor_hide(vport);
1175 vp = i;
1176 vport = &viewports[vp];
1177 cursor_print(vport);
1178 retval = 0;
1179 break;
1180 case FB_VIEWPORT_CREATE:
1181 retval = viewport_create(IPC_GET_ARG1(call) >> 16,
1182 IPC_GET_ARG1(call) & 0xffff,
1183 IPC_GET_ARG2(call) >> 16,
1184 IPC_GET_ARG2(call) & 0xffff);
1185 break;
1186 case FB_VIEWPORT_DELETE:
1187 i = IPC_GET_ARG1(call);
1188 if (i < 0 || i >= MAX_VIEWPORTS) {
1189 retval = EINVAL;
1190 break;
1192 if (! viewports[i].initialized ) {
1193 retval = EADDRNOTAVAIL;
1194 break;
1196 viewports[i].initialized = 0;
1197 if (viewports[i].dbdata) {
1198 free(viewports[i].dbdata);
1199 viewports[i].dbdata = NULL;
1201 retval = 0;
1202 break;
1203 case FB_SET_STYLE:
1204 vport->style.fg_color = IPC_GET_ARG1(call);
1205 vport->style.bg_color = IPC_GET_ARG2(call);
1206 retval = 0;
1207 break;
1208 case FB_GET_RESOLUTION:
1209 ipc_answer_fast(callid, 0, screen.xres,screen.yres);
1210 continue;
1211 case FB_POINTER_MOVE:
1212 pointer_enabled = 1;
1213 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
1214 retval = 0;
1215 break;
1216 default:
1217 retval = ENOENT;
1219 ipc_answer_fast(callid,retval,0,0);
1223 /** Initialization of framebuffer */
1224 int fb_init(void)
1226 void *fb_ph_addr;
1227 unsigned int fb_width;
1228 unsigned int fb_height;
1229 unsigned int fb_bpp;
1230 unsigned int fb_bpp_align;
1231 unsigned int fb_scanline;
1232 unsigned int fb_invert_colors;
1233 void *fb_addr;
1234 size_t asz;
1236 async_set_client_connection(fb_client_connection);
1238 fb_ph_addr = (void *) sysinfo_value("fb.address.physical");
1239 fb_width = sysinfo_value("fb.width");
1240 fb_height = sysinfo_value("fb.height");
1241 fb_bpp = sysinfo_value("fb.bpp");
1242 fb_bpp_align = sysinfo_value("fb.bpp-align");
1243 fb_scanline = sysinfo_value("fb.scanline");
1244 fb_invert_colors = sysinfo_value("fb.invert-colors");
1246 asz = fb_scanline*fb_height;
1247 fb_addr = as_get_mappable_page(asz);
1249 map_physmem(fb_ph_addr, fb_addr, ALIGN_UP(asz,PAGE_SIZE) >>PAGE_WIDTH,
1250 AS_AREA_READ | AS_AREA_WRITE);
1252 screen_init(fb_addr, fb_width, fb_height, fb_bpp, fb_scanline, fb_bpp_align, fb_invert_colors);
1253 return 0;
1256 /**
1257 * @}