Subversion Repositories HelenOS

Rev

Rev 3478 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1363 vana 1
/*
2071 jermar 2
 * Copyright (c) 2006 Jakub Vana
3
 * Copyright (c) 2006 Ondrej Palkovsky
1363 vana 4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 *
10
 * - Redistributions of source code must retain the above copyright
11
 *   notice, this list of conditions and the following disclaimer.
12
 * - Redistributions in binary form must reproduce the above copyright
13
 *   notice, this list of conditions and the following disclaimer in the
14
 *   documentation and/or other materials provided with the distribution.
15
 * - The name of the author may not be used to endorse or promote products
16
 *   derived from this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 */
29
 
1740 jermar 30
/**
31
 * @defgroup fb Graphical framebuffer
32
 * @brief   HelenOS graphical framebuffer.
1649 cejka 33
 * @ingroup fbs
34
 * @{
35
 */
1888 jermar 36
 
1649 cejka 37
/** @file
38
 */
39
 
1430 jermar 40
#include <stdlib.h>
41
#include <unistd.h>
42
#include <string.h>
1363 vana 43
#include <ddi.h>
44
#include <sysinfo.h>
45
#include <align.h>
46
#include <as.h>
47
#include <ipc/fb.h>
48
#include <ipc/ipc.h>
1430 jermar 49
#include <ipc/ns.h>
1363 vana 50
#include <ipc/services.h>
51
#include <kernel/errno.h>
1993 decky 52
#include <kernel/genarch/fb/visuals.h>
1392 palkovsky 53
#include <async.h>
1993 decky 54
#include <bool.h>
1505 palkovsky 55
 
1404 palkovsky 56
#include "font-8x16.h"
1363 vana 57
#include "fb.h"
1505 palkovsky 58
#include "main.h"
59
#include "../console/screenbuffer.h"
1547 palkovsky 60
#include "ppm.h"
1363 vana 61
 
1711 palkovsky 62
#include "pointer.xbm"
63
#include "pointer_mask.xbm"
64
 
1630 palkovsky 65
#define DEFAULT_BGCOLOR                0xf0f0f0
66
#define DEFAULT_FGCOLOR                0x0
1363 vana 67
 
68
/***************************************************************/
69
/* Pixel specific fuctions */
70
 
1555 palkovsky 71
typedef void (*conv2scr_fn_t)(void *, int);
72
typedef int (*conv2rgb_fn_t)(void *);
1363 vana 73
 
1485 palkovsky 74
struct {
1875 jermar 75
    uint8_t *fbaddress;
1363 vana 76
 
1875 jermar 77
    unsigned int xres;
78
    unsigned int yres;
79
    unsigned int scanline;
80
    unsigned int pixelbytes;
81
    unsigned int invert_colors;
1363 vana 82
 
1555 palkovsky 83
    conv2scr_fn_t rgb2scr;
84
    conv2rgb_fn_t scr2rgb;
1485 palkovsky 85
} screen;
1363 vana 86
 
1485 palkovsky 87
typedef struct {
88
    int initialized;
89
    unsigned int x, y;
90
    unsigned int width, height;
1363 vana 91
 
1485 palkovsky 92
    /* Text support in window */
93
    unsigned int rows, cols;
94
    /* Style for text printing */
1509 palkovsky 95
    style_t style;
1485 palkovsky 96
    /* Auto-cursor position */
1486 palkovsky 97
    int cursor_active, cur_col, cur_row;
1500 palkovsky 98
    int cursor_shown;
1672 palkovsky 99
    /* Double buffering */
1781 jermar 100
    uint8_t *dbdata;
1672 palkovsky 101
    unsigned int dboffset;
102
    unsigned int paused;
1485 palkovsky 103
} viewport_t;
1363 vana 104
 
1646 palkovsky 105
#define MAX_ANIM_LEN    8
106
#define MAX_ANIMATIONS  4
107
typedef struct {
108
    int initialized;
109
    int enabled;
110
    unsigned int vp;
111
 
112
    unsigned int pos;
113
    unsigned int animlen;
114
    unsigned int pixmaps[MAX_ANIM_LEN];
115
} animation_t;
116
static animation_t animations[MAX_ANIMATIONS];
117
static int anims_enabled;
118
 
1552 palkovsky 119
/** Maximum number of saved pixmaps
120
 * Pixmap is a saved rectangle
121
 */
122
#define MAX_PIXMAPS        256
123
typedef struct {
124
    unsigned int width;
125
    unsigned int height;
1781 jermar 126
    uint8_t *data;
1552 palkovsky 127
} pixmap_t;
128
static pixmap_t pixmaps[MAX_PIXMAPS];
129
 
130
/* Viewport is a rectangular area on the screen */
1485 palkovsky 131
#define MAX_VIEWPORTS 128
132
static viewport_t viewports[128];
133
 
134
/* Allow only 1 connection */
135
static int client_connected = 0;
136
 
1363 vana 137
#define RED(x, bits)    ((x >> (16 + 8 - bits)) & ((1 << bits) - 1))
138
#define GREEN(x, bits)  ((x >> (8 + 8 - bits)) & ((1 << bits) - 1))
139
#define BLUE(x, bits)   ((x >> (8 - bits)) & ((1 << bits) - 1))
140
 
1485 palkovsky 141
#define COL_WIDTH   8
142
#define ROW_BYTES   (screen.scanline * FONT_SCANLINES)
1363 vana 143
 
1485 palkovsky 144
#define POINTPOS(x, y)  ((y) * screen.scanline + (x) * screen.pixelbytes)
1363 vana 145
 
1875 jermar 146
static inline int COLOR(int color)
147
{
148
    return screen.invert_colors ? ~color : color;
149
}
150
 
1555 palkovsky 151
/* Conversion routines between different color representations */
2070 jermar 152
static void
153
rgb_byte0888(void *dst, int rgb)
1363 vana 154
{
1555 palkovsky 155
    *(int *)dst = rgb;
1363 vana 156
}
157
 
2070 jermar 158
static int
159
byte0888_rgb(void *src)
1363 vana 160
{
1555 palkovsky 161
    return (*(int *)src) & 0xffffff;
1363 vana 162
}
163
 
2070 jermar 164
static void
165
bgr_byte0888(void *dst, int rgb)
1994 decky 166
{
2025 jermar 167
    *((uint32_t *) dst) = BLUE(rgb, 8) << 16 | GREEN(rgb, 8) << 8 |
2619 jermar 168
        RED(rgb, 8);
1994 decky 169
}
170
 
2070 jermar 171
static int
172
byte0888_bgr(void *src)
1994 decky 173
{
174
    int color = *(uint32_t *)(src);
2070 jermar 175
    return ((color & 0xff) << 16) | (((color >> 8) & 0xff) << 8) |
2619 jermar 176
        ((color >> 16) & 0xff);
1994 decky 177
}
178
 
4628 pillai 179
static void bgr_byte8880(void *dst, int rgb)
180
{
181
    uint8_t *scr = (uint8_t *) dst;
182
    scr[3] = RED(rgb, 8);
183
    scr[2] = GREEN(rgb, 8);
184
    scr[1] = BLUE(rgb, 8);
185
}
186
 
187
static int byte8880_bgr(void *src)
188
{
189
    uint8_t *scr = (uint8_t *) src;
190
    return scr[3] << 16 | scr[2] << 8 | scr[1];
191
}
192
 
193
 
