00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00040 #include <stdlib.h>
00041 #include <unistd.h>
00042 #include <string.h>
00043 #include <ddi.h>
00044 #include <sysinfo.h>
00045 #include <align.h>
00046 #include <as.h>
00047 #include <ipc/fb.h>
00048 #include <ipc/ipc.h>
00049 #include <ipc/ns.h>
00050 #include <ipc/services.h>
00051 #include <kernel/errno.h>
00052 #include <async.h>
00053
00054 #include "font-8x16.h"
00055 #include "fb.h"
00056 #include "main.h"
00057 #include "../console/screenbuffer.h"
00058 #include "ppm.h"
00059
00060 #include "pointer.xbm"
00061 #include "pointer_mask.xbm"
00062
00063 #define DEFAULT_BGCOLOR 0xf0f0f0
00064 #define DEFAULT_FGCOLOR 0x0
00065
00066
00067
00068
00069 typedef void (*conv2scr_fn_t)(void *, int);
00070 typedef int (*conv2rgb_fn_t)(void *);
00071
00072 struct {
00073 __u8 *fbaddress ;
00074
00075 unsigned int xres ;
00076 unsigned int yres ;
00077 unsigned int scanline ;
00078 unsigned int pixelbytes ;
00079
00080 conv2scr_fn_t rgb2scr;
00081 conv2rgb_fn_t scr2rgb;
00082 } screen;
00083
00084 typedef struct {
00085 int initialized;
00086 unsigned int x, y;
00087 unsigned int width, height;
00088
00089
00090 unsigned int rows, cols;
00091
00092 style_t style;
00093
00094 int cursor_active, cur_col, cur_row;
00095 int cursor_shown;
00096
00097 __u8 *dbdata;
00098 unsigned int dboffset;
00099 unsigned int paused;
00100 } viewport_t;
00101
00102 #define MAX_ANIM_LEN 8
00103 #define MAX_ANIMATIONS 4
00104 typedef struct {
00105 int initialized;
00106 int enabled;
00107 unsigned int vp;
00108
00109 unsigned int pos;
00110 unsigned int animlen;
00111 unsigned int pixmaps[MAX_ANIM_LEN];
00112 } animation_t;
00113 static animation_t animations[MAX_ANIMATIONS];
00114 static int anims_enabled;
00115
00119 #define MAX_PIXMAPS 256
00120 typedef struct {
00121 unsigned int width;
00122 unsigned int height;
00123 __u8 *data;
00124 } pixmap_t;
00125 static pixmap_t pixmaps[MAX_PIXMAPS];
00126
00127
00128 #define MAX_VIEWPORTS 128
00129 static viewport_t viewports[128];
00130
00131
00132 static int client_connected = 0;
00133
00134 #define RED(x, bits) ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
00135 #define GREEN(x, bits) ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
00136 #define BLUE(x, bits) ((x >> (8 - bits)) & ((1 << bits) - 1))
00137
00138 #define COL_WIDTH 8
00139 #define ROW_BYTES (screen.scanline * FONT_SCANLINES)
00140
00141 #define POINTPOS(x, y) ((y) * screen.scanline + (x) * screen.pixelbytes)
00142
00143
00144 static void rgb_4byte(void *dst, int rgb)
00145 {
00146 *(int *)dst = rgb;
00147 }
00148
00149 static int byte4_rgb(void *src)
00150 {
00151 return (*(int *)src) & 0xffffff;
00152 }
00153
00154 static void rgb_3byte(void *dst, int rgb)
00155 {
00156 __u8 *scr = dst;
00157 #if (defined(BIG_ENDIAN) || defined(FB_BIG_ENDIAN))
00158 scr[0] = RED(rgb, 8);
00159 scr[1] = GREEN(rgb, 8);
00160 scr[2] = BLUE(rgb, 8);
00161 #else
00162 scr[2] = RED(rgb, 8);
00163 scr[1] = GREEN(rgb, 8);
00164 scr[0] = BLUE(rgb, 8);
00165 #endif
00166
00167
00168 }
00169
00170 static int byte3_rgb(void *src)
00171 {
00172 __u8 *scr = src;
00173 #if (defined(BIG_ENDIAN) || defined(FB_BIG_ENDIAN))
00174 return scr[0] << 16 | scr[1] << 8 | scr[2];
00175 #else
00176 return scr[2] << 16 | scr[1] << 8 | scr[0];
00177 #endif
00178 }
00179
00181 static void rgb_2byte(void *dst, int rgb)
00182 {
00183
00184 *((__u16 *)(dst)) = RED(rgb, 5) << 11 | GREEN(rgb, 6) << 5 | BLUE(rgb, 5);
00185 }
00186
00188 static int byte2_rgb(void *src)
00189 {
00190 int color = *(__u16 *)(src);
00191 return (((color >> 11) & 0x1f) << (16 + 3)) | (((color >> 5) & 0x3f) << (8 + 2)) | ((color & 0x1f) << 3);
00192 }
00193
00195 static void rgb_1byte(void *dst, int rgb)
00196 {
00197 *(__u8 *)dst = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 | BLUE(rgb, 3);
00198 }
00199
00201 static int byte1_rgb(void *src)
00202 {
00203 int color = *(__u8 *)src;
00204 return (((color >> 5) & 0x7) << (16 + 5)) | (((color >> 3) & 0x3) << (8 + 6)) | ((color & 0x7) << 5);
00205 }
00206
00214 static void putpixel(viewport_t *vport, unsigned int x, unsigned int y, int color)
00215 {
00216 int dx = vport->x + x;
00217 int dy = vport->y + y;
00218
00219 if (! (vport->paused && vport->dbdata))
00220 (*screen.rgb2scr)(&screen.fbaddress[POINTPOS(dx,dy)],color);
00221
00222 if (vport->dbdata) {
00223 int dline = (y + vport->dboffset) % vport->height;
00224 int doffset = screen.pixelbytes * (dline * vport->width + x);
00225 (*screen.rgb2scr)(&vport->dbdata[doffset],color);
00226 }
00227 }
00228
00230 static int getpixel(viewport_t *vport, unsigned int x, unsigned int y)
00231 {
00232 int dx = vport->x + x;
00233 int dy = vport->y + y;
00234
00235 return (*screen.scr2rgb)(&screen.fbaddress[POINTPOS(dx,dy)]);
00236 }
00237
00238 static inline void putpixel_mem(char *mem, unsigned int x, unsigned int y,
00239 int color)
00240 {
00241 (*screen.rgb2scr)(&mem[POINTPOS(x,y)],color);
00242 }
00243
00244 static void draw_rectangle(viewport_t *vport, unsigned int sx, unsigned int sy,
00245 unsigned int width, unsigned int height,
00246 int color)
00247 {
00248 unsigned int x, y;
00249 static void *tmpline;
00250
00251 if (!tmpline)
00252 tmpline = malloc(screen.scanline*screen.pixelbytes);
00253
00254
00255 for (x = 0; x < width; x++)
00256 putpixel_mem(tmpline, x, 0, color);
00257
00258 if (!vport->paused) {
00259
00260 sx += vport->x;
00261 sy += vport->y;
00262
00263 for (y = sy;y < sy+height; y++)
00264 memcpy(&screen.fbaddress[POINTPOS(sx,y)], tmpline,
00265 screen.pixelbytes * width);
00266 }
00267 if (vport->dbdata) {
00268 for (y=sy;y < sy+height; y++) {
00269 int rline = (y + vport->dboffset) % vport->height;
00270 int rpos = (rline * vport->width + sx) * screen.pixelbytes;
00271 memcpy(&vport->dbdata[rpos], tmpline, screen.pixelbytes * width);
00272 }
00273 }
00274
00275 }
00276
00278 static void clear_port(viewport_t *vport)
00279 {
00280 draw_rectangle(vport, 0, 0, vport->width, vport->height, vport->style.bg_color);
00281 }
00282
00288 static void scroll_port_nodb(viewport_t *vport, int lines)
00289 {
00290 int y;
00291
00292 if (lines > 0) {
00293 for (y=vport->y; y < vport->y+vport->height - lines; y++)
00294 memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
00295 &screen.fbaddress[POINTPOS(vport->x,y + lines)],
00296 screen.pixelbytes * vport->width);
00297 draw_rectangle(vport, 0, vport->height - lines,
00298 vport->width, lines, vport->style.bg_color);
00299 } else if (lines < 0) {
00300 lines = -lines;
00301 for (y=vport->y + vport->height-1; y >= vport->y + lines; y--)
00302 memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
00303 &screen.fbaddress[POINTPOS(vport->x,y - lines)],
00304 screen.pixelbytes * vport->width);
00305 draw_rectangle(vport, 0, 0, vport->width, lines, vport->style.bg_color);
00306 }
00307 }
00308
00310 static void refresh_viewport_db(viewport_t *vport)
00311 {
00312 unsigned int y, srcy, srcoff, dsty, dstx;
00313
00314 for (y = 0; y < vport->height; y++) {
00315 srcy = (y + vport->dboffset) % vport->height;
00316 srcoff = (vport->width * srcy) * screen.pixelbytes;
00317
00318 dstx = vport->x;
00319 dsty = vport->y + y;
00320
00321 memcpy(&screen.fbaddress[POINTPOS(dstx,dsty)],
00322 &vport->dbdata[srcoff],
00323 vport->width*screen.pixelbytes);
00324 }
00325 }
00326
00328 static void scroll_port_db(viewport_t *vport, int lines)
00329 {
00330 ++vport->paused;
00331 if (lines > 0) {
00332 draw_rectangle(vport, 0, 0, vport->width, lines,
00333 vport->style.bg_color);
00334 vport->dboffset += lines;
00335 vport->dboffset %= vport->height;
00336 } else if (lines < 0) {
00337 lines = -lines;
00338 draw_rectangle(vport, 0, vport->height-lines,
00339 vport->width, lines,
00340 vport->style.bg_color);
00341
00342 if (vport->dboffset < lines)
00343 vport->dboffset += vport->height;
00344 vport->dboffset -= lines;
00345 }
00346
00347 --vport->paused;
00348
00349 refresh_viewport_db(vport);
00350 }
00351
00353 static void scroll_port(viewport_t *vport, int lines)
00354 {
00355 if (vport->dbdata)
00356 scroll_port_db(vport, lines);
00357 else
00358 scroll_port_nodb(vport, lines);
00359
00360 }
00361
00362 static void invert_pixel(viewport_t *vport, unsigned int x, unsigned int y)
00363 {
00364 putpixel(vport, x, y, ~getpixel(vport, x, y));
00365 }
00366
00367
00368
00369
00370
00379 static void draw_glyph(viewport_t *vport,__u8 glyph, unsigned int sx, unsigned int sy,
00380 style_t style, int transparent)
00381 {
00382 int i;
00383 unsigned int y;
00384 unsigned int glline;
00385
00386 for (y = 0; y < FONT_SCANLINES; y++) {
00387 glline = fb_font[glyph * FONT_SCANLINES + y];
00388 for (i = 0; i < 8; i++) {
00389 if (glline & (1 << (7 - i)))
00390 putpixel(vport, sx + i, sy + y, style.fg_color);
00391 else if (!transparent)
00392 putpixel(vport, sx + i, sy + y, style.bg_color);
00393 }
00394 }
00395 }
00396
00398 static void invert_char(viewport_t *vport,unsigned int row, unsigned int col)
00399 {
00400 unsigned int x;
00401 unsigned int y;
00402
00403 for (x = 0; x < COL_WIDTH; x++)
00404 for (y = 0; y < FONT_SCANLINES; y++)
00405 invert_pixel(vport, col * COL_WIDTH + x, row * FONT_SCANLINES + y);
00406 }
00407
00408
00409
00410
00411
00416 static int viewport_create(unsigned int x, unsigned int y,unsigned int width,
00417 unsigned int height)
00418 {
00419 int i;
00420
00421 for (i=0; i < MAX_VIEWPORTS; i++) {
00422 if (!viewports[i].initialized)
00423 break;
00424 }
00425 if (i == MAX_VIEWPORTS)
00426 return ELIMIT;
00427
00428 viewports[i].x = x;
00429 viewports[i].y = y;
00430 viewports[i].width = width;
00431 viewports[i].height = height;
00432
00433 viewports[i].rows = height / FONT_SCANLINES;
00434 viewports[i].cols = width / COL_WIDTH;
00435
00436 viewports[i].style.bg_color = DEFAULT_BGCOLOR;
00437 viewports[i].style.fg_color = DEFAULT_FGCOLOR;
00438
00439 viewports[i].cur_col = 0;
00440 viewports[i].cur_row = 0;
00441 viewports[i].cursor_active = 0;
00442
00443 viewports[i].initialized = 1;
00444
00445 return i;
00446 }
00447
00448
00458 static void screen_init(void *addr, unsigned int xres, unsigned int yres, unsigned int bpp, unsigned int scan)
00459 {
00460 switch (bpp) {
00461 case 8:
00462 screen.rgb2scr = rgb_1byte;
00463 screen.scr2rgb = byte1_rgb;
00464 screen.pixelbytes = 1;
00465 break;
00466 case 16:
00467 screen.rgb2scr = rgb_2byte;
00468 screen.scr2rgb = byte2_rgb;
00469 screen.pixelbytes = 2;
00470 break;
00471 case 24:
00472 screen.rgb2scr = rgb_3byte;
00473 screen.scr2rgb = byte3_rgb;
00474 screen.pixelbytes = 3;
00475 break;
00476 case 32:
00477 screen.rgb2scr = rgb_4byte;
00478 screen.scr2rgb = byte4_rgb;
00479 screen.pixelbytes = 4;
00480 break;
00481 }
00482
00483
00484 screen.fbaddress = (unsigned char *) addr;
00485 screen.xres = xres;
00486 screen.yres = yres;
00487 screen.scanline = scan;
00488
00489
00490 viewport_create(0,0,xres,yres);
00491 }
00492
00494 static void cursor_hide(viewport_t *vport)
00495 {
00496 if (vport->cursor_active && vport->cursor_shown) {
00497 invert_char(vport, vport->cur_row, vport->cur_col);
00498 vport->cursor_shown = 0;
00499 }
00500 }
00501
00503 static void cursor_print(viewport_t *vport)
00504 {
00505
00506 if (vport->cursor_active) {
00507 invert_char(vport, vport->cur_row, vport->cur_col);
00508 vport->cursor_shown = 1;
00509 }
00510 }
00511
00513 static void cursor_blink(viewport_t *vport)
00514 {
00515 if (vport->cursor_shown)
00516 cursor_hide(vport);
00517 else
00518 cursor_print(vport);
00519 }
00520
00529 static void draw_char(viewport_t *vport, char c, unsigned int row, unsigned int col,
00530 style_t style, int transparent)
00531 {
00532
00533 if (vport->cursor_active && vport->cursor_shown &&
00534 (vport->cur_col != col || vport->cur_row != row))
00535 invert_char(vport, vport->cur_row, vport->cur_col);
00536
00537 draw_glyph(vport, c, col * COL_WIDTH, row * FONT_SCANLINES, style, transparent);
00538
00539 vport->cur_col = col;
00540 vport->cur_row = row;
00541
00542 vport->cur_col++;
00543 if (vport->cur_col>= vport->cols) {
00544 vport->cur_col = 0;
00545 vport->cur_row++;
00546 if (vport->cur_row >= vport->rows)
00547 vport->cur_row--;
00548 }
00549 cursor_print(vport);
00550 }
00551
00557 static void draw_text_data(viewport_t *vport, keyfield_t *data)
00558 {
00559 int i;
00560 int col,row;
00561
00562 clear_port(vport);
00563 for (i=0; i < vport->cols * vport->rows; i++) {
00564 if (data[i].character == ' ' && style_same(data[i].style,vport->style))
00565 continue;
00566 col = i % vport->cols;
00567 row = i / vport->cols;
00568 draw_glyph(vport, data[i].character, col * COL_WIDTH, row * FONT_SCANLINES,
00569 data[i].style, style_same(data[i].style,vport->style));
00570 }
00571 cursor_print(vport);
00572 }
00573
00574
00576 static int find_free_pixmap(void)
00577 {
00578 int i;
00579
00580 for (i=0;i < MAX_PIXMAPS;i++)
00581 if (!pixmaps[i].data)
00582 return i;
00583 return -1;
00584 }
00585
00586 static void putpixel_pixmap(int pm, unsigned int x, unsigned int y, int color)
00587 {
00588 pixmap_t *pmap = &pixmaps[pm];
00589 int pos = (y * pmap->width + x) * screen.pixelbytes;
00590
00591 (*screen.rgb2scr)(&pmap->data[pos],color);
00592 }
00593
00595 static int shm2pixmap(unsigned char *shm, size_t size)
00596 {
00597 int pm;
00598 pixmap_t *pmap;
00599
00600 pm = find_free_pixmap();
00601 if (pm == -1)
00602 return ELIMIT;
00603 pmap = &pixmaps[pm];
00604
00605 if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
00606 return EINVAL;
00607
00608 pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
00609 if (!pmap->data)
00610 return ENOMEM;
00611
00612 ppm_draw(shm, size, 0, 0, pmap->width, pmap->height,
00613 (putpixel_cb_t)putpixel_pixmap, (void *)pm);
00614
00615 return pm;
00616 }
00617
00638 static int shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
00639 {
00640 static keyfield_t *interbuffer = NULL;
00641 static size_t intersize = 0;
00642
00643 static unsigned char *shm = NULL;
00644 static ipcarg_t shm_id = 0;
00645 static size_t shm_size;
00646
00647 int handled = 1;
00648 int retval = 0;
00649 viewport_t *vport = &viewports[vp];
00650 unsigned int x,y;
00651
00652 switch (IPC_GET_METHOD(*call)) {
00653 case IPC_M_AS_AREA_SEND:
00654
00655 if (IPC_GET_ARG1(*call) == shm_id) {
00656 void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
00657 shm_size = IPC_GET_ARG2(*call);
00658 if (!ipc_answer_fast(callid, 0, (sysarg_t)dest, 0))
00659 shm = dest;
00660 else
00661 shm_id = 0;
00662 if (shm[0] != 'P')
00663 while (1)
00664 ;
00665 return 1;
00666 } else {
00667 intersize = IPC_GET_ARG2(*call);
00668 receive_comm_area(callid,call,(void *)&interbuffer);
00669 }
00670 return 1;
00671 case FB_PREPARE_SHM:
00672 if (shm_id)
00673 retval = EBUSY;
00674 else
00675 shm_id = IPC_GET_ARG1(*call);
00676 break;
00677
00678 case FB_DROP_SHM:
00679 if (shm) {
00680 as_area_destroy(shm);
00681 shm = NULL;
00682 }
00683 shm_id = 0;
00684 break;
00685
00686 case FB_SHM2PIXMAP:
00687 if (!shm) {
00688 retval = EINVAL;
00689 break;
00690 }
00691 retval = shm2pixmap(shm, shm_size);
00692 break;
00693 case FB_DRAW_PPM:
00694 if (!shm) {
00695 retval = EINVAL;
00696 break;
00697 }
00698 x = IPC_GET_ARG1(*call);
00699 y = IPC_GET_ARG2(*call);
00700 if (x > vport->width || y > vport->height) {
00701 retval = EINVAL;
00702 break;
00703 }
00704
00705 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call), IPC_GET_ARG2(*call),
00706 vport->width - x, vport->height - y, (putpixel_cb_t)putpixel, vport);
00707 break;
00708 case FB_DRAW_TEXT_DATA:
00709 if (!interbuffer) {
00710 retval = EINVAL;
00711 break;
00712 }
00713 if (intersize < vport->cols*vport->rows*sizeof(*interbuffer)) {
00714 retval = EINVAL;
00715 break;
00716 }
00717 draw_text_data(vport, interbuffer);
00718 break;
00719 default:
00720 handled = 0;
00721 }
00722
00723 if (handled)
00724 ipc_answer_fast(callid, retval, 0, 0);
00725 return handled;
00726 }
00727
00728 static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
00729 {
00730 int y;
00731 int rowsize;
00732 int tmp;
00733 int width = vport->width;
00734 int height = vport->height;
00735
00736 if (width + vport->x > screen.xres)
00737 width = screen.xres - vport->x;
00738 if (height + vport->y > screen.yres)
00739 height = screen.yres - vport->y;
00740
00741 rowsize = width * screen.pixelbytes;
00742
00743 for (y=0;y < height; y++) {
00744 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
00745 memcpy(pmap->data + rowsize*y, screen.fbaddress + tmp, rowsize);
00746 }
00747 }
00748
00750 static int save_vp_to_pixmap(viewport_t *vport)
00751 {
00752 int pm;
00753 pixmap_t *pmap;
00754
00755 pm = find_free_pixmap();
00756 if (pm == -1)
00757 return ELIMIT;
00758
00759 pmap = &pixmaps[pm];
00760 pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
00761 if (!pmap->data)
00762 return ENOMEM;
00763
00764 pmap->width = vport->width;
00765 pmap->height = vport->height;
00766
00767 copy_vp_to_pixmap(vport, pmap);
00768
00769 return pm;
00770 }
00771
00777 static int draw_pixmap(int vp, int pm)
00778 {
00779 pixmap_t *pmap = &pixmaps[pm];
00780 viewport_t *vport = &viewports[vp];
00781 int y;
00782 int tmp, srcrowsize;
00783 int realwidth, realheight, realrowsize;
00784 int width = vport->width;
00785 int height = vport->height;
00786
00787 if (width + vport->x > screen.xres)
00788 width = screen.xres - vport->x;
00789 if (height + vport->y > screen.yres)
00790 height = screen.yres - vport->y;
00791
00792 if (!pmap->data)
00793 return EINVAL;
00794
00795 realwidth = pmap->width <= width ? pmap->width : width;
00796 realheight = pmap->height <= height ? pmap->height : height;
00797
00798 srcrowsize = vport->width * screen.pixelbytes;
00799 realrowsize = realwidth * screen.pixelbytes;
00800
00801 for (y=0; y < realheight; y++) {
00802 tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
00803 memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize, realrowsize);
00804 }
00805 return 0;
00806 }
00807
00809 static void anims_tick(void)
00810 {
00811 int i;
00812 static int counts = 0;
00813
00814
00815 counts = (counts+1) % 8;
00816 if (counts)
00817 return;
00818
00819 for (i=0; i < MAX_ANIMATIONS; i++) {
00820 if (!animations[i].animlen || !animations[i].initialized || !animations[i].enabled)
00821 continue;
00822 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
00823 animations[i].pos = (animations[i].pos+1) % animations[i].animlen;
00824 }
00825 }
00826
00827
00828 static int pointer_x, pointer_y;
00829 static int pointer_shown, pointer_enabled;
00830 static int pointer_vport = -1;
00831 static int pointer_pixmap = -1;
00832
00833 static void mouse_show(void)
00834 {
00835 int i,j;
00836 int visibility;
00837 int color;
00838 int bytepos;
00839
00840 if (pointer_shown || !pointer_enabled)
00841 return;
00842
00843
00844 if (pointer_vport == -1) {
00845 pointer_vport = viewport_create(pointer_x, pointer_y, pointer_width, pointer_height);
00846 if (pointer_vport < 0)
00847 return;
00848 } else {
00849 viewports[pointer_vport].x = pointer_x;
00850 viewports[pointer_vport].y = pointer_y;
00851 }
00852
00853 if (pointer_pixmap == -1)
00854 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
00855 else
00856 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
00857
00858
00859 for (i=0; i < pointer_height; i++)
00860 for (j=0;j < pointer_width; j++) {
00861 bytepos = i*((pointer_width-1)/8+1) + j/8;
00862 visibility = pointer_mask_bits[bytepos] & (1 << (j % 8));
00863 if (visibility) {
00864 color = pointer_bits[bytepos] & (1 << (j % 8)) ? 0 : 0xffffff;
00865 if (pointer_x+j < screen.xres && pointer_y+i < screen.yres)
00866 putpixel(&viewports[0], pointer_x+j, pointer_y+i, color);
00867 }
00868 }
00869 pointer_shown = 1;
00870 }
00871
00872 static void mouse_hide(void)
00873 {
00874
00875 if (pointer_shown) {
00876 draw_pixmap(pointer_vport, pointer_pixmap);
00877 pointer_shown = 0;
00878 }
00879 }
00880
00881 static void mouse_move(unsigned int x, unsigned int y)
00882 {
00883 mouse_hide();
00884 pointer_x = x;
00885 pointer_y = y;
00886 mouse_show();
00887 }
00888
00889 static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
00890 {
00891 int handled = 1;
00892 int retval = 0;
00893 int i,nvp;
00894 int newval;
00895
00896 switch (IPC_GET_METHOD(*call)) {
00897 case FB_ANIM_CREATE:
00898 nvp = IPC_GET_ARG1(*call);
00899 if (nvp == -1)
00900 nvp = vp;
00901 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
00902 retval = EINVAL;
00903 break;
00904 }
00905 for (i=0; i < MAX_ANIMATIONS; i++) {
00906 if (! animations[i].initialized)
00907 break;
00908 }
00909 if (i == MAX_ANIMATIONS) {
00910 retval = ELIMIT;
00911 break;
00912 }
00913 animations[i].initialized = 1;
00914 animations[i].animlen = 0;
00915 animations[i].pos = 0;
00916 animations[i].enabled = 0;
00917 animations[i].vp = nvp;
00918 retval = i;
00919 break;
00920 case FB_ANIM_DROP:
00921 i = IPC_GET_ARG1(*call);
00922 if (i >= MAX_ANIMATIONS || i < 0) {
00923 retval = EINVAL;
00924 break;
00925 }
00926 animations[i].initialized = 0;
00927 break;
00928 case FB_ANIM_ADDPIXMAP:
00929 i = IPC_GET_ARG1(*call);
00930 if (i >= MAX_ANIMATIONS || i < 0 || !animations[i].initialized) {
00931 retval = EINVAL;
00932 break;
00933 }
00934 if (animations[i].animlen == MAX_ANIM_LEN) {
00935 retval = ELIMIT;
00936 break;
00937 }
00938 newval = IPC_GET_ARG2(*call);
00939 if (newval < 0 || newval > MAX_PIXMAPS || !pixmaps[newval].data) {
00940 retval = EINVAL;
00941 break;
00942 }
00943 animations[i].pixmaps[animations[i].animlen++] = newval;
00944 break;
00945 case FB_ANIM_CHGVP:
00946 i = IPC_GET_ARG1(*call);
00947 if (i >= MAX_ANIMATIONS || i < 0) {
00948 retval = EINVAL;
00949 break;
00950 }
00951 nvp = IPC_GET_ARG2(*call);
00952 if (nvp == -1)
00953 nvp = vp;
00954 if (nvp >= MAX_VIEWPORTS || nvp < 0 || !viewports[nvp].initialized) {
00955 retval = EINVAL;
00956 break;
00957 }
00958 animations[i].vp = nvp;
00959 break;
00960 case FB_ANIM_START:
00961 case FB_ANIM_STOP:
00962 i = IPC_GET_ARG1(*call);
00963 if (i >= MAX_ANIMATIONS || i < 0) {
00964 retval = EINVAL;
00965 break;
00966 }
00967 newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
00968 if (newval ^ animations[i].enabled) {
00969 animations[i].enabled = newval;
00970 anims_enabled += newval ? 1 : -1;
00971 }
00972 break;
00973 default:
00974 handled = 0;
00975 }
00976 if (handled)
00977 ipc_answer_fast(callid, retval, 0, 0);
00978 return handled;
00979 }
00980
00982 static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
00983 {
00984 int handled = 1;
00985 int retval = 0;
00986 int i,nvp;
00987
00988 switch (IPC_GET_METHOD(*call)) {
00989 case FB_VP_DRAW_PIXMAP:
00990 nvp = IPC_GET_ARG1(*call);
00991 if (nvp == -1)
00992 nvp = vp;
00993 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized) {
00994 retval = EINVAL;
00995 break;
00996 }
00997 i = IPC_GET_ARG2(*call);
00998 retval = draw_pixmap(nvp, i);
00999 break;
01000 case FB_VP2PIXMAP:
01001 nvp = IPC_GET_ARG1(*call);
01002 if (nvp == -1)
01003 nvp = vp;
01004 if (nvp < 0 || nvp >= MAX_VIEWPORTS || !viewports[nvp].initialized)
01005 retval = EINVAL;
01006 else
01007 retval = save_vp_to_pixmap(&viewports[nvp]);
01008 break;
01009 case FB_DROP_PIXMAP:
01010 i = IPC_GET_ARG1(*call);
01011 if (i >= MAX_PIXMAPS) {
01012 retval = EINVAL;
01013 break;
01014 }
01015 if (pixmaps[i].data) {
01016 free(pixmaps[i].data);
01017 pixmaps[i].data = NULL;
01018 }
01019 break;
01020 default:
01021 handled = 0;
01022 }
01023
01024 if (handled)
01025 ipc_answer_fast(callid, retval, 0, 0);
01026 return handled;
01027
01028 }
01029
01033 static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
01034 {
01035 ipc_callid_t callid;
01036 ipc_call_t call;
01037 int retval;
01038 int i;
01039 unsigned int row,col;
01040 char c;
01041
01042 int vp = 0;
01043 viewport_t *vport = &viewports[0];
01044
01045 if (client_connected) {
01046 ipc_answer_fast(iid, ELIMIT, 0,0);
01047 return;
01048 }
01049 client_connected = 1;
01050 ipc_answer_fast(iid, 0, 0, 0);
01051
01052 while (1) {
01053 if (vport->cursor_active || anims_enabled)
01054 callid = async_get_call_timeout(&call,250000);
01055 else
01056 callid = async_get_call(&call);
01057
01058 mouse_hide();
01059 if (!callid) {
01060 cursor_blink(vport);
01061 anims_tick();
01062 mouse_show();
01063 continue;
01064 }
01065 if (shm_handle(callid, &call, vp))
01066 continue;
01067 if (pixmap_handle(callid, &call, vp))
01068 continue;
01069 if (anim_handle(callid, &call, vp))
01070 continue;
01071
01072 switch (IPC_GET_METHOD(call)) {
01073 case IPC_M_PHONE_HUNGUP:
01074 client_connected = 0;
01075
01076 for (i=1; i < MAX_VIEWPORTS; i++)
01077 vport->initialized = 0;
01078 return;
01079
01080 case FB_PUTCHAR:
01081 case FB_TRANS_PUTCHAR:
01082 c = IPC_GET_ARG1(call);
01083 row = IPC_GET_ARG2(call);
01084 col = IPC_GET_ARG3(call);
01085 if (row >= vport->rows || col >= vport->cols) {
01086 retval = EINVAL;
01087 break;
01088 }
01089 ipc_answer_fast(callid,0,0,0);
01090
01091 draw_char(vport, c, row, col, vport->style, IPC_GET_METHOD(call) == FB_TRANS_PUTCHAR);
01092 continue;
01093 case FB_CLEAR:
01094 clear_port(vport);
01095 cursor_print(vport);
01096 retval = 0;
01097 break;
01098 case FB_CURSOR_GOTO:
01099 row = IPC_GET_ARG1(call);
01100 col = IPC_GET_ARG2(call);
01101 if (row >= vport->rows || col >= vport->cols) {
01102 retval = EINVAL;
01103 break;
01104 }
01105 retval = 0;
01106 cursor_hide(vport);
01107 vport->cur_col = col;
01108 vport->cur_row = row;
01109 cursor_print(vport);
01110 break;
01111 case FB_CURSOR_VISIBILITY:
01112 cursor_hide(vport);
01113 vport->cursor_active = IPC_GET_ARG1(call);
01114 cursor_print(vport);
01115 retval = 0;
01116 break;
01117 case FB_GET_CSIZE:
01118 ipc_answer_fast(callid, 0, vport->rows, vport->cols);
01119 continue;
01120 case FB_SCROLL:
01121 i = IPC_GET_ARG1(call);
01122 if (i > vport->rows || i < (- (int)vport->rows)) {
01123 retval = EINVAL;
01124 break;
01125 }
01126 cursor_hide(vport);
01127 scroll_port(vport, i*FONT_SCANLINES);
01128 cursor_print(vport);
01129 retval = 0;
01130 break;
01131 case FB_VIEWPORT_DB:
01132
01133 i = IPC_GET_ARG1(call);
01134 if (i == -1)
01135 i = vp;
01136 if (i < 0 || i >= MAX_VIEWPORTS) {
01137 retval = EINVAL;
01138 break;
01139 }
01140 if (! viewports[i].initialized ) {
01141 retval = EADDRNOTAVAIL;
01142 break;
01143 }
01144 viewports[i].dboffset = 0;
01145 if (IPC_GET_ARG2(call) == 1 && !viewports[i].dbdata)
01146 viewports[i].dbdata = malloc(screen.pixelbytes*viewports[i].width * viewports[i].height);
01147 else if (IPC_GET_ARG2(call) == 0 && viewports[i].dbdata) {
01148 free(viewports[i].dbdata);
01149 viewports[i].dbdata = NULL;
01150 }
01151 retval = 0;
01152 break;
01153 case FB_VIEWPORT_SWITCH:
01154 i = IPC_GET_ARG1(call);
01155 if (i < 0 || i >= MAX_VIEWPORTS) {
01156 retval = EINVAL;
01157 break;
01158 }
01159 if (! viewports[i].initialized ) {
01160 retval = EADDRNOTAVAIL;
01161 break;
01162 }
01163 cursor_hide(vport);
01164 vp = i;
01165 vport = &viewports[vp];
01166 cursor_print(vport);
01167 retval = 0;
01168 break;
01169 case FB_VIEWPORT_CREATE:
01170 retval = viewport_create(IPC_GET_ARG1(call) >> 16,
01171 IPC_GET_ARG1(call) & 0xffff,
01172 IPC_GET_ARG2(call) >> 16,
01173 IPC_GET_ARG2(call) & 0xffff);
01174 break;
01175 case FB_VIEWPORT_DELETE:
01176 i = IPC_GET_ARG1(call);
01177 if (i < 0 || i >= MAX_VIEWPORTS) {
01178 retval = EINVAL;
01179 break;
01180 }
01181 if (! viewports[i].initialized ) {
01182 retval = EADDRNOTAVAIL;
01183 break;
01184 }
01185 viewports[i].initialized = 0;
01186 if (viewports[i].dbdata) {
01187 free(viewports[i].dbdata);
01188 viewports[i].dbdata = NULL;
01189 }
01190 retval = 0;
01191 break;
01192 case FB_SET_STYLE:
01193 vport->style.fg_color = IPC_GET_ARG1(call);
01194 vport->style.bg_color = IPC_GET_ARG2(call);
01195 retval = 0;
01196 break;
01197 case FB_GET_RESOLUTION:
01198 ipc_answer_fast(callid, 0, screen.xres,screen.yres);
01199 continue;
01200 case FB_POINTER_MOVE:
01201 pointer_enabled = 1;
01202 mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
01203 retval = 0;
01204 break;
01205 default:
01206 retval = ENOENT;
01207 }
01208 ipc_answer_fast(callid,retval,0,0);
01209 }
01210 }
01211
01213 int fb_init(void)
01214 {
01215 void *fb_ph_addr;
01216 unsigned int fb_width;
01217 unsigned int fb_height;
01218 unsigned int fb_bpp;
01219 unsigned int fb_scanline;
01220 void *fb_addr;
01221 size_t asz;
01222
01223 async_set_client_connection(fb_client_connection);
01224
01225 fb_ph_addr=(void *)sysinfo_value("fb.address.physical");
01226 fb_width=sysinfo_value("fb.width");
01227 fb_height=sysinfo_value("fb.height");
01228 fb_bpp=sysinfo_value("fb.bpp");
01229 fb_scanline=sysinfo_value("fb.scanline");
01230
01231 asz = fb_scanline*fb_height;
01232 fb_addr = as_get_mappable_page(asz);
01233
01234 map_physmem(fb_ph_addr, fb_addr, ALIGN_UP(asz,PAGE_SIZE) >>PAGE_WIDTH,
01235 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE);
01236
01237 screen_init(fb_addr, fb_width, fb_height, fb_bpp, fb_scanline);
01238
01239 return 0;
01240 }
01241
01242