2 * Copyright (c) 2006 Jakub Vana
3 * Copyright (c) 2006 Ondrej Palkovsky
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
31 * @defgroup fb Graphical framebuffer
32 * @brief HelenOS graphical framebuffer.
50 #include <ipc/services.h>
51 #include <kernel/errno.h>
52 #include <kernel/genarch/fb/visuals.h>
56 #include "font-8x16.h"
59 #include "../console/screenbuffer.h"
62 #include "pointer.xbm"
63 #include "pointer_mask.xbm"
65 #define DEFAULT_BGCOLOR 0xf0f0f0
66 #define DEFAULT_FGCOLOR 0x0
68 /***************************************************************/
69 /* Pixel specific fuctions */
71 typedef void (*conv2scr_fn_t
)(void *, int);
72 typedef int (*conv2rgb_fn_t
)(void *);
79 unsigned int scanline
;
80 unsigned int pixelbytes
;
81 unsigned int invert_colors
;
83 conv2scr_fn_t rgb2scr
;
84 conv2rgb_fn_t scr2rgb
;
90 unsigned int width
, height
;
92 /* Text support in window */
93 unsigned int rows
, cols
;
94 /* Style for text printing */
96 /* Auto-cursor position */
97 int cursor_active
, cur_col
, cur_row
;
99 /* Double buffering */
101 unsigned int dboffset
;
105 #define MAX_ANIM_LEN 8
106 #define MAX_ANIMATIONS 4
113 unsigned int animlen
;
114 unsigned int pixmaps
[MAX_ANIM_LEN
];
116 static animation_t animations
[MAX_ANIMATIONS
];
117 static int anims_enabled
;
119 /** Maximum number of saved pixmaps
120 * Pixmap is a saved rectangle
122 #define MAX_PIXMAPS 256
128 static pixmap_t pixmaps
[MAX_PIXMAPS
];
130 /* Viewport is a rectangular area on the screen */
131 #define MAX_VIEWPORTS 128
132 static viewport_t viewports
[128];
134 /* Allow only 1 connection */
135 static int client_connected
= 0;
137 #define RED(x, bits) ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
138 #define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
139 #define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
142 #define ROW_BYTES (screen.scanline * FONT_SCANLINES)
144 #define POINTPOS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
146 static inline int COLOR(int color
)
148 return screen
.invert_colors
? ~color
: color
;
151 /* Conversion routines between different color representations */
153 rgb_byte0888(void *dst
, int rgb
)
159 byte0888_rgb(void *src
)
161 return (*(int *)src
) & 0xffffff;
165 bgr_byte0888(void *dst
, int rgb
)
167 *((uint32_t *) dst
) = BLUE(rgb
, 8) << 16 | GREEN(rgb
, 8) << 8 |
172 byte0888_bgr(void *src
)
174 int color
= *(uint32_t *)(src
);
175 return ((color
& 0xff) << 16) | (((color
>> 8) & 0xff) << 8) |
176 ((color
>> 16) & 0xff);
180 rgb_byte888(void *dst
, int rgb
)
183 #if defined(FB_INVERT_ENDIAN)
184 scr
[0] = RED(rgb
, 8);
185 scr
[1] = GREEN(rgb
, 8);
186 scr
[2] = BLUE(rgb
, 8);
188 scr
[2] = RED(rgb
, 8);
189 scr
[1] = GREEN(rgb
, 8);
190 scr
[0] = BLUE(rgb
, 8);
195 byte888_rgb(void *src
)
198 #if defined(FB_INVERT_ENDIAN)
199 return scr
[0] << 16 | scr
[1] << 8 | scr
[2];
201 return scr
[2] << 16 | scr
[1] << 8 | scr
[0];
205 /** 16-bit depth (5:5:5) */
207 rgb_byte555(void *dst
, int rgb
)
209 /* 5-bit, 5-bits, 5-bits */
210 *((uint16_t *)(dst
)) = RED(rgb
, 5) << 10 | GREEN(rgb
, 5) << 5 |
214 /** 16-bit depth (5:5:5) */
216 byte555_rgb(void *src
)
218 int color
= *(uint16_t *)(src
);
219 return (((color
>> 10) & 0x1f) << (16 + 3)) |
220 (((color
>> 5) & 0x1f) << (8 + 3)) | ((color
& 0x1f) << 3);
223 /** 16-bit depth (5:6:5) */
225 rgb_byte565(void *dst
, int rgb
)
227 /* 5-bit, 6-bits, 5-bits */
228 *((uint16_t *)(dst
)) = RED(rgb
, 5) << 11 | GREEN(rgb
, 6) << 5 |
232 /** 16-bit depth (5:6:5) */
234 byte565_rgb(void *src
)
236 int color
= *(uint16_t *)(src
);
237 return (((color
>> 11) & 0x1f) << (16 + 3)) |
238 (((color
>> 5) & 0x3f) << (8 + 2)) | ((color
& 0x1f) << 3);
241 /** Put pixel - 8-bit depth (3:2:3) */
243 rgb_byte8(void *dst
, int rgb
)
245 *(uint8_t *)dst
= RED(rgb
, 3) << 5 | GREEN(rgb
, 2) << 3 | BLUE(rgb
, 3);
248 /** Return pixel color - 8-bit depth (3:2:3) */
252 int color
= *(uint8_t *)src
;
253 return (((color
>> 5) & 0x7) << (16 + 5)) |
254 (((color
>> 3) & 0x3) << (8 + 6)) | ((color
& 0x7) << 5);
257 /** Put pixel into viewport
259 * @param vport Viewport identification
260 * @param x X coord relative to viewport
261 * @param y Y coord relative to viewport
262 * @param color RGB color
265 putpixel(viewport_t
*vport
, unsigned int x
, unsigned int y
, int color
)
267 int dx
= vport
->x
+ x
;
268 int dy
= vport
->y
+ y
;
270 if (! (vport
->paused
&& vport
->dbdata
))
271 (*screen
.rgb2scr
)(&screen
.fbaddress
[POINTPOS(dx
,dy
)],
275 int dline
= (y
+ vport
->dboffset
) % vport
->height
;
276 int doffset
= screen
.pixelbytes
* (dline
* vport
->width
+ x
);
277 (*screen
.rgb2scr
)(&vport
->dbdata
[doffset
], COLOR(color
));
281 /** Get pixel from viewport */
283 getpixel(viewport_t
*vport
, unsigned int x
, unsigned int y
)
285 int dx
= vport
->x
+ x
;
286 int dy
= vport
->y
+ y
;
288 return COLOR((*screen
.scr2rgb
)(&screen
.fbaddress
[POINTPOS(dx
, dy
)]));
292 putpixel_mem(char *mem
, unsigned int x
, unsigned int y
, int color
)
294 (*screen
.rgb2scr
)(&mem
[POINTPOS(x
,y
)], COLOR(color
));
298 draw_rectangle(viewport_t
*vport
, unsigned int sx
, unsigned int sy
,
299 unsigned int width
, unsigned int height
, int color
)
302 static void *tmpline
;
305 tmpline
= malloc(screen
.scanline
*screen
.pixelbytes
);
307 /* Clear first line */
308 for (x
= 0; x
< width
; x
++)
309 putpixel_mem(tmpline
, x
, 0, color
);
311 if (!vport
->paused
) {
312 /* Recompute to screen coords */
316 for (y
= sy
;y
< sy
+height
; y
++)
317 memcpy(&screen
.fbaddress
[POINTPOS(sx
,y
)], tmpline
,
318 screen
.pixelbytes
* width
);
321 for (y
= sy
; y
< sy
+ height
; y
++) {
322 int rline
= (y
+ vport
->dboffset
) % vport
->height
;
323 int rpos
= (rline
* vport
->width
+ sx
) *
325 memcpy(&vport
->dbdata
[rpos
], tmpline
,
326 screen
.pixelbytes
* width
);
332 /** Fill viewport with background color */
334 clear_port(viewport_t
*vport
)
336 draw_rectangle(vport
, 0, 0, vport
->width
, vport
->height
,
337 vport
->style
.bg_color
);
340 /** Scroll unbuffered viewport up/down
342 * @param vport Viewport to scroll
343 * @param lines Positive number - scroll up, negative - scroll down
346 scroll_port_nodb(viewport_t
*vport
, int lines
)
351 for (y
= vport
->y
; y
< vport
->y
+vport
->height
- lines
; y
++)
352 memcpy(&screen
.fbaddress
[POINTPOS(vport
->x
,y
)],
353 &screen
.fbaddress
[POINTPOS(vport
->x
,y
+ lines
)],
354 screen
.pixelbytes
* vport
->width
);
355 draw_rectangle(vport
, 0, vport
->height
- lines
, vport
->width
,
356 lines
, vport
->style
.bg_color
);
357 } else if (lines
< 0) {
359 for (y
= vport
->y
+ vport
->height
-1; y
>= vport
->y
+ lines
;
361 memcpy(&screen
.fbaddress
[POINTPOS(vport
->x
,y
)],
362 &screen
.fbaddress
[POINTPOS(vport
->x
,y
- lines
)],
363 screen
.pixelbytes
* vport
->width
);
364 draw_rectangle(vport
, 0, 0, vport
->width
, lines
,
365 vport
->style
.bg_color
);
369 /** Refresh given viewport from double buffer */
371 refresh_viewport_db(viewport_t
*vport
)
373 unsigned int y
, srcy
, srcoff
, dsty
, dstx
;
375 for (y
= 0; y
< vport
->height
; y
++) {
376 srcy
= (y
+ vport
->dboffset
) % vport
->height
;
377 srcoff
= (vport
->width
* srcy
) * screen
.pixelbytes
;
382 memcpy(&screen
.fbaddress
[POINTPOS(dstx
,dsty
)],
383 &vport
->dbdata
[srcoff
],
384 vport
->width
*screen
.pixelbytes
);
388 /** Scroll viewport that has double buffering enabled */
390 scroll_port_db(viewport_t
*vport
, int lines
)
394 draw_rectangle(vport
, 0, 0, vport
->width
, lines
,
395 vport
->style
.bg_color
);
396 vport
->dboffset
+= lines
;
397 vport
->dboffset
%= vport
->height
;
398 } else if (lines
< 0) {
400 draw_rectangle(vport
, 0, vport
->height
-lines
,
402 vport
->style
.bg_color
);
404 if (vport
->dboffset
< lines
)
405 vport
->dboffset
+= vport
->height
;
406 vport
->dboffset
-= lines
;
411 refresh_viewport_db(vport
);
414 /** Scrolls viewport given number of lines */
416 scroll_port(viewport_t
*vport
, int lines
)
419 scroll_port_db(vport
, lines
);
421 scroll_port_nodb(vport
, lines
);
426 invert_pixel(viewport_t
*vport
, unsigned int x
, unsigned int y
)
428 putpixel(vport
, x
, y
, ~getpixel(vport
, x
, y
));
432 /***************************************************************/
433 /* Character-console functions */
435 /** Draw character at given position
437 * @param vport Viewport where the character is printed
438 * @param sx Coordinates of top-left of the character
439 * @param sy Coordinates of top-left of the character
440 * @param style Color of the character
441 * @param transparent If false, print background color
444 draw_glyph(viewport_t
*vport
,uint8_t glyph
, unsigned int sx
,
445 unsigned int sy
, style_t style
, int transparent
)
451 for (y
= 0; y
< FONT_SCANLINES
; y
++) {
452 glline
= fb_font
[glyph
* FONT_SCANLINES
+ y
];
453 for (i
= 0; i
< 8; i
++) {
454 if (glline
& (1 << (7 - i
)))
455 putpixel(vport
, sx
+ i
, sy
+ y
,
457 else if (!transparent
)
458 putpixel(vport
, sx
+ i
, sy
+ y
,
464 /** Invert character at given position */
466 invert_char(viewport_t
*vport
,unsigned int row
, unsigned int col
)
471 for (x
= 0; x
< COL_WIDTH
; x
++)
472 for (y
= 0; y
< FONT_SCANLINES
; y
++)
473 invert_pixel(vport
, col
* COL_WIDTH
+ x
, row
*
477 /***************************************************************/
478 /* Stdout specific functions */
481 /** Create new viewport
483 * @return New viewport number
486 viewport_create(unsigned int x
, unsigned int y
,unsigned int width
,
491 for (i
= 0; i
< MAX_VIEWPORTS
; i
++) {
492 if (!viewports
[i
].initialized
)
495 if (i
== MAX_VIEWPORTS
)
500 viewports
[i
].width
= width
;
501 viewports
[i
].height
= height
;
503 viewports
[i
].rows
= height
/ FONT_SCANLINES
;
504 viewports
[i
].cols
= width
/ COL_WIDTH
;
506 viewports
[i
].style
.bg_color
= DEFAULT_BGCOLOR
;
507 viewports
[i
].style
.fg_color
= DEFAULT_FGCOLOR
;
509 viewports
[i
].cur_col
= 0;
510 viewports
[i
].cur_row
= 0;
511 viewports
[i
].cursor_active
= 0;
513 viewports
[i
].initialized
= 1;
518 /** Initialize framebuffer as a chardev output device
520 * @param addr Address of theframebuffer
521 * @param xres Screen width in pixels
522 * @param yres Screen height in pixels
523 * @param visual Bits per pixel (8, 16, 24, 32)
524 * @param scan Bytes per one scanline
525 * @param invert_colors Inverted colors.
529 screen_init(void *addr
, unsigned int xres
, unsigned int yres
,
530 unsigned int scan
, unsigned int visual
, bool invert_colors
)
533 case VISUAL_INDIRECT_8
:
534 screen
.rgb2scr
= rgb_byte8
;
535 screen
.scr2rgb
= byte8_rgb
;
536 screen
.pixelbytes
= 1;
538 case VISUAL_RGB_5_5_5
:
539 screen
.rgb2scr
= rgb_byte555
;
540 screen
.scr2rgb
= byte555_rgb
;
541 screen
.pixelbytes
= 2;
543 case VISUAL_RGB_5_6_5
:
544 screen
.rgb2scr
= rgb_byte565
;
545 screen
.scr2rgb
= byte565_rgb
;
546 screen
.pixelbytes
= 2;
548 case VISUAL_RGB_8_8_8
:
549 screen
.rgb2scr
= rgb_byte888
;
550 screen
.scr2rgb
= byte888_rgb
;
551 screen
.pixelbytes
= 3;
553 case VISUAL_RGB_8_8_8_0
:
554 screen
.rgb2scr
= rgb_byte888
;
555 screen
.scr2rgb
= byte888_rgb
;
556 screen
.pixelbytes
= 4;
558 case VISUAL_RGB_0_8_8_8
:
559 screen
.rgb2scr
= rgb_byte0888
;
560 screen
.scr2rgb
= byte0888_rgb
;
561 screen
.pixelbytes
= 4;
563 case VISUAL_BGR_0_8_8_8
:
564 screen
.rgb2scr
= bgr_byte0888
;
565 screen
.scr2rgb
= byte0888_bgr
;
566 screen
.pixelbytes
= 4;
572 screen
.fbaddress
= (unsigned char *) addr
;
575 screen
.scanline
= scan
;
576 screen
.invert_colors
= invert_colors
;
578 /* Create first viewport */
579 viewport_create(0, 0, xres
, yres
);
584 /** Hide cursor if it is shown */
586 cursor_hide(viewport_t
*vport
)
588 if (vport
->cursor_active
&& vport
->cursor_shown
) {
589 invert_char(vport
, vport
->cur_row
, vport
->cur_col
);
590 vport
->cursor_shown
= 0;
594 /** Show cursor if cursor showing is enabled */
596 cursor_print(viewport_t
*vport
)
598 /* Do not check for cursor_shown */
599 if (vport
->cursor_active
) {
600 invert_char(vport
, vport
->cur_row
, vport
->cur_col
);
601 vport
->cursor_shown
= 1;
605 /** Invert cursor, if it is enabled */
607 cursor_blink(viewport_t
*vport
)
609 if (vport
->cursor_shown
)
615 /** Draw character at given position relative to viewport
617 * @param vport Viewport identification
618 * @param c Character to print
619 * @param row Screen position relative to viewport
620 * @param col Screen position relative to viewport
621 * @param transparent If false, print background color with character
624 draw_char(viewport_t
*vport
, char c
, unsigned int row
, unsigned int col
,
625 style_t style
, int transparent
)
627 /* Optimize - do not hide cursor if we are going to overwrite it */
628 if (vport
->cursor_active
&& vport
->cursor_shown
&&
629 (vport
->cur_col
!= col
|| vport
->cur_row
!= row
))
630 invert_char(vport
, vport
->cur_row
, vport
->cur_col
);
632 draw_glyph(vport
, c
, col
* COL_WIDTH
, row
* FONT_SCANLINES
, style
,
635 vport
->cur_col
= col
;
636 vport
->cur_row
= row
;
639 if (vport
->cur_col
>= vport
->cols
) {
642 if (vport
->cur_row
>= vport
->rows
)
648 /** Draw text data to viewport
650 * @param vport Viewport id
651 * @param data Text data fitting exactly into viewport
654 draw_text_data(viewport_t
*vport
, keyfield_t
*data
)
660 for (i
= 0; i
< vport
->cols
* vport
->rows
; i
++) {
661 if (data
[i
].character
== ' ' && style_same(data
[i
].style
,
664 col
= i
% vport
->cols
;
665 row
= i
/ vport
->cols
;
666 draw_glyph(vport
, data
[i
].character
, col
* COL_WIDTH
, row
*
667 FONT_SCANLINES
, data
[i
].style
,
668 style_same(data
[i
].style
,vport
->style
));
673 /** Return first free pixmap */
675 find_free_pixmap(void)
679 for (i
= 0;i
< MAX_PIXMAPS
;i
++)
680 if (!pixmaps
[i
].data
)
686 putpixel_pixmap(int pm
, unsigned int x
, unsigned int y
, int color
)
688 pixmap_t
*pmap
= &pixmaps
[pm
];
689 int pos
= (y
* pmap
->width
+ x
) * screen
.pixelbytes
;
691 (*screen
.rgb2scr
)(&pmap
->data
[pos
],COLOR(color
));
694 /** Create a new pixmap and return appropriate ID */
696 shm2pixmap(unsigned char *shm
, size_t size
)
701 pm
= find_free_pixmap();
706 if (ppm_get_data(shm
, size
, &pmap
->width
, &pmap
->height
))
709 pmap
->data
= malloc(pmap
->width
* pmap
->height
* screen
.pixelbytes
);
713 ppm_draw(shm
, size
, 0, 0, pmap
->width
, pmap
->height
,
714 (putpixel_cb_t
)putpixel_pixmap
, (void *)pm
);
719 /** Handle shared memory communication calls
721 * Protocol for drawing pixmaps:
722 * - FB_PREPARE_SHM(client shm identification)
723 * - IPC_M_AS_AREA_SEND
724 * - FB_DRAW_PPM(startx,starty)
727 * Protocol for text drawing
728 * - IPC_M_AS_AREA_SEND
729 * - FB_DRAW_TEXT_DATA
731 * @param callid Callid of the current call
732 * @param call Current call data
733 * @param vp Active viewport
734 * @return 0 if the call was not handled byt this function, 1 otherwise
736 * note: this function is not threads safe, you would have
737 * to redefine static variables with __thread
740 shm_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
742 static keyfield_t
*interbuffer
= NULL
;
743 static size_t intersize
= 0;
745 static unsigned char *shm
= NULL
;
746 static ipcarg_t shm_id
= 0;
747 static size_t shm_size
;
751 viewport_t
*vport
= &viewports
[vp
];
754 switch (IPC_GET_METHOD(*call
)) {
755 case IPC_M_AS_AREA_SEND
:
756 /* We accept one area for data interchange */
757 if (IPC_GET_ARG1(*call
) == shm_id
) {
758 void *dest
= as_get_mappable_page(IPC_GET_ARG2(*call
),
759 PAGE_COLOR(IPC_GET_ARG1(*call
)));
760 shm_size
= IPC_GET_ARG2(*call
);
761 if (!ipc_answer_fast(callid
, 0, (sysarg_t
) dest
, 0))
770 intersize
= IPC_GET_ARG2(*call
);
771 receive_comm_area(callid
, call
, (void *) &interbuffer
);
778 shm_id
= IPC_GET_ARG1(*call
);
783 as_area_destroy(shm
);
794 retval
= shm2pixmap(shm
, shm_size
);
801 x
= IPC_GET_ARG1(*call
);
802 y
= IPC_GET_ARG2(*call
);
803 if (x
> vport
->width
|| y
> vport
->height
) {
808 ppm_draw(shm
, shm_size
, IPC_GET_ARG1(*call
),
809 IPC_GET_ARG2(*call
), vport
->width
- x
,
810 vport
->height
- y
, (putpixel_cb_t
)putpixel
, vport
);
812 case FB_DRAW_TEXT_DATA
:
817 if (intersize
< vport
->cols
* vport
->rows
*
818 sizeof(*interbuffer
)) {
822 draw_text_data(vport
, interbuffer
);
829 ipc_answer_fast(callid
, retval
, 0, 0);
834 copy_vp_to_pixmap(viewport_t
*vport
, pixmap_t
*pmap
)
839 int width
= vport
->width
;
840 int height
= vport
->height
;
842 if (width
+ vport
->x
> screen
.xres
)
843 width
= screen
.xres
- vport
->x
;
844 if (height
+ vport
->y
> screen
.yres
)
845 height
= screen
.yres
- vport
->y
;
847 rowsize
= width
* screen
.pixelbytes
;
849 for (y
= 0; y
< height
; y
++) {
850 tmp
= (vport
->y
+ y
) * screen
.scanline
+
851 vport
->x
* screen
.pixelbytes
;
852 memcpy(pmap
->data
+ rowsize
* y
, screen
.fbaddress
+ tmp
,
857 /** Save viewport to pixmap */
859 save_vp_to_pixmap(viewport_t
*vport
)
864 pm
= find_free_pixmap();
869 pmap
->data
= malloc(screen
.pixelbytes
* vport
->width
* vport
->height
);
873 pmap
->width
= vport
->width
;
874 pmap
->height
= vport
->height
;
876 copy_vp_to_pixmap(vport
, pmap
);
881 /** Draw pixmap on screen
883 * @param vp Viewport to draw on
884 * @param pm Pixmap identifier
886 static int draw_pixmap(int vp
, int pm
)
888 pixmap_t
*pmap
= &pixmaps
[pm
];
889 viewport_t
*vport
= &viewports
[vp
];
892 int realwidth
, realheight
, realrowsize
;
893 int width
= vport
->width
;
894 int height
= vport
->height
;
896 if (width
+ vport
->x
> screen
.xres
)
897 width
= screen
.xres
- vport
->x
;
898 if (height
+ vport
->y
> screen
.yres
)
899 height
= screen
.yres
- vport
->y
;
904 realwidth
= pmap
->width
<= width
? pmap
->width
: width
;
905 realheight
= pmap
->height
<= height
? pmap
->height
: height
;
907 srcrowsize
= vport
->width
* screen
.pixelbytes
;
908 realrowsize
= realwidth
* screen
.pixelbytes
;
910 for (y
= 0; y
< realheight
; y
++) {
911 tmp
= (vport
->y
+ y
) * screen
.scanline
+
912 vport
->x
* screen
.pixelbytes
;
913 memcpy(screen
.fbaddress
+ tmp
, pmap
->data
+ y
* srcrowsize
,
919 /** Tick animation one step forward */
924 static int counts
= 0;
926 /* Limit redrawing */
927 counts
= (counts
+ 1) % 8;
931 for (i
= 0; i
< MAX_ANIMATIONS
; i
++) {
932 if (!animations
[i
].animlen
|| !animations
[i
].initialized
||
933 !animations
[i
].enabled
)
935 draw_pixmap(animations
[i
].vp
,
936 animations
[i
].pixmaps
[animations
[i
].pos
]);
937 animations
[i
].pos
= (animations
[i
].pos
+ 1) %
938 animations
[i
].animlen
;
943 static int pointer_x
, pointer_y
;
944 static int pointer_shown
, pointer_enabled
;
945 static int pointer_vport
= -1;
946 static int pointer_pixmap
= -1;
956 if (pointer_shown
|| !pointer_enabled
)
959 /* Save image under the cursor */
960 if (pointer_vport
== -1) {
961 pointer_vport
= viewport_create(pointer_x
, pointer_y
,
962 pointer_width
, pointer_height
);
963 if (pointer_vport
< 0)
966 viewports
[pointer_vport
].x
= pointer_x
;
967 viewports
[pointer_vport
].y
= pointer_y
;
970 if (pointer_pixmap
== -1)
971 pointer_pixmap
= save_vp_to_pixmap(&viewports
[pointer_vport
]);
973 copy_vp_to_pixmap(&viewports
[pointer_vport
],
974 &pixmaps
[pointer_pixmap
]);
977 for (i
= 0; i
< pointer_height
; i
++)
978 for (j
= 0; j
< pointer_width
; j
++) {
979 bytepos
= i
* ((pointer_width
- 1) / 8 + 1) + j
/ 8;
980 visibility
= pointer_mask_bits
[bytepos
] &
983 color
= pointer_bits
[bytepos
] & (1 << (j
% 8))
985 if (pointer_x
+ j
< screen
.xres
&& pointer_y
+
987 putpixel(&viewports
[0], pointer_x
+ j
,
988 pointer_y
+ i
, color
);
997 /* Restore image under the cursor */
999 draw_pixmap(pointer_vport
, pointer_pixmap
);
1005 mouse_move(unsigned int x
, unsigned int y
)
1014 anim_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
1021 switch (IPC_GET_METHOD(*call
)) {
1022 case FB_ANIM_CREATE
:
1023 nvp
= IPC_GET_ARG1(*call
);
1026 if (nvp
>= MAX_VIEWPORTS
|| nvp
< 0 ||
1027 !viewports
[nvp
].initialized
) {
1031 for (i
= 0; i
< MAX_ANIMATIONS
; i
++) {
1032 if (!animations
[i
].initialized
)
1035 if (i
== MAX_ANIMATIONS
) {
1039 animations
[i
].initialized
= 1;
1040 animations
[i
].animlen
= 0;
1041 animations
[i
].pos
= 0;
1042 animations
[i
].enabled
= 0;
1043 animations
[i
].vp
= nvp
;
1047 i
= IPC_GET_ARG1(*call
);
1048 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
1052 animations
[i
].initialized
= 0;
1054 case FB_ANIM_ADDPIXMAP
:
1055 i
= IPC_GET_ARG1(*call
);
1056 if (i
>= MAX_ANIMATIONS
|| i
< 0 ||
1057 !animations
[i
].initialized
) {
1061 if (animations
[i
].animlen
== MAX_ANIM_LEN
) {
1065 newval
= IPC_GET_ARG2(*call
);
1066 if (newval
< 0 || newval
> MAX_PIXMAPS
||
1067 !pixmaps
[newval
].data
) {
1071 animations
[i
].pixmaps
[animations
[i
].animlen
++] = newval
;
1074 i
= IPC_GET_ARG1(*call
);
1075 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
1079 nvp
= IPC_GET_ARG2(*call
);
1082 if (nvp
>= MAX_VIEWPORTS
|| nvp
< 0 ||
1083 !viewports
[nvp
].initialized
) {
1087 animations
[i
].vp
= nvp
;
1091 i
= IPC_GET_ARG1(*call
);
1092 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
1096 newval
= (IPC_GET_METHOD(*call
) == FB_ANIM_START
);
1097 if (newval
^ animations
[i
].enabled
) {
1098 animations
[i
].enabled
= newval
;
1099 anims_enabled
+= newval
? 1 : -1;
1106 ipc_answer_fast(callid
, retval
, 0, 0);
1110 /** Handler for messages concerning pixmap handling */
1112 pixmap_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
1118 switch (IPC_GET_METHOD(*call
)) {
1119 case FB_VP_DRAW_PIXMAP
:
1120 nvp
= IPC_GET_ARG1(*call
);
1123 if (nvp
< 0 || nvp
>= MAX_VIEWPORTS
||
1124 !viewports
[nvp
].initialized
) {
1128 i
= IPC_GET_ARG2(*call
);
1129 retval
= draw_pixmap(nvp
, i
);
1132 nvp
= IPC_GET_ARG1(*call
);
1135 if (nvp
< 0 || nvp
>= MAX_VIEWPORTS
||
1136 !viewports
[nvp
].initialized
)
1139 retval
= save_vp_to_pixmap(&viewports
[nvp
]);
1141 case FB_DROP_PIXMAP
:
1142 i
= IPC_GET_ARG1(*call
);
1143 if (i
>= MAX_PIXMAPS
) {
1147 if (pixmaps
[i
].data
) {
1148 free(pixmaps
[i
].data
);
1149 pixmaps
[i
].data
= NULL
;
1157 ipc_answer_fast(callid
, retval
, 0, 0);
1162 /** Function for handling connections to FB
1166 fb_client_connection(ipc_callid_t iid
, ipc_call_t
*icall
)
1168 ipc_callid_t callid
;
1172 unsigned int row
,col
;
1176 viewport_t
*vport
= &viewports
[0];
1178 if (client_connected
) {
1179 ipc_answer_fast(iid
, ELIMIT
, 0,0);
1182 client_connected
= 1;
1183 ipc_answer_fast(iid
, 0, 0, 0); /* Accept connection */
1186 if (vport
->cursor_active
|| anims_enabled
)
1187 callid
= async_get_call_timeout(&call
, 250000);
1189 callid
= async_get_call(&call
);
1193 cursor_blink(vport
);
1198 if (shm_handle(callid
, &call
, vp
))
1200 if (pixmap_handle(callid
, &call
, vp
))
1202 if (anim_handle(callid
, &call
, vp
))
1205 switch (IPC_GET_METHOD(call
)) {
1206 case IPC_M_PHONE_HUNGUP
:
1207 client_connected
= 0;
1208 /* cleanup other viewports */
1209 for (i
= 1; i
< MAX_VIEWPORTS
; i
++)
1210 vport
->initialized
= 0;
1211 return; /* Exit thread */
1214 case FB_TRANS_PUTCHAR
:
1215 c
= IPC_GET_ARG1(call
);
1216 row
= IPC_GET_ARG2(call
);
1217 col
= IPC_GET_ARG3(call
);
1218 if (row
>= vport
->rows
|| col
>= vport
->cols
) {
1222 ipc_answer_fast(callid
, 0, 0, 0);
1224 draw_char(vport
, c
, row
, col
, vport
->style
,
1225 IPC_GET_METHOD(call
) == FB_TRANS_PUTCHAR
);
1226 continue; /* msg already answered */
1229 cursor_print(vport
);
1232 case FB_CURSOR_GOTO
:
1233 row
= IPC_GET_ARG1(call
);
1234 col
= IPC_GET_ARG2(call
);
1235 if (row
>= vport
->rows
|| col
>= vport
->cols
) {
1241 vport
->cur_col
= col
;
1242 vport
->cur_row
= row
;
1243 cursor_print(vport
);
1245 case FB_CURSOR_VISIBILITY
:
1247 vport
->cursor_active
= IPC_GET_ARG1(call
);
1248 cursor_print(vport
);
1252 ipc_answer_fast(callid
, 0, vport
->rows
, vport
->cols
);
1255 i
= IPC_GET_ARG1(call
);
1256 if (i
> vport
->rows
|| i
< (- (int)vport
->rows
)) {
1261 scroll_port(vport
, i
*FONT_SCANLINES
);
1262 cursor_print(vport
);
1265 case FB_VIEWPORT_DB
:
1266 /* Enable double buffering */
1267 i
= IPC_GET_ARG1(call
);
1270 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1274 if (! viewports
[i
].initialized
) {
1275 retval
= EADDRNOTAVAIL
;
1278 viewports
[i
].dboffset
= 0;
1279 if (IPC_GET_ARG2(call
) == 1 && !viewports
[i
].dbdata
)
1280 viewports
[i
].dbdata
= malloc(screen
.pixelbytes
1281 * viewports
[i
].width
*
1282 viewports
[i
].height
);
1283 else if (IPC_GET_ARG2(call
) == 0 &&
1284 viewports
[i
].dbdata
) {
1285 free(viewports
[i
].dbdata
);
1286 viewports
[i
].dbdata
= NULL
;
1290 case FB_VIEWPORT_SWITCH
:
1291 i
= IPC_GET_ARG1(call
);
1292 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1296 if (! viewports
[i
].initialized
) {
1297 retval
= EADDRNOTAVAIL
;
1302 vport
= &viewports
[vp
];
1303 cursor_print(vport
);
1306 case FB_VIEWPORT_CREATE
:
1307 retval
= viewport_create(IPC_GET_ARG1(call
) >> 16,
1308 IPC_GET_ARG1(call
) & 0xffff,
1309 IPC_GET_ARG2(call
) >> 16,
1310 IPC_GET_ARG2(call
) & 0xffff);
1312 case FB_VIEWPORT_DELETE
:
1313 i
= IPC_GET_ARG1(call
);
1314 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1318 if (! viewports
[i
].initialized
) {
1319 retval
= EADDRNOTAVAIL
;
1322 viewports
[i
].initialized
= 0;
1323 if (viewports
[i
].dbdata
) {
1324 free(viewports
[i
].dbdata
);
1325 viewports
[i
].dbdata
= NULL
;
1330 vport
->style
.fg_color
= IPC_GET_ARG1(call
);
1331 vport
->style
.bg_color
= IPC_GET_ARG2(call
);
1334 case FB_GET_RESOLUTION
:
1335 ipc_answer_fast(callid
, 0, screen
.xres
,screen
.yres
);
1337 case FB_POINTER_MOVE
:
1338 pointer_enabled
= 1;
1339 mouse_move(IPC_GET_ARG1(call
), IPC_GET_ARG2(call
));
1345 ipc_answer_fast(callid
,retval
, 0, 0);
1349 /** Initialization of framebuffer */
1354 unsigned int fb_width
;
1355 unsigned int fb_height
;
1356 unsigned int fb_scanline
;
1357 unsigned int fb_visual
;
1358 bool fb_invert_colors
;
1362 async_set_client_connection(fb_client_connection
);
1364 fb_ph_addr
= (void *) sysinfo_value("fb.address.physical");
1365 fb_width
= sysinfo_value("fb.width");
1366 fb_height
= sysinfo_value("fb.height");
1367 fb_scanline
= sysinfo_value("fb.scanline");
1368 fb_visual
= sysinfo_value("fb.visual");
1369 fb_invert_colors
= sysinfo_value("fb.invert-colors");
1371 asz
= fb_scanline
* fb_height
;
1372 fb_addr
= as_get_mappable_page(asz
, (int)
1373 sysinfo_value("fb.address.color"));
1375 physmem_map(fb_ph_addr
, fb_addr
, ALIGN_UP(asz
, PAGE_SIZE
) >>
1376 PAGE_WIDTH
, AS_AREA_READ
| AS_AREA_WRITE
);
1378 if (screen_init(fb_addr
, fb_width
, fb_height
, fb_scanline
, fb_visual
,