2070 jermar 194
static void
195
rgb_byte888(void *dst, int rgb)
1363 vana 196
{
1781 jermar 197
    uint8_t *scr = dst;
1871 jermar 198
#if defined(FB_INVERT_ENDIAN)
1555 palkovsky 199
    scr[0] = RED(rgb, 8);
200
    scr[1] = GREEN(rgb, 8);
201
    scr[2] = BLUE(rgb, 8);
1363 vana 202
#else
1555 palkovsky 203
    scr[2] = RED(rgb, 8);
204
    scr[1] = GREEN(rgb, 8);
205
    scr[0] = BLUE(rgb, 8);
1363 vana 206
#endif
207
}
208
 
2070 jermar 209
static int
210
byte888_rgb(void *src)
1363 vana 211
{
1781 jermar 212
    uint8_t *scr = src;
1871 jermar 213
#if defined(FB_INVERT_ENDIAN)
1555 palkovsky 214
    return scr[0] << 16 | scr[1] << 8 | scr[2];
1363 vana 215
#else
1555 palkovsky 216
    return scr[2] << 16 | scr[1] << 8 | scr[0];
217
#endif  
1363 vana 218
}
219
 
1993 decky 220
/**  16-bit depth (5:5:5) */
2070 jermar 221
static void
222
rgb_byte555(void *dst, int rgb)
1993 decky 223
{
224
    /* 5-bit, 5-bits, 5-bits */
2025 jermar 225
    *((uint16_t *)(dst)) = RED(rgb, 5) << 10 | GREEN(rgb, 5) << 5 |
2619 jermar 226
        BLUE(rgb, 5);
1993 decky 227
}
228
 
229
/** 16-bit depth (5:5:5) */
2070 jermar 230
static int
231
byte555_rgb(void *src)
1993 decky 232
{
233
    int color = *(uint16_t *)(src);
2070 jermar 234
    return (((color >> 10) & 0x1f) << (16 + 3)) |
2619 jermar 235
        (((color >> 5) & 0x1f) << (8 + 3)) | ((color & 0x1f) << 3);
1993 decky 236
}
237
 
1555 palkovsky 238
/**  16-bit depth (5:6:5) */
2070 jermar 239
static void
240
rgb_byte565(void *dst, int rgb)
1363 vana 241
{
242
    /* 5-bit, 6-bits, 5-bits */
2025 jermar 243
    *((uint16_t *)(dst)) = RED(rgb, 5) << 11 | GREEN(rgb, 6) << 5 |
2619 jermar 244
        BLUE(rgb, 5);
1363 vana 245
}
246
 
1555 palkovsky 247
/** 16-bit depth (5:6:5) */
2070 jermar 248
static int
249
byte565_rgb(void *src)
1363 vana 250
{
1781 jermar 251
    int color = *(uint16_t *)(src);
2070 jermar 252
    return (((color >> 11) & 0x1f) << (16 + 3)) |
2619 jermar 253
        (((color >> 5) & 0x3f) << (8 + 2)) | ((color & 0x1f) << 3);
1363 vana 254
}
255
 
256
/** Put pixel - 8-bit depth (3:2:3) */
2070 jermar 257
static void
258
rgb_byte8(void *dst, int rgb)
1363 vana 259
{
1781 jermar 260
    *(uint8_t *)dst = RED(rgb, 3) << 5 | GREEN(rgb, 2) << 3 | BLUE(rgb, 3);
1363 vana 261
}
262
 
263
/** Return pixel color - 8-bit depth (3:2:3) */
2070 jermar 264
static int
265
byte8_rgb(void *src)
1363 vana 266
{
1781 jermar 267
    int color = *(uint8_t *)src;
2070 jermar 268
    return (((color >> 5) & 0x7) << (16 + 5)) |
2619 jermar 269
        (((color >> 3) & 0x3) << (8 + 6)) | ((color & 0x7) << 5);
1363 vana 270
}
271
 
1498 palkovsky 272
/** Put pixel into viewport
273
 *
1709 jermar 274
 * @param vport Viewport identification
1498 palkovsky 275
 * @param x X coord relative to viewport
276
 * @param y Y coord relative to viewport
277
 * @param color RGB color
278
 */
2070 jermar 279
static void
280
putpixel(viewport_t *vport, unsigned int x, unsigned int y, int color)
1485 palkovsky 281
{
1673 palkovsky 282
    int dx = vport->x + x;
283
    int dy = vport->y + y;
1672 palkovsky 284
 
1673 palkovsky 285
    if (! (vport->paused && vport->dbdata))
2070 jermar 286
        (*screen.rgb2scr)(&screen.fbaddress[POINTPOS(dx,dy)],
2619 jermar 287
            COLOR(color));
1672 palkovsky 288
 
1673 palkovsky 289
    if (vport->dbdata) {
290
        int dline = (y + vport->dboffset) % vport->height;
291
        int doffset = screen.pixelbytes * (dline * vport->width + x);
1875 jermar 292
        (*screen.rgb2scr)(&vport->dbdata[doffset], COLOR(color));
1672 palkovsky 293
    }
1485 palkovsky 294
}
1672 palkovsky 295
 
1498 palkovsky 296
/** Get pixel from viewport */
2070 jermar 297
static int
298
getpixel(viewport_t *vport, unsigned int x, unsigned int y)
1485 palkovsky 299
{
1673 palkovsky 300
    int dx = vport->x + x;
301
    int dy = vport->y + y;
1555 palkovsky 302
 
2070 jermar 303
    return COLOR((*screen.scr2rgb)(&screen.fbaddress[POINTPOS(dx, dy)]));
1485 palkovsky 304
}
305
 
2070 jermar 306
static inline void
307
putpixel_mem(char *mem, unsigned int x, unsigned int y, int color)
1363 vana 308
{
2619 jermar 309
    (*screen.rgb2scr)(&mem[POINTPOS(x, y)], COLOR(color));
1363 vana 310
}
311
 
2070 jermar 312
static void
313
draw_rectangle(viewport_t *vport, unsigned int sx, unsigned int sy,
2025 jermar 314
    unsigned int width, unsigned int height, int color)
1559 palkovsky 315
{
316
    unsigned int x, y;
1668 palkovsky 317
    static void *tmpline;
1559 palkovsky 318
 
1668 palkovsky 319
    if (!tmpline)
2619 jermar 320
        tmpline = malloc(screen.scanline * screen.pixelbytes);
1668 palkovsky 321
 
1559 palkovsky 322
    /* Clear first line */
323
    for (x = 0; x < width; x++)
1668 palkovsky 324
        putpixel_mem(tmpline, x, 0, color);
1559 palkovsky 325
 
1673 palkovsky 326
    if (!vport->paused) {
1672 palkovsky 327
        /* Recompute to screen coords */
1673 palkovsky 328
        sx += vport->x;
329
        sy += vport->y;
1672 palkovsky 330
        /* Copy the rest */
331
        for (y = sy;y < sy+height; y++)
332
            memcpy(&screen.fbaddress[POINTPOS(sx,y)], tmpline,
2619 jermar 333
                screen.pixelbytes * width);
1672 palkovsky 334
    }
1673 palkovsky 335
    if (vport->dbdata) {
2025 jermar 336
        for (y = sy; y < sy + height; y++) {
1673 palkovsky 337
            int rline = (y + vport->dboffset) % vport->height;
2025 jermar 338
            int rpos = (rline * vport->width + sx) *
2619 jermar 339
                screen.pixelbytes;
2025 jermar 340
            memcpy(&vport->dbdata[rpos], tmpline,
2619 jermar 341
                screen.pixelbytes * width);
1672 palkovsky 342
        }
343
    }
1559 palkovsky 344
 
345
}
346
 
1485 palkovsky 347
/** Fill viewport with background color */
2070 jermar 348
static void
349
clear_port(viewport_t *vport)
1363 vana 350
{
2025 jermar 351
    draw_rectangle(vport, 0, 0, vport->width, vport->height,
2619 jermar 352
        vport->style.bg_color);
1363 vana 353
}
354
 
