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 */
152 static void rgb_byte0888(void *dst
, int rgb
)
157 static int byte0888_rgb(void *src
)
159 return (*(int *)src
) & 0xffffff;
162 static void bgr_byte0888(void *dst
, int rgb
)
164 *((uint32_t *) dst
) = BLUE(rgb
, 8) << 16 | GREEN(rgb
, 8) << 8 |
168 static int byte0888_bgr(void *src
)
170 int color
= *(uint32_t *)(src
);
171 return ((color
& 0xff) << 16) | (((color
>> 8) & 0xff) << 8) | ((color
175 static void rgb_byte888(void *dst
, int rgb
)
178 #if defined(FB_INVERT_ENDIAN)
179 scr
[0] = RED(rgb
, 8);
180 scr
[1] = GREEN(rgb
, 8);
181 scr
[2] = BLUE(rgb
, 8);
183 scr
[2] = RED(rgb
, 8);
184 scr
[1] = GREEN(rgb
, 8);
185 scr
[0] = BLUE(rgb
, 8);
189 static int byte888_rgb(void *src
)
192 #if defined(FB_INVERT_ENDIAN)
193 return scr
[0] << 16 | scr
[1] << 8 | scr
[2];
195 return scr
[2] << 16 | scr
[1] << 8 | scr
[0];
199 /** 16-bit depth (5:5:5) */
200 static void rgb_byte555(void *dst
, int rgb
)
202 /* 5-bit, 5-bits, 5-bits */
203 *((uint16_t *)(dst
)) = RED(rgb
, 5) << 10 | GREEN(rgb
, 5) << 5 |
207 /** 16-bit depth (5:5:5) */
208 static int byte555_rgb(void *src
)
210 int color
= *(uint16_t *)(src
);
211 return (((color
>> 10) & 0x1f) << (16 + 3)) | (((color
>> 5) & 0x1f) <<
212 (8 + 3)) | ((color
& 0x1f) << 3);
215 /** 16-bit depth (5:6:5) */
216 static void rgb_byte565(void *dst
, int rgb
)
218 /* 5-bit, 6-bits, 5-bits */
219 *((uint16_t *)(dst
)) = RED(rgb
, 5) << 11 | GREEN(rgb
, 6) << 5 |
223 /** 16-bit depth (5:6:5) */
224 static int byte565_rgb(void *src
)
226 int color
= *(uint16_t *)(src
);
227 return (((color
>> 11) & 0x1f) << (16 + 3)) | (((color
>> 5) & 0x3f) <<
228 (8 + 2)) | ((color
& 0x1f) << 3);
231 /** Put pixel - 8-bit depth (3:2:3) */
232 static void rgb_byte8(void *dst
, int rgb
)
234 *(uint8_t *)dst
= RED(rgb
, 3) << 5 | GREEN(rgb
, 2) << 3 | BLUE(rgb
, 3);
237 /** Return pixel color - 8-bit depth (3:2:3) */
238 static int byte8_rgb(void *src
)
240 int color
= *(uint8_t *)src
;
241 return (((color
>> 5) & 0x7) << (16 + 5)) | (((color
>> 3) & 0x3) <<
242 (8 + 6)) | ((color
& 0x7) << 5);
245 /** Put pixel into viewport
247 * @param vport Viewport identification
248 * @param x X coord relative to viewport
249 * @param y Y coord relative to viewport
250 * @param color RGB color
252 static void putpixel(viewport_t
*vport
, unsigned int x
, unsigned int y
, int
255 int dx
= vport
->x
+ x
;
256 int dy
= vport
->y
+ y
;
258 if (! (vport
->paused
&& vport
->dbdata
))
259 (*screen
.rgb2scr
)(&screen
.fbaddress
[POINTPOS(dx
,dy
)], COLOR(color
));
262 int dline
= (y
+ vport
->dboffset
) % vport
->height
;
263 int doffset
= screen
.pixelbytes
* (dline
* vport
->width
+ x
);
264 (*screen
.rgb2scr
)(&vport
->dbdata
[doffset
], COLOR(color
));
268 /** Get pixel from viewport */
269 static int getpixel(viewport_t
*vport
, unsigned int x
, unsigned int y
)
271 int dx
= vport
->x
+ x
;
272 int dy
= vport
->y
+ y
;
274 return COLOR((*screen
.scr2rgb
)(&screen
.fbaddress
[POINTPOS(dx
,dy
)]));
277 static inline void putpixel_mem(char *mem
, unsigned int x
, unsigned int y
, int
280 (*screen
.rgb2scr
)(&mem
[POINTPOS(x
,y
)], COLOR(color
));
283 static void draw_rectangle(viewport_t
*vport
, unsigned int sx
, unsigned int sy
,
284 unsigned int width
, unsigned int height
, int color
)
287 static void *tmpline
;
290 tmpline
= malloc(screen
.scanline
*screen
.pixelbytes
);
292 /* Clear first line */
293 for (x
= 0; x
< width
; x
++)
294 putpixel_mem(tmpline
, x
, 0, color
);
296 if (!vport
->paused
) {
297 /* Recompute to screen coords */
301 for (y
= sy
;y
< sy
+height
; y
++)
302 memcpy(&screen
.fbaddress
[POINTPOS(sx
,y
)], tmpline
,
303 screen
.pixelbytes
* width
);
306 for (y
= sy
; y
< sy
+ height
; y
++) {
307 int rline
= (y
+ vport
->dboffset
) % vport
->height
;
308 int rpos
= (rline
* vport
->width
+ sx
) *
310 memcpy(&vport
->dbdata
[rpos
], tmpline
,
311 screen
.pixelbytes
* width
);
317 /** Fill viewport with background color */
318 static void clear_port(viewport_t
*vport
)
320 draw_rectangle(vport
, 0, 0, vport
->width
, vport
->height
,
321 vport
->style
.bg_color
);
324 /** Scroll unbuffered viewport up/down
326 * @param vport Viewport to scroll
327 * @param lines Positive number - scroll up, negative - scroll down
329 static void scroll_port_nodb(viewport_t
*vport
, int lines
)
334 for (y
= vport
->y
; y
< vport
->y
+vport
->height
- lines
; y
++)
335 memcpy(&screen
.fbaddress
[POINTPOS(vport
->x
,y
)],
336 &screen
.fbaddress
[POINTPOS(vport
->x
,y
+ lines
)],
337 screen
.pixelbytes
* vport
->width
);
338 draw_rectangle(vport
, 0, vport
->height
- lines
, vport
->width
,
339 lines
, vport
->style
.bg_color
);
340 } else if (lines
< 0) {
342 for (y
= vport
->y
+ vport
->height
-1; y
>= vport
->y
+ lines
;
344 memcpy(&screen
.fbaddress
[POINTPOS(vport
->x
,y
)],
345 &screen
.fbaddress
[POINTPOS(vport
->x
,y
- lines
)],
346 screen
.pixelbytes
* vport
->width
);
347 draw_rectangle(vport
, 0, 0, vport
->width
, lines
,
348 vport
->style
.bg_color
);
352 /** Refresh given viewport from double buffer */
353 static void refresh_viewport_db(viewport_t
*vport
)
355 unsigned int y
, srcy
, srcoff
, dsty
, dstx
;
357 for (y
= 0; y
< vport
->height
; y
++) {
358 srcy
= (y
+ vport
->dboffset
) % vport
->height
;
359 srcoff
= (vport
->width
* srcy
) * screen
.pixelbytes
;
364 memcpy(&screen
.fbaddress
[POINTPOS(dstx
,dsty
)],
365 &vport
->dbdata
[srcoff
],
366 vport
->width
*screen
.pixelbytes
);
370 /** Scroll viewport that has double buffering enabled */
371 static void scroll_port_db(viewport_t
*vport
, int lines
)
375 draw_rectangle(vport
, 0, 0, vport
->width
, lines
,
376 vport
->style
.bg_color
);
377 vport
->dboffset
+= lines
;
378 vport
->dboffset
%= vport
->height
;
379 } else if (lines
< 0) {
381 draw_rectangle(vport
, 0, vport
->height
-lines
,
383 vport
->style
.bg_color
);
385 if (vport
->dboffset
< lines
)
386 vport
->dboffset
+= vport
->height
;
387 vport
->dboffset
-= lines
;
392 refresh_viewport_db(vport
);
395 /** Scrolls viewport given number of lines */
396 static void scroll_port(viewport_t
*vport
, int lines
)
399 scroll_port_db(vport
, lines
);
401 scroll_port_nodb(vport
, lines
);
405 static void invert_pixel(viewport_t
*vport
, unsigned int x
, unsigned int y
)
407 putpixel(vport
, x
, y
, ~getpixel(vport
, x
, y
));
411 /***************************************************************/
412 /* Character-console functions */
414 /** Draw character at given position
416 * @param vport Viewport where the character is printed
417 * @param sx Coordinates of top-left of the character
418 * @param sy Coordinates of top-left of the character
419 * @param style Color of the character
420 * @param transparent If false, print background color
422 static void draw_glyph(viewport_t
*vport
,uint8_t glyph
, unsigned int sx
,
423 unsigned int sy
, style_t style
, int transparent
)
429 for (y
= 0; y
< FONT_SCANLINES
; y
++) {
430 glline
= fb_font
[glyph
* FONT_SCANLINES
+ y
];
431 for (i
= 0; i
< 8; i
++) {
432 if (glline
& (1 << (7 - i
)))
433 putpixel(vport
, sx
+ i
, sy
+ y
,
435 else if (!transparent
)
436 putpixel(vport
, sx
+ i
, sy
+ y
,
442 /** Invert character at given position */
443 static void invert_char(viewport_t
*vport
,unsigned int row
, unsigned int col
)
448 for (x
= 0; x
< COL_WIDTH
; x
++)
449 for (y
= 0; y
< FONT_SCANLINES
; y
++)
450 invert_pixel(vport
, col
* COL_WIDTH
+ x
, row
*
454 /***************************************************************/
455 /* Stdout specific functions */
458 /** Create new viewport
460 * @return New viewport number
462 static int viewport_create(unsigned int x
, unsigned int y
,unsigned int width
,
467 for (i
=0; i
< MAX_VIEWPORTS
; i
++) {
468 if (!viewports
[i
].initialized
)
471 if (i
== MAX_VIEWPORTS
)
476 viewports
[i
].width
= width
;
477 viewports
[i
].height
= height
;
479 viewports
[i
].rows
= height
/ FONT_SCANLINES
;
480 viewports
[i
].cols
= width
/ COL_WIDTH
;
482 viewports
[i
].style
.bg_color
= DEFAULT_BGCOLOR
;
483 viewports
[i
].style
.fg_color
= DEFAULT_FGCOLOR
;
485 viewports
[i
].cur_col
= 0;
486 viewports
[i
].cur_row
= 0;
487 viewports
[i
].cursor_active
= 0;
489 viewports
[i
].initialized
= 1;
495 /** Initialize framebuffer as a chardev output device
497 * @param addr Address of theframebuffer
498 * @param xres Screen width in pixels
499 * @param yres Screen height in pixels
500 * @param visual Bits per pixel (8, 16, 24, 32)
501 * @param scan Bytes per one scanline
502 * @param invert_colors Inverted colors.
505 static bool screen_init(void *addr
, unsigned int xres
, unsigned int yres
,
506 unsigned int scan
, unsigned int visual
, bool invert_colors
)
509 case VISUAL_INDIRECT_8
:
510 screen
.rgb2scr
= rgb_byte8
;
511 screen
.scr2rgb
= byte8_rgb
;
512 screen
.pixelbytes
= 1;
514 case VISUAL_RGB_5_5_5
:
515 screen
.rgb2scr
= rgb_byte555
;
516 screen
.scr2rgb
= byte555_rgb
;
517 screen
.pixelbytes
= 2;
519 case VISUAL_RGB_5_6_5
:
520 screen
.rgb2scr
= rgb_byte565
;
521 screen
.scr2rgb
= byte565_rgb
;
522 screen
.pixelbytes
= 2;
524 case VISUAL_RGB_8_8_8
:
525 screen
.rgb2scr
= rgb_byte888
;
526 screen
.scr2rgb
= byte888_rgb
;
527 screen
.pixelbytes
= 3;
529 case VISUAL_RGB_8_8_8_0
:
530 screen
.rgb2scr
= rgb_byte888
;
531 screen
.scr2rgb
= byte888_rgb
;
532 screen
.pixelbytes
= 4;
534 case VISUAL_RGB_0_8_8_8
:
535 screen
.rgb2scr
= rgb_byte0888
;
536 screen
.scr2rgb
= byte0888_rgb
;
537 screen
.pixelbytes
= 4;
539 case VISUAL_BGR_0_8_8_8
:
540 screen
.rgb2scr
= bgr_byte0888
;
541 screen
.scr2rgb
= byte0888_bgr
;
542 screen
.pixelbytes
= 4;
548 screen
.fbaddress
= (unsigned char *) addr
;
551 screen
.scanline
= scan
;
552 screen
.invert_colors
= invert_colors
;
554 /* Create first viewport */
555 viewport_create(0, 0, xres
, yres
);
560 /** Hide cursor if it is shown */
561 static void cursor_hide(viewport_t
*vport
)
563 if (vport
->cursor_active
&& vport
->cursor_shown
) {
564 invert_char(vport
, vport
->cur_row
, vport
->cur_col
);
565 vport
->cursor_shown
= 0;
569 /** Show cursor if cursor showing is enabled */
570 static void cursor_print(viewport_t
*vport
)
572 /* Do not check for cursor_shown */
573 if (vport
->cursor_active
) {
574 invert_char(vport
, vport
->cur_row
, vport
->cur_col
);
575 vport
->cursor_shown
= 1;
579 /** Invert cursor, if it is enabled */
580 static void cursor_blink(viewport_t
*vport
)
582 if (vport
->cursor_shown
)
588 /** Draw character at given position relative to viewport
590 * @param vport Viewport identification
591 * @param c Character to print
592 * @param row Screen position relative to viewport
593 * @param col Screen position relative to viewport
594 * @param transparent If false, print background color with character
596 static void draw_char(viewport_t
*vport
, char c
, unsigned int row
, unsigned int
597 col
, style_t style
, int transparent
)
599 /* Optimize - do not hide cursor if we are going to overwrite it */
600 if (vport
->cursor_active
&& vport
->cursor_shown
&&
601 (vport
->cur_col
!= col
|| vport
->cur_row
!= row
))
602 invert_char(vport
, vport
->cur_row
, vport
->cur_col
);
604 draw_glyph(vport
, c
, col
* COL_WIDTH
, row
* FONT_SCANLINES
, style
,
607 vport
->cur_col
= col
;
608 vport
->cur_row
= row
;
611 if (vport
->cur_col
>= vport
->cols
) {
614 if (vport
->cur_row
>= vport
->rows
)
620 /** Draw text data to viewport
622 * @param vport Viewport id
623 * @param data Text data fitting exactly into viewport
625 static void draw_text_data(viewport_t
*vport
, keyfield_t
*data
)
631 for (i
= 0; i
< vport
->cols
* vport
->rows
; i
++) {
632 if (data
[i
].character
== ' ' && style_same(data
[i
].style
,
635 col
= i
% vport
->cols
;
636 row
= i
/ vport
->cols
;
637 draw_glyph(vport
, data
[i
].character
, col
* COL_WIDTH
, row
*
638 FONT_SCANLINES
, data
[i
].style
,
639 style_same(data
[i
].style
,vport
->style
));
645 /** Return first free pixmap */
646 static int find_free_pixmap(void)
650 for (i
=0;i
< MAX_PIXMAPS
;i
++)
651 if (!pixmaps
[i
].data
)
656 static void putpixel_pixmap(int pm
, unsigned int x
, unsigned int y
, int color
)
658 pixmap_t
*pmap
= &pixmaps
[pm
];
659 int pos
= (y
* pmap
->width
+ x
) * screen
.pixelbytes
;
661 (*screen
.rgb2scr
)(&pmap
->data
[pos
],COLOR(color
));
664 /** Create a new pixmap and return appropriate ID */
665 static int shm2pixmap(unsigned char *shm
, size_t size
)
670 pm
= find_free_pixmap();
675 if (ppm_get_data(shm
, size
, &pmap
->width
, &pmap
->height
))
678 pmap
->data
= malloc(pmap
->width
* pmap
->height
* screen
.pixelbytes
);
682 ppm_draw(shm
, size
, 0, 0, pmap
->width
, pmap
->height
,
683 (putpixel_cb_t
)putpixel_pixmap
, (void *)pm
);
688 /** Handle shared memory communication calls
690 * Protocol for drawing pixmaps:
691 * - FB_PREPARE_SHM(client shm identification)
692 * - IPC_M_AS_AREA_SEND
693 * - FB_DRAW_PPM(startx,starty)
696 * Protocol for text drawing
697 * - IPC_M_AS_AREA_SEND
698 * - FB_DRAW_TEXT_DATA
700 * @param callid Callid of the current call
701 * @param call Current call data
702 * @param vp Active viewport
703 * @return 0 if the call was not handled byt this function, 1 otherwise
705 * note: this function is not threads safe, you would have
706 * to redefine static variables with __thread
708 static int shm_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
710 static keyfield_t
*interbuffer
= NULL
;
711 static size_t intersize
= 0;
713 static unsigned char *shm
= NULL
;
714 static ipcarg_t shm_id
= 0;
715 static size_t shm_size
;
719 viewport_t
*vport
= &viewports
[vp
];
722 switch (IPC_GET_METHOD(*call
)) {
723 case IPC_M_AS_AREA_SEND
:
724 /* We accept one area for data interchange */
725 if (IPC_GET_ARG1(*call
) == shm_id
) {
726 void *dest
= as_get_mappable_page(IPC_GET_ARG2(*call
),
727 PAGE_COLOR(IPC_GET_ARG1(*call
)));
728 shm_size
= IPC_GET_ARG2(*call
);
729 if (!ipc_answer_fast(callid
, 0, (sysarg_t
) dest
, 0))
738 intersize
= IPC_GET_ARG2(*call
);
739 receive_comm_area(callid
, call
, (void *) &interbuffer
);
746 shm_id
= IPC_GET_ARG1(*call
);
751 as_area_destroy(shm
);
762 retval
= shm2pixmap(shm
, shm_size
);
769 x
= IPC_GET_ARG1(*call
);
770 y
= IPC_GET_ARG2(*call
);
771 if (x
> vport
->width
|| y
> vport
->height
) {
776 ppm_draw(shm
, shm_size
, IPC_GET_ARG1(*call
),
777 IPC_GET_ARG2(*call
), vport
->width
- x
, vport
->height
-
778 y
, (putpixel_cb_t
)putpixel
, vport
);
780 case FB_DRAW_TEXT_DATA
:
785 if (intersize
< vport
->cols
* vport
->rows
*
786 sizeof(*interbuffer
)) {
790 draw_text_data(vport
, interbuffer
);
797 ipc_answer_fast(callid
, retval
, 0, 0);
801 static void copy_vp_to_pixmap(viewport_t
*vport
, pixmap_t
*pmap
)
806 int width
= vport
->width
;
807 int height
= vport
->height
;
809 if (width
+ vport
->x
> screen
.xres
)
810 width
= screen
.xres
- vport
->x
;
811 if (height
+ vport
->y
> screen
.yres
)
812 height
= screen
.yres
- vport
->y
;
814 rowsize
= width
* screen
.pixelbytes
;
816 for (y
= 0; y
< height
; y
++) {
817 tmp
= (vport
->y
+ y
) * screen
.scanline
+ vport
->x
*
819 memcpy(pmap
->data
+ rowsize
* y
, screen
.fbaddress
+ tmp
,
824 /** Save viewport to pixmap */
825 static int save_vp_to_pixmap(viewport_t
*vport
)
830 pm
= find_free_pixmap();
835 pmap
->data
= malloc(screen
.pixelbytes
* vport
->width
* vport
->height
);
839 pmap
->width
= vport
->width
;
840 pmap
->height
= vport
->height
;
842 copy_vp_to_pixmap(vport
, pmap
);
847 /** Draw pixmap on screen
849 * @param vp Viewport to draw on
850 * @param pm Pixmap identifier
852 static int draw_pixmap(int vp
, int pm
)
854 pixmap_t
*pmap
= &pixmaps
[pm
];
855 viewport_t
*vport
= &viewports
[vp
];
858 int realwidth
, realheight
, realrowsize
;
859 int width
= vport
->width
;
860 int height
= vport
->height
;
862 if (width
+ vport
->x
> screen
.xres
)
863 width
= screen
.xres
- vport
->x
;
864 if (height
+ vport
->y
> screen
.yres
)
865 height
= screen
.yres
- vport
->y
;
870 realwidth
= pmap
->width
<= width
? pmap
->width
: width
;
871 realheight
= pmap
->height
<= height
? pmap
->height
: height
;
873 srcrowsize
= vport
->width
* screen
.pixelbytes
;
874 realrowsize
= realwidth
* screen
.pixelbytes
;
876 for (y
=0; y
< realheight
; y
++) {
877 tmp
= (vport
->y
+ y
) * screen
.scanline
+ vport
->x
*
879 memcpy(screen
.fbaddress
+ tmp
, pmap
->data
+ y
* srcrowsize
,
885 /** Tick animation one step forward */
886 static void anims_tick(void)
889 static int counts
= 0;
891 /* Limit redrawing */
892 counts
= (counts
+ 1) % 8;
896 for (i
=0; i
< MAX_ANIMATIONS
; i
++) {
897 if (!animations
[i
].animlen
|| !animations
[i
].initialized
||
898 !animations
[i
].enabled
)
900 draw_pixmap(animations
[i
].vp
,
901 animations
[i
].pixmaps
[animations
[i
].pos
]);
902 animations
[i
].pos
= (animations
[i
].pos
+ 1) %
903 animations
[i
].animlen
;
908 static int pointer_x
, pointer_y
;
909 static int pointer_shown
, pointer_enabled
;
910 static int pointer_vport
= -1;
911 static int pointer_pixmap
= -1;
913 static void mouse_show(void)
920 if (pointer_shown
|| !pointer_enabled
)
923 /* Save image under the cursor */
924 if (pointer_vport
== -1) {
925 pointer_vport
= viewport_create(pointer_x
, pointer_y
,
926 pointer_width
, pointer_height
);
927 if (pointer_vport
< 0)
930 viewports
[pointer_vport
].x
= pointer_x
;
931 viewports
[pointer_vport
].y
= pointer_y
;
934 if (pointer_pixmap
== -1)
935 pointer_pixmap
= save_vp_to_pixmap(&viewports
[pointer_vport
]);
937 copy_vp_to_pixmap(&viewports
[pointer_vport
],
938 &pixmaps
[pointer_pixmap
]);
941 for (i
= 0; i
< pointer_height
; i
++)
942 for (j
= 0; j
< pointer_width
; j
++) {
943 bytepos
= i
* ((pointer_width
- 1) / 8 + 1) + j
/ 8;
944 visibility
= pointer_mask_bits
[bytepos
] & (1 << (j
%
947 color
= pointer_bits
[bytepos
] & (1 << (j
% 8))
949 if (pointer_x
+ j
< screen
.xres
&& pointer_y
+
951 putpixel(&viewports
[0], pointer_x
+ j
,
958 static void mouse_hide(void)
960 /* Restore image under the cursor */
962 draw_pixmap(pointer_vport
, pointer_pixmap
);
967 static void mouse_move(unsigned int x
, unsigned int y
)
975 static int anim_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
982 switch (IPC_GET_METHOD(*call
)) {
984 nvp
= IPC_GET_ARG1(*call
);
987 if (nvp
>= MAX_VIEWPORTS
|| nvp
< 0 ||
988 !viewports
[nvp
].initialized
) {
992 for (i
= 0; i
< MAX_ANIMATIONS
; i
++) {
993 if (!animations
[i
].initialized
)
996 if (i
== MAX_ANIMATIONS
) {
1000 animations
[i
].initialized
= 1;
1001 animations
[i
].animlen
= 0;
1002 animations
[i
].pos
= 0;
1003 animations
[i
].enabled
= 0;
1004 animations
[i
].vp
= nvp
;
1008 i
= IPC_GET_ARG1(*call
);
1009 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
1013 animations
[i
].initialized
= 0;
1015 case FB_ANIM_ADDPIXMAP
:
1016 i
= IPC_GET_ARG1(*call
);
1017 if (i
>= MAX_ANIMATIONS
|| i
< 0 ||
1018 !animations
[i
].initialized
) {
1022 if (animations
[i
].animlen
== MAX_ANIM_LEN
) {
1026 newval
= IPC_GET_ARG2(*call
);
1027 if (newval
< 0 || newval
> MAX_PIXMAPS
||
1028 !pixmaps
[newval
].data
) {
1032 animations
[i
].pixmaps
[animations
[i
].animlen
++] = newval
;
1035 i
= IPC_GET_ARG1(*call
);
1036 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
1040 nvp
= IPC_GET_ARG2(*call
);
1043 if (nvp
>= MAX_VIEWPORTS
|| nvp
< 0 ||
1044 !viewports
[nvp
].initialized
) {
1048 animations
[i
].vp
= nvp
;
1052 i
= IPC_GET_ARG1(*call
);
1053 if (i
>= MAX_ANIMATIONS
|| i
< 0) {
1057 newval
= (IPC_GET_METHOD(*call
) == FB_ANIM_START
);
1058 if (newval
^ animations
[i
].enabled
) {
1059 animations
[i
].enabled
= newval
;
1060 anims_enabled
+= newval
? 1 : -1;
1067 ipc_answer_fast(callid
, retval
, 0, 0);
1071 /** Handler for messages concerning pixmap handling */
1072 static int pixmap_handle(ipc_callid_t callid
, ipc_call_t
*call
, int vp
)
1078 switch (IPC_GET_METHOD(*call
)) {
1079 case FB_VP_DRAW_PIXMAP
:
1080 nvp
= IPC_GET_ARG1(*call
);
1083 if (nvp
< 0 || nvp
>= MAX_VIEWPORTS
||
1084 !viewports
[nvp
].initialized
) {
1088 i
= IPC_GET_ARG2(*call
);
1089 retval
= draw_pixmap(nvp
, i
);
1092 nvp
= IPC_GET_ARG1(*call
);
1095 if (nvp
< 0 || nvp
>= MAX_VIEWPORTS
||
1096 !viewports
[nvp
].initialized
)
1099 retval
= save_vp_to_pixmap(&viewports
[nvp
]);
1101 case FB_DROP_PIXMAP
:
1102 i
= IPC_GET_ARG1(*call
);
1103 if (i
>= MAX_PIXMAPS
) {
1107 if (pixmaps
[i
].data
) {
1108 free(pixmaps
[i
].data
);
1109 pixmaps
[i
].data
= NULL
;
1117 ipc_answer_fast(callid
, retval
, 0, 0);
1122 /** Function for handling connections to FB
1125 static void fb_client_connection(ipc_callid_t iid
, ipc_call_t
*icall
)
1127 ipc_callid_t callid
;
1131 unsigned int row
,col
;
1135 viewport_t
*vport
= &viewports
[0];
1137 if (client_connected
) {
1138 ipc_answer_fast(iid
, ELIMIT
, 0,0);
1141 client_connected
= 1;
1142 ipc_answer_fast(iid
, 0, 0, 0); /* Accept connection */
1145 if (vport
->cursor_active
|| anims_enabled
)
1146 callid
= async_get_call_timeout(&call
,250000);
1148 callid
= async_get_call(&call
);
1152 cursor_blink(vport
);
1157 if (shm_handle(callid
, &call
, vp
))
1159 if (pixmap_handle(callid
, &call
, vp
))
1161 if (anim_handle(callid
, &call
, vp
))
1164 switch (IPC_GET_METHOD(call
)) {
1165 case IPC_M_PHONE_HUNGUP
:
1166 client_connected
= 0;
1167 /* cleanup other viewports */
1168 for (i
= 1; i
< MAX_VIEWPORTS
; i
++)
1169 vport
->initialized
= 0;
1170 return; /* Exit thread */
1173 case FB_TRANS_PUTCHAR
:
1174 c
= IPC_GET_ARG1(call
);
1175 row
= IPC_GET_ARG2(call
);
1176 col
= IPC_GET_ARG3(call
);
1177 if (row
>= vport
->rows
|| col
>= vport
->cols
) {
1181 ipc_answer_fast(callid
,0,0,0);
1183 draw_char(vport
, c
, row
, col
, vport
->style
,
1184 IPC_GET_METHOD(call
) == FB_TRANS_PUTCHAR
);
1185 continue; /* msg already answered */
1188 cursor_print(vport
);
1191 case FB_CURSOR_GOTO
:
1192 row
= IPC_GET_ARG1(call
);
1193 col
= IPC_GET_ARG2(call
);
1194 if (row
>= vport
->rows
|| col
>= vport
->cols
) {
1200 vport
->cur_col
= col
;
1201 vport
->cur_row
= row
;
1202 cursor_print(vport
);
1204 case FB_CURSOR_VISIBILITY
:
1206 vport
->cursor_active
= IPC_GET_ARG1(call
);
1207 cursor_print(vport
);
1211 ipc_answer_fast(callid
, 0, vport
->rows
, vport
->cols
);
1214 i
= IPC_GET_ARG1(call
);
1215 if (i
> vport
->rows
|| i
< (- (int)vport
->rows
)) {
1220 scroll_port(vport
, i
*FONT_SCANLINES
);
1221 cursor_print(vport
);
1224 case FB_VIEWPORT_DB
:
1225 /* Enable double buffering */
1226 i
= IPC_GET_ARG1(call
);
1229 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1233 if (! viewports
[i
].initialized
) {
1234 retval
= EADDRNOTAVAIL
;
1237 viewports
[i
].dboffset
= 0;
1238 if (IPC_GET_ARG2(call
) == 1 && !viewports
[i
].dbdata
)
1239 viewports
[i
].dbdata
= malloc(screen
.pixelbytes
1240 * viewports
[i
].width
*
1241 viewports
[i
].height
);
1242 else if (IPC_GET_ARG2(call
) == 0 &&
1243 viewports
[i
].dbdata
) {
1244 free(viewports
[i
].dbdata
);
1245 viewports
[i
].dbdata
= NULL
;
1249 case FB_VIEWPORT_SWITCH
:
1250 i
= IPC_GET_ARG1(call
);
1251 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1255 if (! viewports
[i
].initialized
) {
1256 retval
= EADDRNOTAVAIL
;
1261 vport
= &viewports
[vp
];
1262 cursor_print(vport
);
1265 case FB_VIEWPORT_CREATE
:
1266 retval
= viewport_create(IPC_GET_ARG1(call
) >> 16,
1267 IPC_GET_ARG1(call
) & 0xffff, IPC_GET_ARG2(call
)
1268 >> 16, IPC_GET_ARG2(call
) & 0xffff);
1270 case FB_VIEWPORT_DELETE
:
1271 i
= IPC_GET_ARG1(call
);
1272 if (i
< 0 || i
>= MAX_VIEWPORTS
) {
1276 if (! viewports
[i
].initialized
) {
1277 retval
= EADDRNOTAVAIL
;
1280 viewports
[i
].initialized
= 0;
1281 if (viewports
[i
].dbdata
) {
1282 free(viewports
[i
].dbdata
);
1283 viewports
[i
].dbdata
= NULL
;
1288 vport
->style
.fg_color
= IPC_GET_ARG1(call
);
1289 vport
->style
.bg_color
= IPC_GET_ARG2(call
);
1292 case FB_GET_RESOLUTION
:
1293 ipc_answer_fast(callid
, 0, screen
.xres
,screen
.yres
);
1295 case FB_POINTER_MOVE
:
1296 pointer_enabled
= 1;
1297 mouse_move(IPC_GET_ARG1(call
), IPC_GET_ARG2(call
));
1303 ipc_answer_fast(callid
,retval
,0,0);
1307 /** Initialization of framebuffer */
1311 unsigned int fb_width
;
1312 unsigned int fb_height
;
1313 unsigned int fb_scanline
;
1314 unsigned int fb_visual
;
1315 bool fb_invert_colors
;
1319 async_set_client_connection(fb_client_connection
);
1321 fb_ph_addr
= (void *) sysinfo_value("fb.address.physical");
1322 fb_width
= sysinfo_value("fb.width");
1323 fb_height
= sysinfo_value("fb.height");
1324 fb_scanline
= sysinfo_value("fb.scanline");
1325 fb_visual
= sysinfo_value("fb.visual");
1326 fb_invert_colors
= sysinfo_value("fb.invert-colors");
1328 asz
= fb_scanline
* fb_height
;
1329 fb_addr
= as_get_mappable_page(asz
, (int)
1330 sysinfo_value("fb.address.color"));
1332 physmem_map(fb_ph_addr
, fb_addr
, ALIGN_UP(asz
, PAGE_SIZE
) >>
1333 PAGE_WIDTH
, AS_AREA_READ
| AS_AREA_WRITE
);
1335 if (screen_init(fb_addr
, fb_width
, fb_height
, fb_scanline
, fb_visual
,