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>
54 #include "font-8x16.h"
57 #include "../console/screenbuffer.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 *);
77 unsigned int scanline
;
78 unsigned int pixelbytes
;
79 unsigned int invert_colors
;
81 conv2scr_fn_t rgb2scr
;
82 conv2rgb_fn_t scr2rgb
;
88 unsigned int width
, height
;
90 /* Text support in window */
91 unsigned int rows
, cols
;
92 /* Style for text printing */
94 /* Auto-cursor position */
95 int cursor_active
, cur_col
, cur_row
;
97 /* Double buffering */
99 unsigned int dboffset
;
103 #define MAX_ANIM_LEN 8
104 #define MAX_ANIMATIONS 4
111 unsigned int animlen
;
112 unsigned int pixmaps
[MAX_ANIM_LEN
];
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
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))
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
)
155 static int byte4_rgb(void *src
)
157 return (*(int *)src
) & 0xffffff;
160 static void rgb_3byte(void *dst
, int rgb
)
163 #if defined(FB_INVERT_ENDIAN)
164 scr
[0] = RED(rgb
, 8);
165 scr
[1] = GREEN(rgb
, 8);
166 scr
[2] = BLUE(rgb
, 8);
168 scr
[2] = RED(rgb
, 8);
169 scr
[1] = GREEN(rgb
, 8);
170 scr
[0] = BLUE(rgb
, 8);
174 static int byte3_rgb(void *src
)
177 #if defined(FB_INVERT_ENDIAN)
178 return scr
[0] << 16 | scr
[1] << 8 | scr
[2];
180 return scr
[2] << 16 | scr
[1] << 8 | scr
[0];
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
));
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
,
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
,
253 static void *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 */
267 for (y
= sy
;y
< sy
+height
; y
++)
268 memcpy(&screen
.fbaddress
[POINTPOS(sx
,y
)], tmpline
,
269 screen
.pixelbytes
* width
);
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
)
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) {
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
;
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
)
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) {
342 draw_rectangle(vport
, 0, vport
->height
-lines
,
344 vport
->style
.bg_color
);
346 if (vport
->dboffset
< lines
)
347 vport
->dboffset
+= vport
->height
;
348 vport
->dboffset
-= lines
;
353 refresh_viewport_db(vport
);
356 /** Scrolls viewport given number of lines */
357 static void scroll_port(viewport_t
*vport
, int lines
)
360 scroll_port_db(vport
, lines
);
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
)
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
)
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
,
425 for (i
=0; i
< MAX_VIEWPORTS
; i
++) {
426 if (!viewports
[i
].initialized
)
429 if (i
== MAX_VIEWPORTS
)
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;
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.
465 screen_init(void *addr
, unsigned int xres
, unsigned int yres
, unsigned int bpp
, unsigned int scan
,
466 int align
, int invert_colors
)
470 screen
.rgb2scr
= rgb_1byte
;
471 screen
.scr2rgb
= byte1_rgb
;
472 screen
.pixelbytes
= 1;
475 screen
.rgb2scr
= rgb_2byte
;
476 screen
.scr2rgb
= byte2_rgb
;
477 screen
.pixelbytes
= 2;
480 screen
.rgb2scr
= rgb_3byte
;
481 screen
.scr2rgb
= byte3_rgb
;
483 screen
.pixelbytes
= 3;
485 screen
.pixelbytes
= 4;
488 screen
.rgb2scr
= rgb_4byte
;
489 screen
.scr2rgb
= byte4_rgb
;
490 screen
.pixelbytes
= 4;
494 screen
.fbaddress
= (unsigned char *) addr
;
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
)
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
;
554 if (vport
->cur_col
>= vport
->cols
) {
557 if (vport
->cur_row
>= vport
->rows
)
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
)
574 for (i
=0; i
< vport
->cols
* vport
->rows
; i
++) {
575 if (data
[i
].character
== ' ' && style_same(data
[i
].style
,vport
->style
))
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
));
586 /** Return first free pixmap */
587 static int find_free_pixmap(void)
591 for (i
=0;i
< MAX_PIXMAPS
;i
++)
592 if (!pixmaps
[i
].data
)
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
)
611 pm
= find_free_pixmap();
616 if (ppm_get_data(shm
, size
, &pmap
->width
, &pmap
->height
))
619 pmap
->data
= malloc(pmap
->width
* pmap
->height
* screen
.pixelbytes
);
623 ppm_draw(shm
, size
, 0, 0, pmap
->width
, pmap
->height
,
624 (putpixel_cb_t
)putpixel_pixmap
, (void *)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)
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
;
660 viewport_t
*vport
= &viewports
[vp
];
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))
678 intersize
= IPC_GET_ARG2(*call
);
679 receive_comm_area(callid
,call
,(void *)&interbuffer
);
686 shm_id
= IPC_GET_ARG1(*call
);
691 as_area_destroy(shm
);
702 retval
= shm2pixmap(shm
, shm_size
);
709 x
= IPC_GET_ARG1(*call
);
710 y
= IPC_GET_ARG2(*call
);
711 if (x
> vport
->width
|| y
> vport
->height
) {
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
);
719 case FB_DRAW_TEXT_DATA
:
724 if (intersize
< vport
->cols
*vport
->rows
*sizeof(*interbuffer
)) {
728 draw_text_data(vport
, interbuffer
);
735 ipc_answer_fast(callid
, retval
, 0, 0);
739 static void copy_vp_to_pixmap(viewport_t
*vport
, pixmap_t
*pmap
)
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
)
766 pm
= find_free_pixmap();
771 pmap
->data
= malloc(screen
.pixelbytes
* vport
->width
* vport
->height
);
775 pmap
->width
= vport
->width
;
776 pmap
->height
= vport
->height
;
778 copy_vp_to_pixmap(vport
, pmap
);
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
];
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
;
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
);
819 /** Tick animation one step forward */
820 static void anims_tick(void)
823 static int counts
= 0;
825 /* Limit redrawing */
826 counts
= (counts
+1) % 8;
830 for (i
=0; i
< MAX_ANIMATIONS
; i
++) {
831 if (!animations
[i
].animlen
|| !animations
[i
].initialized
|| !animations
[i
].enabled
)
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)
851 if (pointer_shown
|| !pointer_enabled
)
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)
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
]);
867 copy_vp_to_pixmap(&viewports
[pointer_vport
], &pixmaps
[pointer_pixmap
]);
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));
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
);
883 static void mouse_hide(void)
885 /* Restore image under the cursor */
887 draw_pixmap(pointer_vport
, pointer_pixmap
);
892 static void mouse_move(unsigned int x
, unsigned int y
)
900 static int anim_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
907 switch (IPC_GET_METHOD(*call
)) {
909 nvp
= IPC_GET_ARG1(*call
);
912 if (nvp
>= MAX_VIEWPORTS
|| nvp
< 0 || !viewports
[nvp
].initialized
) {
916 for (i
=0; i
< MAX_ANIMATIONS
; i
++) {
917 if (! animations
[i
].initialized
)
920 if (i
== MAX_ANIMATIONS
) {
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
;
932 i
= IPC_GET_ARG1(*call
);
933 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
937 animations
[i
].initialized
= 0;
939 case FB_ANIM_ADDPIXMAP
:
940 i
= IPC_GET_ARG1(*call
);
941 if (i
>= MAX_ANIMATIONS
|| i
< 0 || !animations
[i
].initialized
) {
945 if (animations
[i
].animlen
== MAX_ANIM_LEN
) {
949 newval
= IPC_GET_ARG2(*call
);
950 if (newval
< 0 || newval
> MAX_PIXMAPS
|| !pixmaps
[newval
].data
) {
954 animations
[i
].pixmaps
[animations
[i
].animlen
++] = newval
;
957 i
= IPC_GET_ARG1(*call
);
958 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
962 nvp
= IPC_GET_ARG2(*call
);
965 if (nvp
>= MAX_VIEWPORTS
|| nvp
< 0 || !viewports
[nvp
].initialized
) {
969 animations
[i
].vp
= nvp
;
973 i
= IPC_GET_ARG1(*call
);
974 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
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;
988 ipc_answer_fast(callid
, retval
, 0, 0);
992 /** Handler for messages concerning pixmap handling */
993 static int pixmap_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
999 switch (IPC_GET_METHOD(*call
)) {
1000 case FB_VP_DRAW_PIXMAP
:
1001 nvp
= IPC_GET_ARG1(*call
);
1004 if (nvp
< 0 || nvp
>= MAX_VIEWPORTS
|| !viewports
[nvp
].initialized
) {
1008 i
= IPC_GET_ARG2(*call
);
1009 retval
= draw_pixmap(nvp
, i
);
1012 nvp
= IPC_GET_ARG1(*call
);
1015 if (nvp
< 0 || nvp
>= MAX_VIEWPORTS
|| !viewports
[nvp
].initialized
)
1018 retval
= save_vp_to_pixmap(&viewports
[nvp
]);
1020 case FB_DROP_PIXMAP
:
1021 i
= IPC_GET_ARG1(*call
);
1022 if (i
>= MAX_PIXMAPS
) {
1026 if (pixmaps
[i
].data
) {
1027 free(pixmaps
[i
].data
);
1028 pixmaps
[i
].data
= NULL
;
1036 ipc_answer_fast(callid
, retval
, 0, 0);
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
;
1050 unsigned int row
,col
;
1054 viewport_t
*vport
= &viewports
[0];
1056 if (client_connected
) {
1057 ipc_answer_fast(iid
, ELIMIT
, 0,0);
1060 client_connected
= 1;
1061 ipc_answer_fast(iid
, 0, 0, 0); /* Accept connection */
1064 if (vport
->cursor_active
|| anims_enabled
)
1065 callid
= async_get_call_timeout(&call
,250000);
1067 callid
= async_get_call(&call
);
1071 cursor_blink(vport
);
1076 if (shm_handle(callid
, &call
, vp
))
1078 if (pixmap_handle(callid
, &call
, vp
))
1080 if (anim_handle(callid
, &call
, vp
))
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 */
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
) {
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 */
1106 cursor_print(vport
);
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
) {
1118 vport
->cur_col
= col
;
1119 vport
->cur_row
= row
;
1120 cursor_print(vport
);
1122 case FB_CURSOR_VISIBILITY
:
1124 vport
->cursor_active
= IPC_GET_ARG1(call
);
1125 cursor_print(vport
);
1129 ipc_answer_fast(callid
, 0, vport
->rows
, vport
->cols
);
1132 i
= IPC_GET_ARG1(call
);
1133 if (i
> vport
->rows
|| i
< (- (int)vport
->rows
)) {
1138 scroll_port(vport
, i
*FONT_SCANLINES
);
1139 cursor_print(vport
);
1142 case FB_VIEWPORT_DB
:
1143 /* Enable double buffering */
1144 i
= IPC_GET_ARG1(call
);
1147 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1151 if (! viewports
[i
].initialized
) {
1152 retval
= EADDRNOTAVAIL
;
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
;
1164 case FB_VIEWPORT_SWITCH
:
1165 i
= IPC_GET_ARG1(call
);
1166 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1170 if (! viewports
[i
].initialized
) {
1171 retval
= EADDRNOTAVAIL
;
1176 vport
= &viewports
[vp
];
1177 cursor_print(vport
);
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);
1186 case FB_VIEWPORT_DELETE
:
1187 i
= IPC_GET_ARG1(call
);
1188 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1192 if (! viewports
[i
].initialized
) {
1193 retval
= EADDRNOTAVAIL
;
1196 viewports
[i
].initialized
= 0;
1197 if (viewports
[i
].dbdata
) {
1198 free(viewports
[i
].dbdata
);
1199 viewports
[i
].dbdata
= NULL
;
1204 vport
->style
.fg_color
= IPC_GET_ARG1(call
);
1205 vport
->style
.bg_color
= IPC_GET_ARG2(call
);
1208 case FB_GET_RESOLUTION
:
1209 ipc_answer_fast(callid
, 0, screen
.xres
,screen
.yres
);
1211 case FB_POINTER_MOVE
:
1212 pointer_enabled
= 1;
1213 mouse_move(IPC_GET_ARG1(call
), IPC_GET_ARG2(call
));
1219 ipc_answer_fast(callid
,retval
,0,0);
1223 /** Initialization of framebuffer */
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
;
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
);