1672 palkovsky 355
/** Scroll unbuffered viewport up/down
1485 palkovsky 356
 *
1709 jermar 357
 * @param vport Viewport to scroll
358
 * @param lines Positive number - scroll up, negative - scroll down
1485 palkovsky 359
 */
2070 jermar 360
static void
361
scroll_port_nodb(viewport_t *vport, int lines)
1363 vana 362
{
1485 palkovsky 363
    int y;
1672 palkovsky 364
 
365
    if (lines > 0) {
2025 jermar 366
        for (y = vport->y; y < vport->y+vport->height - lines; y++)
1559 palkovsky 367
            memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
2619 jermar 368
                &screen.fbaddress[POINTPOS(vport->x,y + lines)],
369
                screen.pixelbytes * vport->width);
2025 jermar 370
        draw_rectangle(vport, 0, vport->height - lines, vport->width,
2619 jermar 371
            lines, vport->style.bg_color);
1672 palkovsky 372
    } else if (lines < 0) {
373
        lines = -lines;
2619 jermar 374
        for (y = vport->y + vport->height-1; y >= vport->y + lines; y--)
1559 palkovsky 375
            memcpy(&screen.fbaddress[POINTPOS(vport->x,y)],
2619 jermar 376
                &screen.fbaddress[POINTPOS(vport->x,y - lines)],
377
                screen.pixelbytes * vport->width);
2025 jermar 378
        draw_rectangle(vport, 0, 0, vport->width, lines,
2619 jermar 379
            vport->style.bg_color);
1485 palkovsky 380
    }
1363 vana 381
}
382
 
1672 palkovsky 383
/** Refresh given viewport from double buffer */
2070 jermar 384
static void
385
refresh_viewport_db(viewport_t *vport)
1672 palkovsky 386
{
387
    unsigned int y, srcy, srcoff, dsty, dstx;
388
 
1673 palkovsky 389
    for (y = 0; y < vport->height; y++) {
390
        srcy = (y + vport->dboffset) % vport->height;
391
        srcoff = (vport->width * srcy) * screen.pixelbytes;
1672 palkovsky 392
 
1673 palkovsky 393
        dstx = vport->x;
394
        dsty = vport->y + y;
1672 palkovsky 395
 
396
        memcpy(&screen.fbaddress[POINTPOS(dstx,dsty)],
2619 jermar 397
            &vport->dbdata[srcoff], vport->width * screen.pixelbytes);
1672 palkovsky 398
    }
399
}
400
 
401
/** Scroll viewport that has double buffering enabled */
2070 jermar 402
static void
403
scroll_port_db(viewport_t *vport, int lines)
1672 palkovsky 404
{
1673 palkovsky 405
    ++vport->paused;
1672 palkovsky 406
    if (lines > 0) {
1673 palkovsky 407
        draw_rectangle(vport, 0, 0, vport->width, lines,
2619 jermar 408
            vport->style.bg_color);
1673 palkovsky 409
        vport->dboffset += lines;
410
        vport->dboffset %= vport->height;
1672 palkovsky 411
    } else if (lines < 0) {
412
        lines = -lines;
2619 jermar 413
        draw_rectangle(vport, 0, vport->height-lines, vport->width,
414
            lines, vport->style.bg_color);
1672 palkovsky 415
 
1673 palkovsky 416
        if (vport->dboffset < lines)
417
            vport->dboffset += vport->height;
418
        vport->dboffset -= lines;
1672 palkovsky 419
    }
420
 
1673 palkovsky 421
    --vport->paused;
1672 palkovsky 422
 
1673 palkovsky 423
    refresh_viewport_db(vport);
1672 palkovsky 424
}
425
 
426
/** Scrolls viewport given number of lines */
2070 jermar 427
static void
428
scroll_port(viewport_t *vport, int lines)
1672 palkovsky 429
{
1673 palkovsky 430
    if (vport->dbdata)
431
        scroll_port_db(vport, lines);
1672 palkovsky 432
    else
1673 palkovsky 433
        scroll_port_nodb(vport, lines);
1672 palkovsky 434
 
435
}
436
 
2070 jermar 437
static void
438
invert_pixel(viewport_t *vport, unsigned int x, unsigned int y)
1363 vana 439
{
1673 palkovsky 440
    putpixel(vport, x, y, ~getpixel(vport, x, y));
1363 vana 441
}
442
 
443
 
444
/***************************************************************/
445
/* Character-console functions */
446
 
1558 palkovsky 447
/** Draw character at given position
448
 *
1709 jermar 449
 * @param vport Viewport where the character is printed
1558 palkovsky 450
 * @param sx Coordinates of top-left of the character
451
 * @param sy Coordinates of top-left of the character
452
 * @param style Color of the character
453
 * @param transparent If false, print background color
454
 */
2070 jermar 455
static void
2619 jermar 456
draw_glyph(viewport_t *vport,uint8_t glyph, unsigned int sx, unsigned int sy,
457
    style_t style, int transparent)
1363 vana 458
{
1509 palkovsky 459
    int i;
1363 vana 460
    unsigned int y;
1509 palkovsky 461
    unsigned int glline;
1363 vana 462
 
1509 palkovsky 463
    for (y = 0; y < FONT_SCANLINES; y++) {
464
        glline = fb_font[glyph * FONT_SCANLINES + y];
465
        for (i = 0; i < 8; i++) {
466
            if (glline & (1 << (7 - i)))
2619 jermar 467
                putpixel(vport, sx + i, sy + y, style.fg_color);
1558 palkovsky 468
            else if (!transparent)
2619 jermar 469
                putpixel(vport, sx + i, sy + y, style.bg_color);
1509 palkovsky 470
        }
471
    }
1363 vana 472
}
473
 
474
/** Invert character at given position */
2070 jermar 475
static void
476
invert_char(viewport_t *vport,unsigned int row, unsigned int col)
1363 vana 477
{
478
    unsigned int x;
479
    unsigned int y;
480
 
481
    for (x = 0; x < COL_WIDTH; x++)
482
        for (y = 0; y < FONT_SCANLINES; y++)
2025 jermar 483
            invert_pixel(vport, col * COL_WIDTH + x, row *
2619 jermar 484
                FONT_SCANLINES + y);
1363 vana 485
}
486
 
487
/***************************************************************/
488
/* Stdout specific functions */
489
 
490
 
1485 palkovsky 491
/** Create new viewport
1363 vana 492
 *
1485 palkovsky 493
 * @return New viewport number
1363 vana 494
 */
2070 jermar 495
static int
496
viewport_create(unsigned int x, unsigned int y,unsigned int width,
2025 jermar 497
    unsigned int height)
1363 vana 498
{
1485 palkovsky 499
    int i;
500
 
2070 jermar 501
    for (i = 0; i < MAX_VIEWPORTS; i++) {
1485 palkovsky 502
        if (!viewports[i].initialized)
1363 vana 503
            break;
504
    }
1485 palkovsky 505
    if (i == MAX_VIEWPORTS)
506
        return ELIMIT;
507
 
508
    viewports[i].x = x;
509
    viewports[i].y = y;
510
    viewports[i].width = width;
511
    viewports[i].height = height;
1363 vana 512
 
1485 palkovsky 513
    viewports[i].rows = height / FONT_SCANLINES;
514
    viewports[i].cols = width / COL_WIDTH;
515
 
1509 palkovsky 516
    viewports[i].style.bg_color = DEFAULT_BGCOLOR;
517
    viewports[i].style.fg_color = DEFAULT_FGCOLOR;
1363 vana 518
 
1489 palkovsky 519
    viewports[i].cur_col = 0;
520
    viewports[i].cur_row = 0;
521
    viewports[i].cursor_active = 0;
522
 
1486 palkovsky 523
    viewports[i].initialized = 1;
524
 
1485 palkovsky 525
    return i;
1363 vana 526
}
527
 
