fb.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Martin Decky
00003  * Copyright (c) 2006 Jakub Vana
00004  * Copyright (c) 2006 Ondrej Palkovsky
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions
00009  * are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright
00012  *   notice, this list of conditions and the following disclaimer.
00013  * - Redistributions in binary form must reproduce the above copyright
00014  *   notice, this list of conditions and the following disclaimer in the
00015  *   documentation and/or other materials provided with the distribution.
00016  * - The name of the author may not be used to endorse or promote products
00017  *   derived from this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00020  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00021  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00022  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00023  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00024  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00025  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00026  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00028  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  */
00030 
00041 #include <stdlib.h>
00042 #include <unistd.h>
00043 #include <str.h>
00044 #include <ddi.h>
00045 #include <sysinfo.h>
00046 #include <align.h>
00047 #include <as.h>
00048 #include <ipc/fb.h>
00049 #include <ipc/ns.h>
00050 #include <ipc/services.h>
00051 #include <kernel/errno.h>
00052 #include <kernel/genarch/fb/visuals.h>
00053 #include <io/color.h>
00054 #include <io/style.h>
00055 #include <async.h>
00056 #include <fibril.h>
00057 #include <bool.h>
00058 #include <stdio.h>
00059 #include <byteorder.h>
00060 #include <io/screenbuffer.h>
00061 
00062 #include "font-8x16.h"
00063 #include "fb.h"
00064 #include "main.h"
00065 #include "ppm.h"
00066 
00067 #include "pointer.xbm"
00068 #include "pointer_mask.xbm"
00069 
00070 #define DEFAULT_BGCOLOR  0xf0f0f0
00071 #define DEFAULT_FGCOLOR  0x000000
00072 
00073 #define GLYPH_UNAVAIL  '?'
00074 
00075 #define MAX_ANIM_LEN    8
00076 #define MAX_ANIMATIONS  4
00077 #define MAX_PIXMAPS     256  
00078 #define MAX_VIEWPORTS   128  
00081 typedef void (*rgb_conv_t)(void *, uint32_t);
00082 
00084 typedef void (*mask_conv_t)(void *, bool);
00085 
00087 typedef void (*dg_t)(unsigned int x, unsigned int y, bool cursor,
00088     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
00089 
00090 struct {
00091         uint8_t *fb_addr;
00092         
00093         unsigned int xres;
00094         unsigned int yres;
00095         
00096         unsigned int scanline;
00097         unsigned int glyphscanline;
00098         
00099         unsigned int pixelbytes;
00100         unsigned int glyphbytes;
00101         
00103         uint8_t *glyphs;
00104         
00105         rgb_conv_t rgb_conv;
00106         mask_conv_t mask_conv;
00107 } screen;
00108 
00110 typedef struct {
00111         uint32_t glyph;
00112         uint32_t fg_color;
00113         uint32_t bg_color;
00114 } bb_cell_t;
00115 
00116 typedef struct {
00117         bool initialized;
00118         unsigned int x;
00119         unsigned int y;
00120         unsigned int width;
00121         unsigned int height;
00122         
00123         /* Text support in window */
00124         unsigned int cols;
00125         unsigned int rows;
00126         
00127         /*
00128          * Style and glyphs for text printing
00129          */
00130         
00132         attr_rgb_t attr;
00133         
00134         uint8_t *bgpixel;
00135         
00141         dg_t dglyph;
00142         
00143         /* Auto-cursor position */
00144         bool cursor_active;
00145         unsigned int cur_col;
00146         unsigned int cur_row;
00147         bool cursor_shown;
00148         
00149         /* Back buffer */
00150         bb_cell_t *backbuf;
00151         unsigned int bbsize;
00152 } viewport_t;
00153 
00154 typedef struct {
00155         bool initialized;
00156         bool enabled;
00157         unsigned int vp;
00158         
00159         unsigned int pos;
00160         unsigned int animlen;
00161         unsigned int pixmaps[MAX_ANIM_LEN];
00162 } animation_t;
00163 
00164 static animation_t animations[MAX_ANIMATIONS];
00165 static bool anims_enabled;
00166 
00167 typedef struct {
00168         unsigned int width;
00169         unsigned int height;
00170         uint8_t *data;
00171 } pixmap_t;
00172 
00173 static pixmap_t pixmaps[MAX_PIXMAPS];
00174 static viewport_t viewports[128];
00175 
00176 static bool client_connected = false;  
00178 static uint32_t color_table[16] = {
00179         [COLOR_BLACK]       = 0x000000,
00180         [COLOR_BLUE]        = 0x0000f0,
00181         [COLOR_GREEN]       = 0x00f000,
00182         [COLOR_CYAN]        = 0x00f0f0,
00183         [COLOR_RED]         = 0xf00000,
00184         [COLOR_MAGENTA]     = 0xf000f0,
00185         [COLOR_YELLOW]      = 0xf0f000,
00186         [COLOR_WHITE]       = 0xf0f0f0,
00187         
00188         [8 + COLOR_BLACK]   = 0x000000,
00189         [8 + COLOR_BLUE]    = 0x0000ff,
00190         [8 + COLOR_GREEN]   = 0x00ff00,
00191         [8 + COLOR_CYAN]    = 0x00ffff,
00192         [8 + COLOR_RED]     = 0xff0000,
00193         [8 + COLOR_MAGENTA] = 0xff00ff,
00194         [8 + COLOR_YELLOW]  = 0xffff00,
00195         [8 + COLOR_WHITE]   = 0xffffff,
00196 };
00197 
00198 static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a);
00199 static int rgb_from_style(attr_rgb_t *rgb, int style);
00200 static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color,
00201     sysarg_t bg_color, sysarg_t flags);
00202 
00203 static int fb_set_color(viewport_t *vport, sysarg_t fg_color,
00204     sysarg_t bg_color, sysarg_t attr);
00205 
00206 static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
00207     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
00208 static void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
00209     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color);
00210 
00211 static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
00212     unsigned int row);
00213 
00214 
00215 #define RED(x, bits)                 (((x) >> (8 + 8 + 8 - (bits))) & ((1 << (bits)) - 1))
00216 #define GREEN(x, bits)               (((x) >> (8 + 8 - (bits))) & ((1 << (bits)) - 1))
00217 #define BLUE(x, bits)                (((x) >> (8 - (bits))) & ((1 << (bits)) - 1))
00218 
00219 #define COL2X(col)                   ((col) * FONT_WIDTH)
00220 #define ROW2Y(row)                   ((row) * FONT_SCANLINES)
00221 
00222 #define X2COL(x)                     ((x) / FONT_WIDTH)
00223 #define Y2ROW(y)                     ((y) / FONT_SCANLINES)
00224 
00225 #define FB_POS(x, y)                 ((y) * screen.scanline + (x) * screen.pixelbytes)
00226 #define BB_POS(vport, col, row)      ((row) * vport->cols + (col))
00227 #define GLYPH_POS(glyph, y, cursor)  (((glyph) + (cursor) * FONT_GLYPHS) * screen.glyphbytes + (y) * screen.glyphscanline)
00228 
00229 /*
00230  * RGB conversion and mask functions.
00231  *
00232  * These functions write an RGB value to some memory in some predefined format.
00233  * The naming convention corresponds to the format created by these functions.
00234  * The functions use the so called network order (i.e. big endian) with respect
00235  * to their names.
00236  */
00237 
00238 static void rgb_0888(void *dst, uint32_t rgb)
00239 {
00240         *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
00241             (RED(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (BLUE(rgb, 8)));
00242 }
00243 
00244 static void bgr_0888(void *dst, uint32_t rgb)
00245 {
00246         *((uint32_t *) dst) = host2uint32_t_be((0 << 24) |
00247             (BLUE(rgb, 8) << 16) | (GREEN(rgb, 8) << 8) | (RED(rgb, 8)));
00248 }
00249 
00250 static void mask_0888(void *dst, bool mask)
00251 {
00252         bgr_0888(dst, mask ? 0xffffff : 0);
00253 }
00254 
00255 static void rgb_8880(void *dst, uint32_t rgb)
00256 {
00257         *((uint32_t *) dst) = host2uint32_t_be((RED(rgb, 8) << 24) |
00258             (GREEN(rgb, 8) << 16) | (BLUE(rgb, 8) << 8) | 0);
00259 }
00260 
00261 static void bgr_8880(void *dst, uint32_t rgb)
00262 {
00263         *((uint32_t *) dst) = host2uint32_t_be((BLUE(rgb, 8) << 24) |
00264             (GREEN(rgb, 8) << 16) | (RED(rgb, 8) << 8) | 0);
00265 }
00266 
00267 static void mask_8880(void *dst, bool mask)
00268 {
00269         bgr_8880(dst, mask ? 0xffffff : 0);
00270 }
00271 
00272 static void rgb_888(void *dst, uint32_t rgb)
00273 {
00274         ((uint8_t *) dst)[0] = RED(rgb, 8);
00275         ((uint8_t *) dst)[1] = GREEN(rgb, 8);
00276         ((uint8_t *) dst)[2] = BLUE(rgb, 8);
00277 }
00278 
00279 static void bgr_888(void *dst, uint32_t rgb)
00280 {
00281         ((uint8_t *) dst)[0] = BLUE(rgb, 8);
00282         ((uint8_t *) dst)[1] = GREEN(rgb, 8);
00283         ((uint8_t *) dst)[2] = RED(rgb, 8);
00284 }
00285 
00286 static void mask_888(void *dst, bool mask)
00287 {
00288         bgr_888(dst, mask ? 0xffffff : 0);
00289 }
00290 
00291 static void rgb_555_be(void *dst, uint32_t rgb)
00292 {
00293         *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 10 |
00294             GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
00295 }
00296 
00297 static void rgb_555_le(void *dst, uint32_t rgb)
00298 {
00299         *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 10 |
00300             GREEN(rgb, 5) << 5 | BLUE(rgb, 5));
00301 }
00302 
00303 static void rgb_565_be(void *dst, uint32_t rgb)
00304 {
00305         *((uint16_t *) dst) = host2uint16_t_be(RED(rgb, 5) << 11 |
00306             GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
00307 }
00308 
00309 static void rgb_565_le(void *dst, uint32_t rgb)
00310 {
00311         *((uint16_t *) dst) = host2uint16_t_le(RED(rgb, 5) << 11 |
00312             GREEN(rgb, 6) << 5 | BLUE(rgb, 5));
00313 }
00314 
00315 static void mask_555(void *dst, bool mask)
00316 {
00317         rgb_555_be(dst, mask ? 0xffffff : 0);
00318 }
00319 
00320 static void mask_565(void *dst, bool mask)
00321 {
00322         rgb_565_be(dst, mask ? 0xffffff : 0);
00323 }
00324 
00325 static void bgr_323(void *dst, uint32_t rgb)
00326 {
00327         *((uint8_t *) dst)
00328             = ~((RED(rgb, 3) << 5) | (GREEN(rgb, 2) << 3) | BLUE(rgb, 3));
00329 }
00330 
00331 static void mask_323(void *dst, bool mask)
00332 {
00333         bgr_323(dst, mask ? 0x0 : ~0x0);
00334 }
00335 
00341 static void draw_filled_rect(unsigned int x0, unsigned int y0, unsigned int x1,
00342     unsigned int y1, uint32_t color)
00343 {
00344         unsigned int x;
00345         unsigned int y;
00346         unsigned int copy_bytes;
00347         
00348         uint8_t *sp;
00349         uint8_t *dp;
00350         uint8_t cbuf[4];
00351         
00352         if ((y0 >= y1) || (x0 >= x1))
00353                 return;
00354         
00355         screen.rgb_conv(cbuf, color);
00356         
00357         sp = &screen.fb_addr[FB_POS(x0, y0)];
00358         dp = sp;
00359         
00360         /* Draw the first line. */
00361         for (x = x0; x < x1; x++) {
00362                 memcpy(dp, cbuf, screen.pixelbytes);
00363                 dp += screen.pixelbytes;
00364         }
00365         
00366         dp = sp + screen.scanline;
00367         copy_bytes = (x1 - x0) * screen.pixelbytes;
00368         
00369         /* Draw the remaining lines by copying. */
00370         for (y = y0 + 1; y < y1; y++) {
00371                 memcpy(dp, sp, copy_bytes);
00372                 dp += screen.scanline;
00373         }
00374 }
00375 
00381 static void vport_redraw(viewport_t *vport)
00382 {
00383         unsigned int col;
00384         unsigned int row;
00385         
00386         for (row = 0; row < vport->rows; row++) {
00387                 for (col = 0; col < vport->cols; col++) {
00388                         draw_vp_glyph(vport, false, col, row);
00389                 }
00390         }
00391         
00392         if (COL2X(vport->cols) < vport->width) {
00393                 draw_filled_rect(
00394                     vport->x + COL2X(vport->cols), vport->y,
00395                     vport->x + vport->width, vport->y + vport->height,
00396                     vport->attr.bg_color);
00397         }
00398         
00399         if (ROW2Y(vport->rows) < vport->height) {
00400                 draw_filled_rect(
00401                     vport->x, vport->y + ROW2Y(vport->rows),
00402                     vport->x + vport->width, vport->y + vport->height,
00403                     vport->attr.bg_color);
00404         }
00405 }
00406 
00407 static void backbuf_clear(bb_cell_t *backbuf, size_t len, uint32_t fg_color,
00408     uint32_t bg_color)
00409 {
00410         size_t i;
00411         
00412         for (i = 0; i < len; i++) {
00413                 backbuf[i].glyph = 0;
00414                 backbuf[i].fg_color = fg_color;
00415                 backbuf[i].bg_color = bg_color;
00416         }
00417 }
00418 
00424 static void vport_clear(viewport_t *vport)
00425 {
00426         backbuf_clear(vport->backbuf, vport->cols * vport->rows,
00427             vport->attr.fg_color, vport->attr.bg_color);
00428         vport_redraw(vport);
00429 }
00430 
00437 static void vport_scroll(viewport_t *vport, int lines)
00438 {
00439         unsigned int col;
00440         unsigned int row;
00441         unsigned int x;
00442         unsigned int y;
00443         uint32_t glyph;
00444         uint32_t fg_color;
00445         uint32_t bg_color;
00446         bb_cell_t *bbp;
00447         bb_cell_t *xbp;
00448         
00449         /*
00450          * Redraw.
00451          */
00452         
00453         y = vport->y;
00454         for (row = 0; row < vport->rows; row++) {
00455                 x = vport->x;
00456                 for (col = 0; col < vport->cols; col++) {
00457                         if (((int) row + lines >= 0) &&
00458                             ((int) row + lines < (int) vport->rows)) {
00459                                 xbp = &vport->backbuf[BB_POS(vport, col, row + lines)];
00460                                 bbp = &vport->backbuf[BB_POS(vport, col, row)];
00461                                 
00462                                 glyph = xbp->glyph;
00463                                 fg_color = xbp->fg_color;
00464                                 bg_color = xbp->bg_color;
00465                                 
00466                                 if ((bbp->glyph == glyph)
00467                                    && (bbp->fg_color == xbp->fg_color)
00468                                    && (bbp->bg_color == xbp->bg_color)) {
00469                                         x += FONT_WIDTH;
00470                                         continue;
00471                                 }
00472                         } else {
00473                                 glyph = 0;
00474                                 fg_color = vport->attr.fg_color;
00475                                 bg_color = vport->attr.bg_color;
00476                         }
00477                         
00478                         (*vport->dglyph)(x, y, false, screen.glyphs, glyph,
00479                             fg_color, bg_color);
00480                         x += FONT_WIDTH;
00481                 }
00482                 y += FONT_SCANLINES;
00483         }
00484         
00485         /*
00486          * Scroll backbuffer.
00487          */
00488         
00489         if (lines > 0) {
00490                 memmove(vport->backbuf, vport->backbuf + vport->cols * lines,
00491                     vport->cols * (vport->rows - lines) * sizeof(bb_cell_t));
00492                 backbuf_clear(&vport->backbuf[BB_POS(vport, 0, vport->rows - lines)],
00493                     vport->cols * lines, vport->attr.fg_color, vport->attr.bg_color);
00494         } else {
00495                 memmove(vport->backbuf - vport->cols * lines, vport->backbuf,
00496                     vport->cols * (vport->rows + lines) * sizeof(bb_cell_t));
00497                 backbuf_clear(vport->backbuf, - vport->cols * lines,
00498                     vport->attr.fg_color, vport->attr.bg_color);
00499         }
00500 }
00501 
00508 static void render_glyphs(void)
00509 {
00510         unsigned int glyph;
00511         
00512         for (glyph = 0; glyph < FONT_GLYPHS; glyph++) {
00513                 unsigned int y;
00514                 
00515                 for (y = 0; y < FONT_SCANLINES; y++) {
00516                         unsigned int x;
00517                         
00518                         for (x = 0; x < FONT_WIDTH; x++) {
00519                                 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, false) + x * screen.pixelbytes],
00520                                     (fb_font[glyph][y] & (1 << (7 - x))) ? true : false);
00521                                 
00522                                 screen.mask_conv(&screen.glyphs[GLYPH_POS(glyph, y, true) + x * screen.pixelbytes],
00523                                     (fb_font[glyph][y] & (1 << (7 - x))) ? false : true);
00524                         }
00525                 }
00526         }
00527 }
00528 
00539 static int vport_create(unsigned int x, unsigned int y,
00540     unsigned int width, unsigned int height)
00541 {
00542         unsigned int i;
00543         
00544         for (i = 0; i < MAX_VIEWPORTS; i++) {
00545                 if (!viewports[i].initialized)
00546                         break;
00547         }
00548         
00549         if (i == MAX_VIEWPORTS)
00550                 return ELIMIT;
00551         
00552         unsigned int cols = width / FONT_WIDTH;
00553         unsigned int rows = height / FONT_SCANLINES;
00554         unsigned int bbsize = cols * rows * sizeof(bb_cell_t);
00555         unsigned int word_size = sizeof(unsigned long);
00556         
00557         bb_cell_t *backbuf = (bb_cell_t *) malloc(bbsize);
00558         if (!backbuf)
00559                 return ENOMEM;
00560         
00561         uint8_t *bgpixel = (uint8_t *) malloc(screen.pixelbytes);
00562         if (!bgpixel) {
00563                 free(backbuf);
00564                 return ENOMEM;
00565         }
00566         
00567         backbuf_clear(backbuf, cols * rows, DEFAULT_FGCOLOR, DEFAULT_BGCOLOR);
00568         memset(bgpixel, 0, screen.pixelbytes);
00569         
00570         viewports[i].x = x;
00571         viewports[i].y = y;
00572         viewports[i].width = width;
00573         viewports[i].height = height;
00574         
00575         viewports[i].cols = cols;
00576         viewports[i].rows = rows;
00577         
00578         viewports[i].attr.bg_color = DEFAULT_BGCOLOR;
00579         viewports[i].attr.fg_color = DEFAULT_FGCOLOR;
00580         
00581         viewports[i].bgpixel = bgpixel;
00582         
00583         /*
00584          * Conditions necessary to select aligned version:
00585          *  - word size is divisible by pixelbytes
00586          *  - cell scanline size is divisible by word size
00587          *  - cell scanlines are word-aligned
00588          *
00589          */
00590         if (((word_size % screen.pixelbytes) == 0)
00591             && ((FONT_WIDTH * screen.pixelbytes) % word_size == 0)
00592             && ((x * screen.pixelbytes) % word_size == 0)
00593             && (screen.scanline % word_size == 0)) {
00594                 viewports[i].dglyph = draw_glyph_aligned;
00595         } else {
00596                 viewports[i].dglyph = draw_glyph_fallback;
00597         }
00598         
00599         viewports[i].cur_col = 0;
00600         viewports[i].cur_row = 0;
00601         viewports[i].cursor_active = false;
00602         viewports[i].cursor_shown = false;
00603         
00604         viewports[i].bbsize = bbsize;
00605         viewports[i].backbuf = backbuf;
00606         
00607         viewports[i].initialized = true;
00608         
00609         screen.rgb_conv(viewports[i].bgpixel, viewports[i].attr.bg_color);
00610         
00611         return i;
00612 }
00613 
00614 
00624 static bool screen_init(void *addr, unsigned int xres, unsigned int yres,
00625     unsigned int scan, unsigned int visual)
00626 {
00627         switch (visual) {
00628         case VISUAL_INDIRECT_8:
00629                 screen.rgb_conv = bgr_323;
00630                 screen.mask_conv = mask_323;
00631                 screen.pixelbytes = 1;
00632                 break;
00633         case VISUAL_RGB_5_5_5_LE:
00634                 screen.rgb_conv = rgb_555_le;
00635                 screen.mask_conv = mask_555;
00636                 screen.pixelbytes = 2;
00637                 break;
00638         case VISUAL_RGB_5_5_5_BE:
00639                 screen.rgb_conv = rgb_555_be;
00640                 screen.mask_conv = mask_555;
00641                 screen.pixelbytes = 2;
00642                 break;
00643         case VISUAL_RGB_5_6_5_LE:
00644                 screen.rgb_conv = rgb_565_le;
00645                 screen.mask_conv = mask_565;
00646                 screen.pixelbytes = 2;
00647                 break;
00648         case VISUAL_RGB_5_6_5_BE:
00649                 screen.rgb_conv = rgb_565_be;
00650                 screen.mask_conv = mask_565;
00651                 screen.pixelbytes = 2;
00652                 break;
00653         case VISUAL_RGB_8_8_8:
00654                 screen.rgb_conv = rgb_888;
00655                 screen.mask_conv = mask_888;
00656                 screen.pixelbytes = 3;
00657                 break;
00658         case VISUAL_BGR_8_8_8:
00659                 screen.rgb_conv = bgr_888;
00660                 screen.mask_conv = mask_888;
00661                 screen.pixelbytes = 3;
00662                 break;
00663         case VISUAL_RGB_8_8_8_0:
00664                 screen.rgb_conv = rgb_8880;
00665                 screen.mask_conv = mask_8880;
00666                 screen.pixelbytes = 4;
00667                 break;
00668         case VISUAL_RGB_0_8_8_8:
00669                 screen.rgb_conv = rgb_0888;
00670                 screen.mask_conv = mask_0888;
00671                 screen.pixelbytes = 4;
00672                 break;
00673         case VISUAL_BGR_0_8_8_8:
00674                 screen.rgb_conv = bgr_0888;
00675                 screen.mask_conv = mask_0888;
00676                 screen.pixelbytes = 4;
00677                 break;
00678         case VISUAL_BGR_8_8_8_0:
00679                 screen.rgb_conv = bgr_8880;
00680                 screen.mask_conv = mask_8880;
00681                 screen.pixelbytes = 4;
00682                 break;
00683         default:
00684                 return false;
00685         }
00686         
00687         screen.fb_addr = (unsigned char *) addr;
00688         screen.xres = xres;
00689         screen.yres = yres;
00690         screen.scanline = scan;
00691         
00692         screen.glyphscanline = FONT_WIDTH * screen.pixelbytes;
00693         screen.glyphbytes = screen.glyphscanline * FONT_SCANLINES;
00694         
00695         size_t glyphsize = 2 * FONT_GLYPHS * screen.glyphbytes;
00696         uint8_t *glyphs = (uint8_t *) malloc(glyphsize);
00697         if (!glyphs)
00698                 return false;
00699         
00700         memset(glyphs, 0, glyphsize);
00701         screen.glyphs = glyphs;
00702         
00703         render_glyphs();
00704         
00705         /* Create first viewport */
00706         vport_create(0, 0, xres, yres);
00707         
00708         return true;
00709 }
00710 
00711 
00734 static void draw_glyph_aligned(unsigned int x, unsigned int y, bool cursor,
00735     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
00736 {
00737         unsigned int i;
00738         unsigned int yd;
00739         unsigned long fg_buf;
00740         unsigned long bg_buf;
00741         unsigned long mask;
00742         
00743         /*
00744          * Prepare a pair of words, one filled with foreground-color
00745          * pattern and the other filled with background-color pattern.
00746          */
00747         for (i = 0; i < sizeof(unsigned long) / screen.pixelbytes; i++) {
00748                 screen.rgb_conv(&((uint8_t *) &fg_buf)[i * screen.pixelbytes],
00749                     fg_color);
00750                 screen.rgb_conv(&((uint8_t *) &bg_buf)[i * screen.pixelbytes],
00751                     bg_color);
00752         }
00753         
00754         /* Pointer to the current position in the mask. */
00755         unsigned long *maskp = (unsigned long *) &glyphs[GLYPH_POS(glyph, 0, cursor)];
00756         
00757         /* Pointer to the current position on the screen. */
00758         unsigned long *dp = (unsigned long *) &screen.fb_addr[FB_POS(x, y)];
00759         
00760         /* Width of the character cell in words. */
00761         unsigned int ww = FONT_WIDTH * screen.pixelbytes / sizeof(unsigned long);
00762         
00763         /* Offset to add when moving to another screen scanline. */
00764         unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
00765         
00766         for (yd = 0; yd < FONT_SCANLINES; yd++) {
00767                 /*
00768                  * Now process the cell scanline, combining foreground
00769                  * and background color patters using the pre-rendered mask.
00770                  */
00771                 for (i = 0; i < ww; i++) {
00772                         mask = *maskp++;
00773                         *dp++ = (fg_buf & mask) | (bg_buf & ~mask);
00774                 }
00775                 
00776                 /* Move to the beginning of the next scanline of the cell. */
00777                 dp = (unsigned long *) ((uint8_t *) dp + d_add);
00778         }
00779 }
00780 
00795 void draw_glyph_fallback(unsigned int x, unsigned int y, bool cursor,
00796     uint8_t *glyphs, uint32_t glyph, uint32_t fg_color, uint32_t bg_color)
00797 {
00798         unsigned int i;
00799         unsigned int j;
00800         unsigned int yd;
00801         uint8_t fg_buf[4];
00802         uint8_t bg_buf[4];
00803         uint8_t *sp;
00804         uint8_t b;
00805         
00806         /* Pre-render 1x the foreground and background color pixels. */
00807         if (cursor) {
00808                 screen.rgb_conv(fg_buf, bg_color);
00809                 screen.rgb_conv(bg_buf, fg_color);
00810         } else {
00811                 screen.rgb_conv(fg_buf, fg_color);
00812                 screen.rgb_conv(bg_buf, bg_color);
00813         }
00814         
00815         /* Pointer to the current position on the screen. */
00816         uint8_t *dp = (uint8_t *) &screen.fb_addr[FB_POS(x, y)];
00817         
00818         /* Offset to add when moving to another screen scanline. */
00819         unsigned int d_add = screen.scanline - FONT_WIDTH * screen.pixelbytes;
00820         
00821         for (yd = 0; yd < FONT_SCANLINES; yd++) {
00822                 /* Byte containing bits of the glyph scanline. */
00823                 b = fb_font[glyph][yd];
00824                 
00825                 for (i = 0; i < FONT_WIDTH; i++) {
00826                         /* Choose color based on the current bit. */
00827                         sp = (b & 0x80) ? fg_buf : bg_buf;
00828                         
00829                         /* Copy the pixel. */
00830                         for (j = 0; j < screen.pixelbytes; j++) {
00831                                 *dp++ = *sp++;
00832                         }
00833                         
00834                         /* Move to the next bit. */
00835                         b = b << 1;
00836                 }
00837                 
00838                 /* Move to the beginning of the next scanline of the cell. */
00839                 dp += d_add;
00840         }
00841 }
00842 
00851 static void draw_vp_glyph(viewport_t *vport, bool cursor, unsigned int col,
00852     unsigned int row)
00853 {
00854         unsigned int x = vport->x + COL2X(col);
00855         unsigned int y = vport->y + ROW2Y(row);
00856         
00857         uint32_t glyph = vport->backbuf[BB_POS(vport, col, row)].glyph;
00858         uint32_t fg_color = vport->backbuf[BB_POS(vport, col, row)].fg_color;
00859         uint32_t bg_color = vport->backbuf[BB_POS(vport, col, row)].bg_color;
00860         
00861         (*vport->dglyph)(x, y, cursor, screen.glyphs, glyph,
00862             fg_color, bg_color);
00863 }
00864 
00868 static void cursor_hide(viewport_t *vport)
00869 {
00870         if ((vport->cursor_active) && (vport->cursor_shown)) {
00871                 draw_vp_glyph(vport, false, vport->cur_col, vport->cur_row);
00872                 vport->cursor_shown = false;
00873         }
00874 }
00875 
00876 
00880 static void cursor_show(viewport_t *vport)
00881 {
00882         /* Do not check for cursor_shown */
00883         if (vport->cursor_active) {
00884                 draw_vp_glyph(vport, true, vport->cur_col, vport->cur_row);
00885                 vport->cursor_shown = true;
00886         }
00887 }
00888 
00889 
00893 static void cursor_blink(viewport_t *vport)
00894 {
00895         if (vport->cursor_shown)
00896                 cursor_hide(vport);
00897         else
00898                 cursor_show(vport);
00899 }
00900 
00901 
00910 static void draw_char(viewport_t *vport, wchar_t c, unsigned int col, unsigned int row)
00911 {
00912         bb_cell_t *bbp;
00913         
00914         /* Do not hide cursor if we are going to overwrite it */
00915         if ((vport->cursor_active) && (vport->cursor_shown) &&
00916             ((vport->cur_col != col) || (vport->cur_row != row)))
00917                 cursor_hide(vport);
00918         
00919         bbp = &vport->backbuf[BB_POS(vport, col, row)];
00920         bbp->glyph = fb_font_glyph(c);
00921         bbp->fg_color = vport->attr.fg_color;
00922         bbp->bg_color = vport->attr.bg_color;
00923         
00924         draw_vp_glyph(vport, false, col, row);
00925         
00926         vport->cur_col = col;
00927         vport->cur_row = row;
00928         
00929         vport->cur_col++;
00930         if (vport->cur_col >= vport->cols) {
00931                 vport->cur_col = 0;
00932                 vport->cur_row++;
00933                 if (vport->cur_row >= vport->rows)
00934                         vport->cur_row--;
00935         }
00936         
00937         cursor_show(vport);
00938 }
00939 
00950 static void draw_text_data(viewport_t *vport, keyfield_t *data, unsigned int x,
00951     unsigned int y, unsigned int w, unsigned int h)
00952 {
00953         unsigned int i;
00954         unsigned int j;
00955         bb_cell_t *bbp;
00956         attrs_t *a;
00957         
00958         for (j = 0; j < h; j++) {
00959                 for (i = 0; i < w; i++) {
00960                         unsigned int col = x + i;
00961                         unsigned int row = y + j;
00962                         
00963                         bbp = &vport->backbuf[BB_POS(vport, col, row)];
00964                         
00965                         a = &data[j * w + i].attrs;
00966                         
00967                         attr_rgb_t rgb;
00968                         rgb.fg_color = 0;
00969                         rgb.bg_color = 0;
00970                         rgb_from_attr(&rgb, a);
00971                         
00972                         bbp->glyph = fb_font_glyph(data[j * w + i].character);
00973                         bbp->fg_color = rgb.fg_color;
00974                         bbp->bg_color = rgb.bg_color;
00975                         
00976                         draw_vp_glyph(vport, false, col, row);
00977                 }
00978         }
00979         cursor_show(vport);
00980 }
00981 
00982 
00983 static void putpixel_pixmap(void *data, unsigned int x, unsigned int y, uint32_t color)
00984 {
00985         int pm = *((int *) data);
00986         pixmap_t *pmap = &pixmaps[pm];
00987         unsigned int pos = (y * pmap->width + x) * screen.pixelbytes;
00988         
00989         screen.rgb_conv(&pmap->data[pos], color);
00990 }
00991 
00992 
00993 static void putpixel(void *data, unsigned int x, unsigned int y, uint32_t color)
00994 {
00995         viewport_t *vport = (viewport_t *) data;
00996         unsigned int dx = vport->x + x;
00997         unsigned int dy = vport->y + y;
00998         
00999         screen.rgb_conv(&screen.fb_addr[FB_POS(dx, dy)], color);
01000 }
01001 
01002 
01006 static int find_free_pixmap(void)
01007 {
01008         unsigned int i;
01009         
01010         for (i = 0; i < MAX_PIXMAPS; i++)
01011                 if (!pixmaps[i].data)
01012                         return i;
01013         
01014         return -1;
01015 }
01016 
01017 
01021 static int shm2pixmap(unsigned char *shm, size_t size)
01022 {
01023         int pm;
01024         pixmap_t *pmap;
01025         
01026         pm = find_free_pixmap();
01027         if (pm == -1)
01028                 return ELIMIT;
01029         
01030         pmap = &pixmaps[pm];
01031         
01032         if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
01033                 return EINVAL;
01034         
01035         pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
01036         if (!pmap->data)
01037                 return ENOMEM;
01038         
01039         ppm_draw(shm, size, 0, 0, pmap->width, pmap->height, putpixel_pixmap, (void *) &pm);
01040         
01041         return pm;
01042 }
01043 
01044 
01067 static bool shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
01068 {
01069         static keyfield_t *interbuffer = NULL;
01070         static size_t intersize = 0;
01071         
01072         static unsigned char *shm = NULL;
01073         static sysarg_t shm_id = 0;
01074         static size_t shm_size;
01075         
01076         bool handled = true;
01077         int retval = EOK;
01078         viewport_t *vport = &viewports[vp];
01079         unsigned int x;
01080         unsigned int y;
01081         unsigned int w;
01082         unsigned int h;
01083         
01084         switch (IPC_GET_IMETHOD(*call)) {
01085         case IPC_M_SHARE_OUT:
01086                 /* We accept one area for data interchange */
01087                 if (IPC_GET_ARG1(*call) == shm_id) {
01088                         void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
01089                         shm_size = IPC_GET_ARG2(*call);
01090                         if (async_answer_1(callid, EOK, (sysarg_t) dest)) {
01091                                 shm_id = 0;
01092                                 return false;
01093                         }
01094                         shm = dest;
01095                         
01096                         if (shm[0] != 'P')
01097                                 return false;
01098                         
01099                         return true;
01100                 } else {
01101                         intersize = IPC_GET_ARG2(*call);
01102                         receive_comm_area(callid, call, (void *) &interbuffer);
01103                 }
01104                 return true;
01105         case FB_PREPARE_SHM:
01106                 if (shm_id)
01107                         retval = EBUSY;
01108                 else 
01109                         shm_id = IPC_GET_ARG1(*call);
01110                 break;
01111                 
01112         case FB_DROP_SHM:
01113                 if (shm) {
01114                         as_area_destroy(shm);
01115                         shm = NULL;
01116                 }
01117                 shm_id = 0;
01118                 break;
01119                 
01120         case FB_SHM2PIXMAP:
01121                 if (!shm) {
01122                         retval = EINVAL;
01123                         break;
01124                 }
01125                 retval = shm2pixmap(shm, shm_size);
01126                 break;
01127         case FB_DRAW_PPM:
01128                 if (!shm) {
01129                         retval = EINVAL;
01130                         break;
01131                 }
01132                 x = IPC_GET_ARG1(*call);
01133                 y = IPC_GET_ARG2(*call);
01134                 
01135                 if ((x > vport->width) || (y > vport->height)) {
01136                         retval = EINVAL;
01137                         break;
01138                 }
01139                 
01140                 ppm_draw(shm, shm_size, IPC_GET_ARG1(*call),
01141                     IPC_GET_ARG2(*call), vport->width - x, vport->height - y, putpixel, (void *) vport);
01142                 break;
01143         case FB_DRAW_TEXT_DATA:
01144                 x = IPC_GET_ARG1(*call);
01145                 y = IPC_GET_ARG2(*call);
01146                 w = IPC_GET_ARG3(*call);
01147                 h = IPC_GET_ARG4(*call);
01148                 if (!interbuffer) {
01149                         retval = EINVAL;
01150                         break;
01151                 }
01152                 if (x + w > vport->cols || y + h > vport->rows) {
01153                         retval = EINVAL;
01154                         break;
01155                 }
01156                 if (intersize < w * h * sizeof(*interbuffer)) {
01157                         retval = EINVAL;
01158                         break;
01159                 }
01160                 draw_text_data(vport, interbuffer, x, y, w, h);
01161                 break;
01162         default:
01163                 handled = false;
01164         }
01165         
01166         if (handled)
01167                 async_answer_0(callid, retval);
01168         return handled;
01169 }
01170 
01171 
01172 static void copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
01173 {
01174         unsigned int width = vport->width;
01175         unsigned int height = vport->height;
01176         
01177         if (width + vport->x > screen.xres)
01178                 width = screen.xres - vport->x;
01179         if (height + vport->y > screen.yres)
01180                 height = screen.yres - vport->y;
01181         
01182         unsigned int realwidth = pmap->width <= width ? pmap->width : width;
01183         unsigned int realheight = pmap->height <= height ? pmap->height : height;
01184         
01185         unsigned int srcrowsize = vport->width * screen.pixelbytes;
01186         unsigned int realrowsize = realwidth * screen.pixelbytes;
01187         
01188         unsigned int y;
01189         for (y = 0; y < realheight; y++) {
01190                 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
01191                 memcpy(pmap->data + srcrowsize * y, screen.fb_addr + tmp, realrowsize);
01192         }
01193 }
01194 
01195 
01199 static int save_vp_to_pixmap(viewport_t *vport)
01200 {
01201         int pm;
01202         pixmap_t *pmap;
01203         
01204         pm = find_free_pixmap();
01205         if (pm == -1)
01206                 return ELIMIT;
01207         
01208         pmap = &pixmaps[pm];
01209         pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
01210         if (!pmap->data)
01211                 return ENOMEM;
01212         
01213         pmap->width = vport->width;
01214         pmap->height = vport->height;
01215         
01216         copy_vp_to_pixmap(vport, pmap);
01217         
01218         return pm;
01219 }
01220 
01221 
01228 static int draw_pixmap(int vp, int pm)
01229 {
01230         pixmap_t *pmap = &pixmaps[pm];
01231         viewport_t *vport = &viewports[vp];
01232         
01233         unsigned int width = vport->width;
01234         unsigned int height = vport->height;
01235         
01236         if (width + vport->x > screen.xres)
01237                 width = screen.xres - vport->x;
01238         if (height + vport->y > screen.yres)
01239                 height = screen.yres - vport->y;
01240         
01241         if (!pmap->data)
01242                 return EINVAL;
01243         
01244         unsigned int realwidth = pmap->width <= width ? pmap->width : width;
01245         unsigned int realheight = pmap->height <= height ? pmap->height : height;
01246         
01247         unsigned int srcrowsize = vport->width * screen.pixelbytes;
01248         unsigned int realrowsize = realwidth * screen.pixelbytes;
01249         
01250         unsigned int y;
01251         for (y = 0; y < realheight; y++) {
01252                 unsigned int tmp = (vport->y + y) * screen.scanline + vport->x * screen.pixelbytes;
01253                 memcpy(screen.fb_addr + tmp, pmap->data + y * srcrowsize, realrowsize);
01254         }
01255         
01256         return EOK;
01257 }
01258 
01259 
01263 static void anims_tick(void)
01264 {
01265         unsigned int i;
01266         static int counts = 0;
01267         
01268         /* Limit redrawing */
01269         counts = (counts + 1) % 8;
01270         if (counts)
01271                 return;
01272         
01273         for (i = 0; i < MAX_ANIMATIONS; i++) {
01274                 if ((!animations[i].animlen) || (!animations[i].initialized) ||
01275                     (!animations[i].enabled))
01276                         continue;
01277                 
01278                 draw_pixmap(animations[i].vp, animations[i].pixmaps[animations[i].pos]);
01279                 animations[i].pos = (animations[i].pos + 1) % animations[i].animlen;
01280         }
01281 }
01282 
01283 
01284 static unsigned int pointer_x;
01285 static unsigned int pointer_y;
01286 static bool pointer_shown, pointer_enabled;
01287 static int pointer_vport = -1;
01288 static int pointer_pixmap = -1;
01289 
01290 
01291 static void mouse_show(void)
01292 {
01293         int i, j;
01294         int visibility;
01295         int color;
01296         int bytepos;
01297         
01298         if ((pointer_shown) || (!pointer_enabled))
01299                 return;
01300         
01301         /* Save image under the pointer. */
01302         if (pointer_vport == -1) {
01303                 pointer_vport = vport_create(pointer_x, pointer_y, pointer_width, pointer_height);
01304                 if (pointer_vport < 0)
01305                         return;
01306         } else {
01307                 viewports[pointer_vport].x = pointer_x;
01308                 viewports[pointer_vport].y = pointer_y;
01309         }
01310         
01311         if (pointer_pixmap == -1)
01312                 pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
01313         else
01314                 copy_vp_to_pixmap(&viewports[pointer_vport], &pixmaps[pointer_pixmap]);
01315         
01316         /* Draw mouse pointer. */
01317         for (i = 0; i < pointer_height; i++)
01318                 for (j = 0; j < pointer_width; j++) {
01319                         bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
01320                         visibility = pointer_mask_bits[bytepos] &
01321                             (1 << (j % 8));
01322                         if (visibility) {
01323                                 color = pointer_bits[bytepos] &
01324                                     (1 << (j % 8)) ? 0 : 0xffffff;
01325                                 if (pointer_x + j < screen.xres && pointer_y +
01326                                     i < screen.yres)
01327                                         putpixel(&viewports[0], pointer_x + j,
01328                                             pointer_y + i, color);
01329                         }
01330                 }
01331         pointer_shown = 1;
01332 }
01333 
01334 
01335 static void mouse_hide(void)
01336 {
01337         /* Restore image under the pointer. */
01338         if (pointer_shown) {
01339                 draw_pixmap(pointer_vport, pointer_pixmap);
01340                 pointer_shown = 0;
01341         }
01342 }
01343 
01344 
01345 static void mouse_move(unsigned int x, unsigned int y)
01346 {
01347         mouse_hide();
01348         pointer_x = x % screen.xres;
01349         pointer_y = y % screen.yres;
01350         mouse_show();
01351 }
01352 
01353 
01354 static int anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
01355 {
01356         bool handled = true;
01357         int retval = EOK;
01358         int i, nvp;
01359         int newval;
01360         
01361         switch (IPC_GET_IMETHOD(*call)) {
01362         case FB_ANIM_CREATE:
01363                 nvp = IPC_GET_ARG1(*call);
01364                 if (nvp == -1)
01365                         nvp = vp;
01366                 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
01367                         !viewports[nvp].initialized) {
01368                         retval = EINVAL;
01369                         break;
01370                 }
01371                 for (i = 0; i < MAX_ANIMATIONS; i++) {
01372                         if (!animations[i].initialized)
01373                                 break;
01374                 }
01375                 if (i == MAX_ANIMATIONS) {
01376                         retval = ELIMIT;
01377                         break;
01378                 }
01379                 animations[i].initialized = 1;
01380                 animations[i].animlen = 0;
01381                 animations[i].pos = 0;
01382                 animations[i].enabled = 0;
01383                 animations[i].vp = nvp;
01384                 retval = i;
01385                 break;
01386         case FB_ANIM_DROP:
01387                 i = IPC_GET_ARG1(*call);
01388                 if (i >= MAX_ANIMATIONS || i < 0) {
01389                         retval = EINVAL;
01390                         break;
01391                 }
01392                 animations[i].initialized = 0;
01393                 break;
01394         case FB_ANIM_ADDPIXMAP:
01395                 i = IPC_GET_ARG1(*call);
01396                 if (i >= MAX_ANIMATIONS || i < 0 ||
01397                         !animations[i].initialized) {
01398                         retval = EINVAL;
01399                         break;
01400                 }
01401                 if (animations[i].animlen == MAX_ANIM_LEN) {
01402                         retval = ELIMIT;
01403                         break;
01404                 }
01405                 newval = IPC_GET_ARG2(*call);
01406                 if (newval < 0 || newval > MAX_PIXMAPS ||
01407                         !pixmaps[newval].data) {
01408                         retval = EINVAL;
01409                         break;
01410                 }
01411                 animations[i].pixmaps[animations[i].animlen++] = newval;
01412                 break;
01413         case FB_ANIM_CHGVP:
01414                 i = IPC_GET_ARG1(*call);
01415                 if (i >= MAX_ANIMATIONS || i < 0) {
01416                         retval = EINVAL;
01417                         break;
01418                 }
01419                 nvp = IPC_GET_ARG2(*call);
01420                 if (nvp == -1)
01421                         nvp = vp;
01422                 if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
01423                         !viewports[nvp].initialized) {
01424                         retval = EINVAL;
01425                         break;
01426                 }
01427                 animations[i].vp = nvp;
01428                 break;
01429         case FB_ANIM_START:
01430         case FB_ANIM_STOP:
01431                 i = IPC_GET_ARG1(*call);
01432                 if (i >= MAX_ANIMATIONS || i < 0) {
01433                         retval = EINVAL;
01434                         break;
01435                 }
01436                 newval = (IPC_GET_IMETHOD(*call) == FB_ANIM_START);
01437                 if (newval ^ animations[i].enabled) {
01438                         animations[i].enabled = newval;
01439                         anims_enabled += newval ? 1 : -1;
01440                 }
01441                 break;
01442         default:
01443                 handled = 0;
01444         }
01445         if (handled)
01446                 async_answer_0(callid, retval);
01447         return handled;
01448 }
01449 
01450 
01454 static int pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
01455 {
01456         bool handled = true;
01457         int retval = EOK;
01458         int i, nvp;
01459         
01460         switch (IPC_GET_IMETHOD(*call)) {
01461         case FB_VP_DRAW_PIXMAP:
01462                 nvp = IPC_GET_ARG1(*call);
01463                 if (nvp == -1)
01464                         nvp = vp;
01465                 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
01466                         !viewports[nvp].initialized) {
01467                         retval = EINVAL;
01468                         break;
01469                 }
01470                 i = IPC_GET_ARG2(*call);
01471                 retval = draw_pixmap(nvp, i);
01472                 break;
01473         case FB_VP2PIXMAP:
01474                 nvp = IPC_GET_ARG1(*call);
01475                 if (nvp == -1)
01476                         nvp = vp;
01477                 if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
01478                         !viewports[nvp].initialized)
01479                         retval = EINVAL;
01480                 else
01481                         retval = save_vp_to_pixmap(&viewports[nvp]);
01482                 break;
01483         case FB_DROP_PIXMAP:
01484                 i = IPC_GET_ARG1(*call);
01485                 if (i >= MAX_PIXMAPS) {
01486                         retval = EINVAL;
01487                         break;
01488                 }
01489                 if (pixmaps[i].data) {
01490                         free(pixmaps[i].data);
01491                         pixmaps[i].data = NULL;
01492                 }
01493                 break;
01494         default:
01495                 handled = 0;
01496         }
01497         
01498         if (handled)
01499                 async_answer_0(callid, retval);
01500         return handled;
01501         
01502 }
01503 
01504 static int rgb_from_style(attr_rgb_t *rgb, int style)
01505 {
01506         switch (style) {
01507         case STYLE_NORMAL:
01508                 rgb->fg_color = color_table[COLOR_BLACK];
01509                 rgb->bg_color = color_table[COLOR_WHITE];
01510                 break;
01511         case STYLE_EMPHASIS:
01512                 rgb->fg_color = color_table[COLOR_RED];
01513                 rgb->bg_color = color_table[COLOR_WHITE];
01514                 break;
01515         case STYLE_INVERTED:
01516                 rgb->fg_color = color_table[COLOR_WHITE];
01517                 rgb->bg_color = color_table[COLOR_BLACK];
01518                 break;
01519         case STYLE_SELECTED:
01520                 rgb->fg_color = color_table[COLOR_WHITE];
01521                 rgb->bg_color = color_table[COLOR_RED];
01522                 break;
01523         default:
01524                 return EINVAL;
01525         }
01526         
01527         return EOK;
01528 }
01529 
01530 static int rgb_from_idx(attr_rgb_t *rgb, sysarg_t fg_color,
01531     sysarg_t bg_color, sysarg_t flags)
01532 {
01533         fg_color = (fg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
01534         bg_color = (bg_color & 7) | ((flags & CATTR_BRIGHT) ? 8 : 0);
01535 
01536         rgb->fg_color = color_table[fg_color];
01537         rgb->bg_color = color_table[bg_color];
01538 
01539         return EOK;
01540 }
01541 
01542 static int rgb_from_attr(attr_rgb_t *rgb, const attrs_t *a)
01543 {
01544         int rc;
01545 
01546         switch (a->t) {
01547         case at_style:
01548                 rc = rgb_from_style(rgb, a->a.s.style);
01549                 break;
01550         case at_idx:
01551                 rc = rgb_from_idx(rgb, a->a.i.fg_color,
01552                     a->a.i.bg_color, a->a.i.flags);
01553                 break;
01554         case at_rgb:
01555                 *rgb = a->a.r;
01556                 rc = EOK;
01557                 break;
01558         }
01559 
01560         return rc;
01561 }
01562 
01563 static int fb_set_style(viewport_t *vport, sysarg_t style)
01564 {
01565         return rgb_from_style(&vport->attr, (int) style);
01566 }
01567 
01568 static int fb_set_color(viewport_t *vport, sysarg_t fg_color,
01569     sysarg_t bg_color, sysarg_t flags)
01570 {
01571         return rgb_from_idx(&vport->attr, fg_color, bg_color, flags);
01572 }
01573 
01577 static void fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
01578 {
01579         unsigned int vp = 0;
01580         viewport_t *vport = &viewports[vp];
01581         
01582         if (client_connected) {
01583                 async_answer_0(iid, ELIMIT);
01584                 return;
01585         }
01586         
01587         /* Accept connection */
01588         client_connected = true;
01589         async_answer_0(iid, EOK);
01590         
01591         while (true) {
01592                 ipc_callid_t callid;
01593                 ipc_call_t call;
01594                 int retval;
01595                 unsigned int i;
01596                 int scroll;
01597                 wchar_t ch;
01598                 unsigned int col, row;
01599                 
01600                 if ((vport->cursor_active) || (anims_enabled))
01601                         callid = async_get_call_timeout(&call, 250000);
01602                 else
01603                         callid = async_get_call(&call);
01604                 
01605                 mouse_hide();
01606                 if (!callid) {
01607                         cursor_blink(vport);
01608                         anims_tick();
01609                         mouse_show();
01610                         continue;
01611                 }
01612                 
01613                 if (shm_handle(callid, &call, vp))
01614                         continue;
01615                 
01616                 if (pixmap_handle(callid, &call, vp))
01617                         continue;
01618                 
01619                 if (anim_handle(callid, &call, vp))
01620                         continue;
01621                 
01622                 switch (IPC_GET_IMETHOD(call)) {
01623                 case IPC_M_PHONE_HUNGUP:
01624                         client_connected = false;
01625                         
01626                         /* Cleanup other viewports */
01627                         for (i = 1; i < MAX_VIEWPORTS; i++)
01628                                 vport->initialized = false;
01629                         
01630                         /* Exit thread */
01631                         return;
01632                 
01633                 case FB_PUTCHAR:
01634                         ch = IPC_GET_ARG1(call);
01635                         col = IPC_GET_ARG2(call);
01636                         row = IPC_GET_ARG3(call);
01637                         
01638                         if ((col >= vport->cols) || (row >= vport->rows)) {
01639                                 retval = EINVAL;
01640                                 break;
01641                         }
01642                         async_answer_0(callid, EOK);
01643                         
01644                         draw_char(vport, ch, col, row);
01645                         
01646                         /* Message already answered */
01647                         continue;
01648                 case FB_CLEAR:
01649                         vport_clear(vport);
01650                         cursor_show(vport);
01651                         retval = EOK;
01652                         break;
01653                 case FB_CURSOR_GOTO:
01654                         col = IPC_GET_ARG1(call);
01655                         row = IPC_GET_ARG2(call);
01656                         
01657                         if ((col >= vport->cols) || (row >= vport->rows)) {
01658                                 retval = EINVAL;
01659                                 break;
01660                         }
01661                         retval = EOK;
01662                         
01663                         cursor_hide(vport);
01664                         vport->cur_col = col;
01665                         vport->cur_row = row;
01666                         cursor_show(vport);
01667                         break;
01668                 case FB_CURSOR_VISIBILITY:
01669                         cursor_hide(vport);
01670                         vport->cursor_active = IPC_GET_ARG1(call);
01671                         cursor_show(vport);
01672                         retval = EOK;
01673                         break;
01674                 case FB_GET_CSIZE:
01675                         async_answer_2(callid, EOK, vport->cols, vport->rows);
01676                         continue;
01677                 case FB_GET_COLOR_CAP:
01678                         async_answer_1(callid, EOK, FB_CCAP_RGB);
01679                         continue;
01680                 case FB_SCROLL:
01681                         scroll = IPC_GET_ARG1(call);
01682                         if ((scroll > (int) vport->rows) || (scroll < (-(int) vport->rows))) {
01683                                 retval = EINVAL;
01684                                 break;
01685                         }
01686                         cursor_hide(vport);
01687                         vport_scroll(vport, scroll);
01688                         cursor_show(vport);
01689                         retval = EOK;
01690                         break;
01691                 case FB_VIEWPORT_SWITCH:
01692                         i = IPC_GET_ARG1(call);
01693                         if (i >= MAX_VIEWPORTS) {
01694                                 retval = EINVAL;
01695                                 break;
01696                         }
01697                         if (!viewports[i].initialized) {
01698                                 retval = EADDRNOTAVAIL;
01699                                 break;
01700                         }
01701                         cursor_hide(vport);
01702                         vp = i;
01703                         vport = &viewports[vp];
01704                         cursor_show(vport);
01705                         retval = EOK;
01706                         break;
01707                 case FB_VIEWPORT_CREATE:
01708                         retval = vport_create(IPC_GET_ARG1(call) >> 16,
01709                             IPC_GET_ARG1(call) & 0xffff,
01710                             IPC_GET_ARG2(call) >> 16,
01711                             IPC_GET_ARG2(call) & 0xffff);
01712                         break;
01713                 case FB_VIEWPORT_DELETE:
01714                         i = IPC_GET_ARG1(call);
01715                         if (i >= MAX_VIEWPORTS) {
01716                                 retval = EINVAL;
01717                                 break;
01718                         }
01719                         if (!viewports[i].initialized) {
01720                                 retval = EADDRNOTAVAIL;
01721                                 break;
01722                         }
01723                         viewports[i].initialized = false;
01724                         if (viewports[i].bgpixel)
01725                                 free(viewports[i].bgpixel);
01726                         if (viewports[i].backbuf)
01727                                 free(viewports[i].backbuf);
01728                         retval = EOK;
01729                         break;
01730                 case FB_SET_STYLE:
01731                         retval = fb_set_style(vport, IPC_GET_ARG1(call));
01732                         break;
01733                 case FB_SET_COLOR:
01734                         retval = fb_set_color(vport, IPC_GET_ARG1(call),
01735                             IPC_GET_ARG2(call), IPC_GET_ARG3(call));
01736                         break;
01737                 case FB_SET_RGB_COLOR:
01738                         vport->attr.fg_color = IPC_GET_ARG1(call);
01739                         vport->attr.bg_color = IPC_GET_ARG2(call);
01740                         retval = EOK;
01741                         break;
01742                 case FB_GET_RESOLUTION:
01743                         async_answer_2(callid, EOK, screen.xres, screen.yres);
01744                         continue;
01745                 case FB_POINTER_MOVE:
01746                         pointer_enabled = true;
01747                         mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
01748                         retval = EOK;
01749                         break;
01750                 case FB_SCREEN_YIELD:
01751                 case FB_SCREEN_RECLAIM:
01752                         retval = EOK;
01753                         break;
01754                 default:
01755                         retval = ENOENT;
01756                 }
01757                 async_answer_0(callid, retval);
01758         }
01759 }
01760 
01764 int fb_init(void)
01765 {
01766         async_set_client_connection(fb_client_connection);
01767         
01768         sysarg_t fb_ph_addr;
01769         if (sysinfo_get_value("fb.address.physical", &fb_ph_addr) != EOK)
01770                 return -1;
01771         
01772         sysarg_t fb_offset;
01773         if (sysinfo_get_value("fb.offset", &fb_offset) != EOK)
01774                 fb_offset = 0;
01775         
01776         sysarg_t fb_width;
01777         if (sysinfo_get_value("fb.width", &fb_width) != EOK)
01778                 return -1;
01779         
01780         sysarg_t fb_height;
01781         if (sysinfo_get_value("fb.height", &fb_height) != EOK)
01782                 return -1;
01783         
01784         sysarg_t fb_scanline;
01785         if (sysinfo_get_value("fb.scanline", &fb_scanline) != EOK)
01786                 return -1;
01787         
01788         sysarg_t fb_visual;
01789         if (sysinfo_get_value("fb.visual", &fb_visual) != EOK)
01790                 return -1;
01791         
01792         sysarg_t fbsize = fb_scanline * fb_height;
01793         void *fb_addr = as_get_mappable_page(fbsize);
01794         
01795         if (physmem_map((void *) fb_ph_addr + fb_offset, fb_addr,
01796             ALIGN_UP(fbsize, PAGE_SIZE) >> PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE) != 0)
01797                 return -1;
01798         
01799         if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual))
01800                 return 0;
01801         
01802         return -1;
01803 }
01804 

Generated on Thu Jun 2 07:45:49 2011 for HelenOS/USB by  doxygen 1.4.7