528
/** Initialize framebuffer as a chardev output device
529
 *
1993 decky 530
 * @param addr          Address of theframebuffer
531
 * @param xres          Screen width in pixels
532
 * @param yres          Screen height in pixels
533
 * @param visual        Bits per pixel (8, 16, 24, 32)
534
 * @param scan          Bytes per one scanline
1875 jermar 535
 * @param invert_colors Inverted colors.
1363 vana 536
 *
537
 */
2070 jermar 538
static bool
539
screen_init(void *addr, unsigned int xres, unsigned int yres,
2025 jermar 540
    unsigned int scan, unsigned int visual, bool invert_colors)
1363 vana 541
{
1993 decky 542
    switch (visual) {
543
    case VISUAL_INDIRECT_8:
544
        screen.rgb2scr = rgb_byte8;
545
        screen.scr2rgb = byte8_rgb;
1886 jermar 546
        screen.pixelbytes = 1;
547
        break;
1993 decky 548
    case VISUAL_RGB_5_5_5:
549
        screen.rgb2scr = rgb_byte555;
550
        screen.scr2rgb = byte555_rgb;
1886 jermar 551
        screen.pixelbytes = 2;
552
        break;
1993 decky 553
    case VISUAL_RGB_5_6_5:
554
        screen.rgb2scr = rgb_byte565;
555
        screen.scr2rgb = byte565_rgb;
556
        screen.pixelbytes = 2;
1886 jermar 557
        break;
1993 decky 558
    case VISUAL_RGB_8_8_8:
559
        screen.rgb2scr = rgb_byte888;
560
        screen.scr2rgb = byte888_rgb;
561
        screen.pixelbytes = 3;
562
        break;
563
    case VISUAL_RGB_8_8_8_0:
564
        screen.rgb2scr = rgb_byte888;
565
        screen.scr2rgb = byte888_rgb;
1886 jermar 566
        screen.pixelbytes = 4;
567
        break;
1993 decky 568
    case VISUAL_RGB_0_8_8_8:
569
        screen.rgb2scr = rgb_byte0888;
570
        screen.scr2rgb = byte0888_rgb;
571
        screen.pixelbytes = 4;
572
        break;
1994 decky 573
    case VISUAL_BGR_0_8_8_8:
574
        screen.rgb2scr = bgr_byte0888;
575
        screen.scr2rgb = byte0888_bgr;
576
        screen.pixelbytes = 4;
577
        break;
4628 pillai 578
    case VISUAL_BGR_8_8_8_0:
579
        screen.rgb2scr = bgr_byte8880;
580
        screen.scr2rgb = byte8880_bgr;
581
        screen.pixelbytes = 4;
582
        break;
1993 decky 583
    default:
584
        return false;
1363 vana 585
    }
586
 
1485 palkovsky 587
    screen.fbaddress = (unsigned char *) addr;
588
    screen.xres = xres;
589
    screen.yres = yres;
590
    screen.scanline = scan;
1875 jermar 591
    screen.invert_colors = invert_colors;
1363 vana 592
 
1485 palkovsky 593
    /* Create first viewport */
1993 decky 594
    viewport_create(0, 0, xres, yres);
595
 
596
    return true;
1485 palkovsky 597
}
1363 vana 598
 
1552 palkovsky 599
/** Hide cursor if it is shown */
2070 jermar 600
static void
601
cursor_hide(viewport_t *vport)
1500 palkovsky 602
{
603
    if (vport->cursor_active && vport->cursor_shown) {
1673 palkovsky 604
        invert_char(vport, vport->cur_row, vport->cur_col);
1500 palkovsky 605
        vport->cursor_shown = 0;
606
    }
607
}
608
 
1552 palkovsky 609
/** Show cursor if cursor showing is enabled */
2070 jermar 610
static void
611
cursor_print(viewport_t *vport)
1500 palkovsky 612
{
613
    /* Do not check for cursor_shown */
614
    if (vport->cursor_active) {
1673 palkovsky 615
        invert_char(vport, vport->cur_row, vport->cur_col);
1500 palkovsky 616
        vport->cursor_shown = 1;
617
    }
618
}
619
 
1552 palkovsky 620
/** Invert cursor, if it is enabled */
2070 jermar 621
static void
622
cursor_blink(viewport_t *vport)
1500 palkovsky 623
{
624
    if (vport->cursor_shown)
1673 palkovsky 625
        cursor_hide(vport);
1500 palkovsky 626
    else
1673 palkovsky 627
        cursor_print(vport);
1500 palkovsky 628
}
629
 
1498 palkovsky 630
/** Draw character at given position relative to viewport
631
 *
1709 jermar 632
 * @param vport Viewport identification
1498 palkovsky 633
 * @param c Character to print
634
 * @param row Screen position relative to viewport
635
 * @param col Screen position relative to viewport
1558 palkovsky 636
 * @param transparent If false, print background color with character
1498 palkovsky 637
 */
2070 jermar 638
static void
639
draw_char(viewport_t *vport, char c, unsigned int row, unsigned int col,
640
    style_t style, int transparent)
1486 palkovsky 641
{
1500 palkovsky 642
    /* Optimize - do not hide cursor if we are going to overwrite it */
643
    if (vport->cursor_active && vport->cursor_shown &&
644
        (vport->cur_col != col || vport->cur_row != row))
1673 palkovsky 645
        invert_char(vport, vport->cur_row, vport->cur_col);
1486 palkovsky 646
 
2025 jermar 647
    draw_glyph(vport, c, col * COL_WIDTH, row * FONT_SCANLINES, style,
2619 jermar 648
        transparent);
1489 palkovsky 649
 
650
    vport->cur_col = col;
651
    vport->cur_row = row;
652
 
653
    vport->cur_col++;
2025 jermar 654
    if (vport->cur_col >= vport->cols) {
1489 palkovsky 655
        vport->cur_col = 0;
656
        vport->cur_row++;
657
        if (vport->cur_row >= vport->rows)
658
            vport->cur_row--;
1486 palkovsky 659
    }
1673 palkovsky 660
    cursor_print(vport);
1486 palkovsky 661
}
662
 
1552 palkovsky 663
/** Draw text data to viewport
664
 *
1709 jermar 665
 * @param vport Viewport id
1552 palkovsky 666
 * @param data Text data fitting exactly into viewport
667
 */
2070 jermar 668
static void
669
draw_text_data(viewport_t *vport, keyfield_t *data)
1505 palkovsky 670
{
671
    int i;
1515 palkovsky 672
    int col,row;
1505 palkovsky 673
 
1673 palkovsky 674
    clear_port(vport);
2025 jermar 675
    for (i = 0; i < vport->cols * vport->rows; i++) {
676
        if (data[i].character == ' ' && style_same(data[i].style,
2619 jermar 677
            vport->style))
1505 palkovsky 678
            continue;
1515 palkovsky 679
        col = i % vport->cols;
680
        row = i / vport->cols;
2025 jermar 681
        draw_glyph(vport, data[i].character, col * COL_WIDTH, row *
2619 jermar 682
            FONT_SCANLINES, data[i].style, style_same(data[i].style,
683
            vport->style));
1505 palkovsky 684
    }
1673 palkovsky 685
    cursor_print(vport);
1505 palkovsky 686
}
687
 
1555 palkovsky 688
/** Return first free pixmap */
2070 jermar 689
static int
690
find_free_pixmap(void)
1555 palkovsky 691
{
692
    int i;
693
 
2070 jermar 694
    for (i = 0;i < MAX_PIXMAPS;i++)
1555 palkovsky 695
        if (!pixmaps[i].data)
696
            return i;
697
    return -1;
698
}
699
 
2070 jermar 700
static void
701
putpixel_pixmap(int pm, unsigned int x, unsigned int y, int color)
1555 palkovsky 702
{
703
    pixmap_t *pmap = &pixmaps[pm];
704
    int pos = (y * pmap->width + x) * screen.pixelbytes;
705
 
1875 jermar 706
    (*screen.rgb2scr)(&pmap->data[pos],COLOR(color));
1555 palkovsky 707
}
708
 
709
/** Create a new pixmap and return appropriate ID */
2070 jermar 710
static int
711
shm2pixmap(unsigned char *shm, size_t size)
1555 palkovsky 712
{
713
    int pm;
714
    pixmap_t *pmap;
715
 
716
    pm = find_free_pixmap();
717
    if (pm == -1)
718
        return ELIMIT;
719
    pmap = &pixmaps[pm];
720
 
721
    if (ppm_get_data(shm, size, &pmap->width, &pmap->height))
722
        return EINVAL;
723
 
724
    pmap->data = malloc(pmap->width * pmap->height * screen.pixelbytes);
725
    if (!pmap->data)
726
        return ENOMEM;
727
 
728
    ppm_draw(shm, size, 0, 0, pmap->width, pmap->height,
2619 jermar 729
        (putpixel_cb_t)putpixel_pixmap, (void *)pm);
1555 palkovsky 730
 
731
    return pm;
732
}
733
 
1552 palkovsky 734
/** Handle shared memory communication calls
735
 *
736
 * Protocol for drawing pixmaps:
737
 * - FB_PREPARE_SHM(client shm identification)
2025 jermar 738
 * - IPC_M_AS_AREA_SEND
1552 palkovsky 739
 * - FB_DRAW_PPM(startx,starty)
740
 * - FB_DROP_SHM
741
 *
742
 * Protocol for text drawing
2025 jermar 743
 * - IPC_M_AS_AREA_SEND
1552 palkovsky 744
 * - FB_DRAW_TEXT_DATA
745
 *
746
 * @param callid Callid of the current call
747
 * @param call Current call data
748
 * @param vp Active viewport
749
 * @return 0 if the call was not handled byt this function, 1 otherwise
750
 *
751
 * note: this function is not threads safe, you would have
752
 * to redefine static variables with __thread
753
 */
2070 jermar 754
static int
755
shm_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1547 palkovsky 756
{
757
    static keyfield_t *interbuffer = NULL;
758
    static size_t intersize = 0;
1505 palkovsky 759
 
1720 palkovsky 760
    static unsigned char *shm = NULL;
1555 palkovsky 761
    static ipcarg_t shm_id = 0;
762
    static size_t shm_size;
1547 palkovsky 763
 
764
    int handled = 1;
765
    int retval = 0;
766
    viewport_t *vport = &viewports[vp];
2070 jermar 767
    unsigned int x, y;
1547 palkovsky 768
 
769
    switch (IPC_GET_METHOD(*call)) {
2677 jermar 770
    case IPC_M_SHARE_OUT:
1547 palkovsky 771
        /* We accept one area for data interchange */
1555 palkovsky 772
        if (IPC_GET_ARG1(*call) == shm_id) {
2141 jermar 773
            void *dest = as_get_mappable_page(IPC_GET_ARG2(*call));
1555 palkovsky 774
            shm_size = IPC_GET_ARG2(*call);
2619 jermar 775
            if (!ipc_answer_1(callid, EOK, (sysarg_t) dest))
1555 palkovsky 776
                shm = dest;
1547 palkovsky 777
            else
1555 palkovsky 778
                shm_id = 0;
779
            if (shm[0] != 'P')
1547 palkovsky 780
                while (1)
781
                    ;
782
            return 1;
783
        } else {
784
            intersize = IPC_GET_ARG2(*call);
2015 jermar 785
            receive_comm_area(callid, call, (void *) &interbuffer);
1547 palkovsky 786
        }
787
        return 1;
788
    case FB_PREPARE_SHM:
1555 palkovsky 789
        if (shm_id)
1547 palkovsky 790
            retval = EBUSY;
791
        else
1555 palkovsky 792
            shm_id = IPC_GET_ARG1(*call);
1547 palkovsky 793
        break;
794
 
795
    case FB_DROP_SHM:
1555 palkovsky 796
        if (shm) {
797
            as_area_destroy(shm);
798
            shm = NULL;
1547 palkovsky 799
        }
1555 palkovsky 800
        shm_id = 0;
1547 palkovsky 801
        break;
1555 palkovsky 802
 
803
    case FB_SHM2PIXMAP:
804
        if (!shm) {
805
            retval = EINVAL;
806
            break;
807
        }
808
        retval = shm2pixmap(shm, shm_size);
809
        break;
1547 palkovsky 810
    case FB_DRAW_PPM:
1555 palkovsky 811
        if (!shm) {
1547 palkovsky 812
            retval = EINVAL;
813
            break;
814
        }
815
        x = IPC_GET_ARG1(*call);
816
        y = IPC_GET_ARG2(*call);
817
        if (x > vport->width || y > vport->height) {
818
            retval = EINVAL;
819
            break;
820
        }
821
 
2025 jermar 822
        ppm_draw(shm, shm_size, IPC_GET_ARG1(*call),
2619 jermar 823
            IPC_GET_ARG2(*call), vport->width - x, vport->height - y,
824
            (putpixel_cb_t)putpixel, vport);
1547 palkovsky 825
        break;
826
    case FB_DRAW_TEXT_DATA:
827
        if (!interbuffer) {
828
            retval = EINVAL;
829
            break;
830
        }
2025 jermar 831
        if (intersize < vport->cols * vport->rows *
2619 jermar 832
            sizeof(*interbuffer)) {
1547 palkovsky 833
            retval = EINVAL;
834
            break;
835
        }
1673 palkovsky 836
        draw_text_data(vport, interbuffer);
1547 palkovsky 837
        break;
838
    default:
839
        handled = 0;
840
    }
841
 
842
    if (handled)
2619 jermar 843
        ipc_answer_0(callid, retval);
1547 palkovsky 844
    return handled;
845
}
846
 
2070 jermar 847
static void
848
copy_vp_to_pixmap(viewport_t *vport, pixmap_t *pmap)
1552 palkovsky 849
{
1720 palkovsky 850
    int y;
2301 decky 851
    int tmp, srcrowsize;
852
    int realwidth, realheight, realrowsize;
1711 palkovsky 853
    int width = vport->width;
854
    int height = vport->height;
1552 palkovsky 855
 
1711 palkovsky 856
    if (width + vport->x > screen.xres)
857
        width = screen.xres - vport->x;
2301 decky 858
    if (height + vport->y > screen.yres)
1711 palkovsky 859
        height = screen.yres - vport->y;
2301 decky 860
 
861
    realwidth = pmap->width <= width ? pmap->width : width;
862
    realheight = pmap->height <= height ? pmap->height : height;
1711 palkovsky 863
 
2301 decky 864
    srcrowsize = vport->width * screen.pixelbytes;
865
    realrowsize = realwidth * screen.pixelbytes;
866
 
867
    for (y = 0; y < realheight; y++) {
2070 jermar 868
        tmp = (vport->y + y) * screen.scanline +
2619 jermar 869
            vport->x * screen.pixelbytes;
2301 decky 870
        memcpy(pmap->data + srcrowsize * y, screen.fbaddress + tmp,
2619 jermar 871
            realrowsize);
1711 palkovsky 872
    }
873
}
874
 
875
/** Save viewport to pixmap */
2070 jermar 876
static int
877
save_vp_to_pixmap(viewport_t *vport)
1711 palkovsky 878
{
879
    int pm;
880
    pixmap_t *pmap;
881
 
1552 palkovsky 882
    pm = find_free_pixmap();
883
    if (pm == -1)
884
        return ELIMIT;
885
 
886
    pmap = &pixmaps[pm];
887
    pmap->data = malloc(screen.pixelbytes * vport->width * vport->height);
888
    if (!pmap->data)
889
        return ENOMEM;
890
 
891
    pmap->width = vport->width;
892
    pmap->height = vport->height;
1711 palkovsky 893
 
894
    copy_vp_to_pixmap(vport, pmap);
1552 palkovsky 895
 
896
    return pm;
897
}
898
 
899
/** Draw pixmap on screen
900
 *
901
 * @param vp Viewport to draw on
902
 * @param pm Pixmap identifier
903
 */
904
static int draw_pixmap(int vp, int pm)
905
{
906
    pixmap_t *pmap = &pixmaps[pm];
907
    viewport_t *vport = &viewports[vp];
1720 palkovsky 908
    int y;
1552 palkovsky 909
    int tmp, srcrowsize;
910
    int realwidth, realheight, realrowsize;
1711 palkovsky 911
    int width = vport->width;
912
    int height = vport->height;
1552 palkovsky 913
 
1711 palkovsky 914
    if (width + vport->x > screen.xres)
915
        width = screen.xres - vport->x;
916
    if (height + vport->y > screen.yres)
917
        height = screen.yres - vport->y;
918
 
1552 palkovsky 919
    if (!pmap->data)
920
        return EINVAL;
921
 
1711 palkovsky 922
    realwidth = pmap->width <= width ? pmap->width : width;
923
    realheight = pmap->height <= height ? pmap->height : height;
1552 palkovsky 924
 
925
    srcrowsize = vport->width * screen.pixelbytes;
926
    realrowsize = realwidth * screen.pixelbytes;
927
 
2070 jermar 928
    for (y = 0; y < realheight; y++) {
929
        tmp = (vport->y + y) * screen.scanline +
2619 jermar 930
            vport->x * screen.pixelbytes;
2025 jermar 931
        memcpy(screen.fbaddress + tmp, pmap->data + y * srcrowsize,
2619 jermar 932
            realrowsize);
1552 palkovsky 933
    }
1567 palkovsky 934
    return 0;
1552 palkovsky 935
}
936
 
1646 palkovsky 937
/** Tick animation one step forward */
2070 jermar 938
static void
939
anims_tick(void)
1646 palkovsky 940
{
941
    int i;
942
    static int counts = 0;
943
 
944
    /* Limit redrawing */
2025 jermar 945
    counts = (counts + 1) % 8;
1646 palkovsky 946
    if (counts)
947
        return;
948
 
2070 jermar 949
    for (i = 0; i < MAX_ANIMATIONS; i++) {
2025 jermar 950
        if (!animations[i].animlen || !animations[i].initialized ||
2619 jermar 951
            !animations[i].enabled)
1646 palkovsky 952
            continue;
2025 jermar 953
        draw_pixmap(animations[i].vp,
2619 jermar 954
            animations[i].pixmaps[animations[i].pos]);
2025 jermar 955
        animations[i].pos = (animations[i].pos + 1) %
2619 jermar 956
            animations[i].animlen;
1646 palkovsky 957
    }
958
}
959
 
1711 palkovsky 960
 
961
static int pointer_x, pointer_y;
1723 palkovsky 962
static int pointer_shown, pointer_enabled;
1711 palkovsky 963
static int pointer_vport = -1;
964
static int pointer_pixmap = -1;
965
 
2070 jermar 966
static void
967
mouse_show(void)
1711 palkovsky 968
{
2070 jermar 969
    int i, j;
1711 palkovsky 970
    int visibility;
971
    int color;
972
    int bytepos;
973
 
1723 palkovsky 974
    if (pointer_shown || !pointer_enabled)
975
        return;
976
 
1711 palkovsky 977
    /* Save image under the cursor */
978
    if (pointer_vport == -1) {
2025 jermar 979
        pointer_vport = viewport_create(pointer_x, pointer_y,
2619 jermar 980
            pointer_width, pointer_height);
1711 palkovsky 981
        if (pointer_vport < 0)
982
            return;
983
    } else {
984
        viewports[pointer_vport].x = pointer_x;
985
        viewports[pointer_vport].y = pointer_y;
986
    }
987
 
988
    if (pointer_pixmap == -1)
989
        pointer_pixmap = save_vp_to_pixmap(&viewports[pointer_vport]);
990
    else
2025 jermar 991
        copy_vp_to_pixmap(&viewports[pointer_vport],
2619 jermar 992
            &pixmaps[pointer_pixmap]);
1711 palkovsky 993
 
994
    /* Draw cursor */
2025 jermar 995
    for (i = 0; i < pointer_height; i++)
996
        for (j = 0; j < pointer_width; j++) {
997
            bytepos = i * ((pointer_width - 1) / 8 + 1) + j / 8;
2070 jermar 998
            visibility = pointer_mask_bits[bytepos] &
2619 jermar 999
                (1 << (j % 8));
1711 palkovsky 1000
            if (visibility) {
2619 jermar 1001
                color = pointer_bits[bytepos] &
1002
                    (1 << (j % 8)) ? 0 : 0xffffff;
2025 jermar 1003
                if (pointer_x + j < screen.xres && pointer_y +
2619 jermar 1004
                    i < screen.yres)
2025 jermar 1005
                    putpixel(&viewports[0], pointer_x + j,
2619 jermar 1006
                        pointer_y + i, color);
1711 palkovsky 1007
            }
1008
        }
1009
    pointer_shown = 1;
1010
}
1011
 
2070 jermar 1012
static void
1013
mouse_hide(void)
1711 palkovsky 1014
{
1015
    /* Restore image under the cursor */
1016
    if (pointer_shown) {
1017
        draw_pixmap(pointer_vport, pointer_pixmap);
1018
        pointer_shown = 0;
1019
    }
1020
}
1021
 
2070 jermar 1022
static void
1023
mouse_move(unsigned int x, unsigned int y)
1711 palkovsky 1024
{
1025
    mouse_hide();
1026
    pointer_x = x;
1027
    pointer_y = y;
1028
    mouse_show();
1029
}
1030
 
2070 jermar 1031
static int
1032
anim_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1646 palkovsky 1033
{
1034
    int handled = 1;
1035
    int retval = 0;
1036
    int i,nvp;
1037
    int newval;
1038
 
1039
    switch (IPC_GET_METHOD(*call)) {
1040
    case FB_ANIM_CREATE:
1041
        nvp = IPC_GET_ARG1(*call);
1042
        if (nvp == -1)
1043
            nvp = vp;
2025 jermar 1044
        if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1045
            !viewports[nvp].initialized) {
1646 palkovsky 1046
            retval = EINVAL;
1047
            break;
1048
        }
2025 jermar 1049
        for (i = 0; i < MAX_ANIMATIONS; i++) {
1050
            if (!animations[i].initialized)
1646 palkovsky 1051
                break;
1052
        }
1053
        if (i == MAX_ANIMATIONS) {
1054
            retval = ELIMIT;
1055
            break;
1056
        }
1057
        animations[i].initialized = 1;
1058
        animations[i].animlen = 0;
1059
        animations[i].pos = 0;
1060
        animations[i].enabled = 0;
1061
        animations[i].vp = nvp;
1062
        retval = i;
1063
        break;
1064
    case FB_ANIM_DROP:
1065
        i = IPC_GET_ARG1(*call);
1720 palkovsky 1066
        if (i >= MAX_ANIMATIONS || i < 0) {
1646 palkovsky 1067
            retval = EINVAL;
1068
            break;
1069
        }
1070
        animations[i].initialized = 0;
1071
        break;
1072
    case FB_ANIM_ADDPIXMAP:
1073
        i = IPC_GET_ARG1(*call);
2025 jermar 1074
        if (i >= MAX_ANIMATIONS || i < 0 ||
1075
            !animations[i].initialized) {
1646 palkovsky 1076
            retval = EINVAL;
1077
            break;
1078
        }
1079
        if (animations[i].animlen == MAX_ANIM_LEN) {
1080
            retval = ELIMIT;
1081
            break;
1082
        }
1083
        newval = IPC_GET_ARG2(*call);
2025 jermar 1084
        if (newval < 0 || newval > MAX_PIXMAPS ||
1085
            !pixmaps[newval].data) {
1646 palkovsky 1086
            retval = EINVAL;
1087
            break;
1088
        }
1089
        animations[i].pixmaps[animations[i].animlen++] = newval;
1090
        break;
1091
    case FB_ANIM_CHGVP:
1092
        i = IPC_GET_ARG1(*call);
1093
        if (i >= MAX_ANIMATIONS || i < 0) {
1094
            retval = EINVAL;
1095
            break;
1096
        }
1097
        nvp = IPC_GET_ARG2(*call);
1098
        if (nvp == -1)
1099
            nvp = vp;
2025 jermar 1100
        if (nvp >= MAX_VIEWPORTS || nvp < 0 ||
1101
            !viewports[nvp].initialized) {
1646 palkovsky 1102
            retval = EINVAL;
1103
            break;
1104
        }
1105
        animations[i].vp = nvp;
1106
        break;
1107
    case FB_ANIM_START:
1108
    case FB_ANIM_STOP:
1109
        i = IPC_GET_ARG1(*call);
1110
        if (i >= MAX_ANIMATIONS || i < 0) {
1111
            retval = EINVAL;
1112
            break;
1113
        }
1114
        newval = (IPC_GET_METHOD(*call) == FB_ANIM_START);
1115
        if (newval ^ animations[i].enabled) {
1116
            animations[i].enabled = newval;
1117
            anims_enabled += newval ? 1 : -1;
1118
        }
1119
        break;
1120
    default:
1121
        handled = 0;
1122
    }
1123
    if (handled)
2619 jermar 1124
        ipc_answer_0(callid, retval);
1646 palkovsky 1125
    return handled;
1126
}
1127
 
1552 palkovsky 1128
/** Handler for messages concerning pixmap handling */
2070 jermar 1129
static int
1130
pixmap_handle(ipc_callid_t callid, ipc_call_t *call, int vp)
1552 palkovsky 1131
{
1132
    int handled = 1;
1133
    int retval = 0;
1134
    int i,nvp;
1135
 
1136
    switch (IPC_GET_METHOD(*call)) {
1137
    case FB_VP_DRAW_PIXMAP:
1138
        nvp = IPC_GET_ARG1(*call);
1139
        if (nvp == -1)
1140
            nvp = vp;
2025 jermar 1141
        if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1142
            !viewports[nvp].initialized) {
1552 palkovsky 1143
            retval = EINVAL;
1144
            break;
1145
        }
1146
        i = IPC_GET_ARG2(*call);
1147
        retval = draw_pixmap(nvp, i);
1148
        break;
1149
    case FB_VP2PIXMAP:
1150
        nvp = IPC_GET_ARG1(*call);
1151
        if (nvp == -1)
1152
            nvp = vp;
2025 jermar 1153
        if (nvp < 0 || nvp >= MAX_VIEWPORTS ||
1154
            !viewports[nvp].initialized)
1552 palkovsky 1155
            retval = EINVAL;
1156
        else
1711 palkovsky 1157
            retval = save_vp_to_pixmap(&viewports[nvp]);
1552 palkovsky 1158
        break;
1159
    case FB_DROP_PIXMAP:
1160
        i = IPC_GET_ARG1(*call);
1161
        if (i >= MAX_PIXMAPS) {
1162
            retval = EINVAL;
1163
            break;
1164
        }
1165
        if (pixmaps[i].data) {
1166
            free(pixmaps[i].data);
1167
            pixmaps[i].data = NULL;
1168
        }
1169
        break;
1170
    default:
1171
        handled = 0;
1172
    }
1173
 
1174
    if (handled)
2619 jermar 1175
        ipc_answer_0(callid, retval);
1552 palkovsky 1176
    return handled;
1177
 
1178
}
1179
 
1498 palkovsky 1180
/** Function for handling connections to FB
1181
 *
1182
 */
2070 jermar 1183
static void
1184
fb_client_connection(ipc_callid_t iid, ipc_call_t *icall)
1363 vana 1185
{
1485 palkovsky 1186
    ipc_callid_t callid;
1187
    ipc_call_t call;
1188
    int retval;
1189
    int i;
1190
    unsigned int row,col;
1191
    char c;
1486 palkovsky 1192
 
1485 palkovsky 1193
    int vp = 0;
1486 palkovsky 1194
    viewport_t *vport = &viewports[0];
1363 vana 1195
 
1485 palkovsky 1196
    if (client_connected) {
2619 jermar 1197
        ipc_answer_0(iid, ELIMIT);
1485 palkovsky 1198
        return;
1199
    }
1486 palkovsky 1200
    client_connected = 1;
2619 jermar 1201
    ipc_answer_0(iid, EOK); /* Accept connection */
1363 vana 1202
 
1485 palkovsky 1203
    while (1) {
1646 palkovsky 1204
        if (vport->cursor_active || anims_enabled)
2070 jermar 1205
            callid = async_get_call_timeout(&call, 250000);
1640 palkovsky 1206
        else
1207
            callid = async_get_call(&call);
1208
 
1713 palkovsky 1209
        mouse_hide();
1500 palkovsky 1210
        if (!callid) {
1673 palkovsky 1211
            cursor_blink(vport);
1646 palkovsky 1212
            anims_tick();
1723 palkovsky 1213
            mouse_show();
1500 palkovsky 1214
            continue;
1215
        }
1547 palkovsky 1216
        if (shm_handle(callid, &call, vp))
1217
            continue;
1552 palkovsky 1218
        if (pixmap_handle(callid, &call, vp))
1219
            continue;
1646 palkovsky 1220
        if (anim_handle(callid, &call, vp))
1221
            continue;
1547 palkovsky 1222
 
1485 palkovsky 1223
        switch (IPC_GET_METHOD(call)) {
1224
        case IPC_M_PHONE_HUNGUP:
1225
            client_connected = 0;
1226
            /* cleanup other viewports */
2025 jermar 1227
            for (i = 1; i < MAX_VIEWPORTS; i++)
1486 palkovsky 1228
                vport->initialized = 0;
1485 palkovsky 1229
            return; /* Exit thread */
1505 palkovsky 1230
 
1485 palkovsky 1231
        case FB_PUTCHAR:
1558 palkovsky 1232
        case FB_TRANS_PUTCHAR:
1485 palkovsky 1233
            c = IPC_GET_ARG1(call);
1234
            row = IPC_GET_ARG2(call);
1235
            col = IPC_GET_ARG3(call);
1486 palkovsky 1236
            if (row >= vport->rows || col >= vport->cols) {
1485 palkovsky 1237
                retval = EINVAL;
1238
                break;
1239
            }
2619 jermar 1240
            ipc_answer_0(callid, EOK);
1486 palkovsky 1241
 
2025 jermar 1242
            draw_char(vport, c, row, col, vport->style,
2619 jermar 1243
                IPC_GET_METHOD(call) == FB_TRANS_PUTCHAR);
1485 palkovsky 1244
            continue; /* msg already answered */
1245
        case FB_CLEAR:
1673 palkovsky 1246
            clear_port(vport);
1247
            cursor_print(vport);
1485 palkovsky 1248
            retval = 0;
1249
            break;
1486 palkovsky 1250
        case FB_CURSOR_GOTO:
1251
            row = IPC_GET_ARG1(call);
1252
            col = IPC_GET_ARG2(call);
1253
            if (row >= vport->rows || col >= vport->cols) {
1254
                retval = EINVAL;
1255
                break;
1256
            }
1257
            retval = 0;
1673 palkovsky 1258
            cursor_hide(vport);
1486 palkovsky 1259
            vport->cur_col = col;
1260
            vport->cur_row = row;
1673 palkovsky 1261
            cursor_print(vport);
1486 palkovsky 1262
            break;
1263
        case FB_CURSOR_VISIBILITY:
1673 palkovsky 1264
            cursor_hide(vport);
1500 palkovsky 1265
            vport->cursor_active = IPC_GET_ARG1(call);
1673 palkovsky 1266
            cursor_print(vport);
1486 palkovsky 1267
            retval = 0;
1268
            break;
1485 palkovsky 1269
        case FB_GET_CSIZE:
2619 jermar 1270
            ipc_answer_2(callid, EOK, vport->rows, vport->cols);
1485 palkovsky 1271
            continue;
1486 palkovsky 1272
        case FB_SCROLL:
1273
            i = IPC_GET_ARG1(call);
1274
            if (i > vport->rows || i < (- (int)vport->rows)) {
1275
                retval = EINVAL;
1276
                break;
1277
            }
1673 palkovsky 1278
            cursor_hide(vport);
1279
            scroll_port(vport, i*FONT_SCANLINES);
1280
            cursor_print(vport);
1486 palkovsky 1281
            retval = 0;
1282
            break;
1672 palkovsky 1283
        case FB_VIEWPORT_DB:
1284
            /* Enable double buffering */
1285
            i = IPC_GET_ARG1(call);
1286
            if (i == -1)
1287
                i = vp;
1288
            if (i < 0 || i >= MAX_VIEWPORTS) {
1289
                retval = EINVAL;
1290
                break;
1291
            }
2619 jermar 1292
            if (!viewports[i].initialized ) {
1672 palkovsky 1293
                retval = EADDRNOTAVAIL;
1294
                break;
1295
            }
1296
            viewports[i].dboffset = 0;
1297
            if (IPC_GET_ARG2(call) == 1 && !viewports[i].dbdata)
2619 jermar 1298
                viewports[i].dbdata =
1299
                    malloc(screen.pixelbytes *
1300
                    viewports[i].width * viewports[i].height);
2025 jermar 1301
            else if (IPC_GET_ARG2(call) == 0 &&
2619 jermar 1302
                viewports[i].dbdata) {
1672 palkovsky 1303
                free(viewports[i].dbdata);
1304
                viewports[i].dbdata = NULL;
1305
            }
1306
            retval = 0;
1307
            break;
1486 palkovsky 1308
        case FB_VIEWPORT_SWITCH:
1309
            i = IPC_GET_ARG1(call);
1310
            if (i < 0 || i >= MAX_VIEWPORTS) {
1311
                retval = EINVAL;
1312
                break;
1313
            }
1314
            if (! viewports[i].initialized ) {
1315
                retval = EADDRNOTAVAIL;
1316
                break;
1317
            }
1673 palkovsky 1318
            cursor_hide(vport);
1486 palkovsky 1319
            vp = i;
1320
            vport = &viewports[vp];
1673 palkovsky 1321
            cursor_print(vport);
1486 palkovsky 1322
            retval = 0;
1323
            break;
1324
        case FB_VIEWPORT_CREATE:
1325
            retval = viewport_create(IPC_GET_ARG1(call) >> 16,
2619 jermar 1326
                IPC_GET_ARG1(call) & 0xffff,
1327
                IPC_GET_ARG2(call) >> 16,
1328
                IPC_GET_ARG2(call) & 0xffff);
1486 palkovsky 1329
            break;
1330
        case FB_VIEWPORT_DELETE:
1331
            i = IPC_GET_ARG1(call);
1332
            if (i < 0 || i >= MAX_VIEWPORTS) {
1333
                retval = EINVAL;
1334
                break;
1335
            }
1336
            if (! viewports[i].initialized ) {
1337
                retval = EADDRNOTAVAIL;
1338
                break;
1339
            }
1340
            viewports[i].initialized = 0;
1672 palkovsky 1341
            if (viewports[i].dbdata) {
1342
                free(viewports[i].dbdata);
1343
                viewports[i].dbdata = NULL;
1344
            }
1486 palkovsky 1345
            retval = 0;
1346
            break;
1347
        case FB_SET_STYLE:
1509 palkovsky 1348
            vport->style.fg_color = IPC_GET_ARG1(call);
1349
            vport->style.bg_color = IPC_GET_ARG2(call);
1486 palkovsky 1350
            retval = 0;
1351
            break;
1352
        case FB_GET_RESOLUTION:
2619 jermar 1353
            ipc_answer_2(callid, EOK, screen.xres, screen.yres);
1486 palkovsky 1354
            continue;
1707 palkovsky 1355
        case FB_POINTER_MOVE:
1723 palkovsky 1356
            pointer_enabled = 1;
1711 palkovsky 1357
            mouse_move(IPC_GET_ARG1(call), IPC_GET_ARG2(call));
1720 palkovsky 1358
            retval = 0;
1707 palkovsky 1359
            break;
1485 palkovsky 1360
        default:
1361
            retval = ENOENT;
1362
        }
2619 jermar 1363
        ipc_answer_0(callid, retval);
1363 vana 1364
    }
1485 palkovsky 1365
}
1363 vana 1366
 
1498 palkovsky 1367
/** Initialization of framebuffer */
2070 jermar 1368
int
1369
fb_init(void)
1485 palkovsky 1370
{
1501 palkovsky 1371
    void *fb_ph_addr;
1490 palkovsky 1372
    unsigned int fb_width;
1373
    unsigned int fb_height;
1374
    unsigned int fb_scanline;
1993 decky 1375
    unsigned int fb_visual;
1376
    bool fb_invert_colors;
1501 palkovsky 1377
    void *fb_addr;
1378
    size_t asz;
1363 vana 1379
 
1490 palkovsky 1380
    async_set_client_connection(fb_client_connection);
1363 vana 1381
 
1886 jermar 1382
    fb_ph_addr = (void *) sysinfo_value("fb.address.physical");
1383
    fb_width = sysinfo_value("fb.width");
1384
    fb_height = sysinfo_value("fb.height");
1385
    fb_scanline = sysinfo_value("fb.scanline");
1993 decky 1386
    fb_visual = sysinfo_value("fb.visual");
1886 jermar 1387
    fb_invert_colors = sysinfo_value("fb.invert-colors");
1490 palkovsky 1388
 
1993 decky 1389
    asz = fb_scanline * fb_height;
2141 jermar 1390
    fb_addr = as_get_mappable_page(asz);
1485 palkovsky 1391
 
2025 jermar 1392
    physmem_map(fb_ph_addr, fb_addr, ALIGN_UP(asz, PAGE_SIZE) >>
2619 jermar 1393
        PAGE_WIDTH, AS_AREA_READ | AS_AREA_WRITE);
1886 jermar 1394
 
2015 jermar 1395
    if (screen_init(fb_addr, fb_width, fb_height, fb_scanline, fb_visual,
2619 jermar 1396
        fb_invert_colors))
1993 decky 1397
        return 0;
1398
 
1399
    return -1;
1363 vana 1400
}
1490 palkovsky 1401
 
1649 cejka 1402
/**
1403
 * @}
1404
 */