Subversion Repositories HelenOS

Rev

Rev 4439 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4419 trochtova 1
/*
2
 * Copyright (c) 2006 Ondrej Palkovsky
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 * - Redistributions of source code must retain the above copyright
10
 *   notice, this list of conditions and the following disclaimer.
11
 * - Redistributions in binary form must reproduce the above copyright
12
 *   notice, this list of conditions and the following disclaimer in the
13
 *   documentation and/or other materials provided with the distribution.
14
 * - The name of the author may not be used to endorse or promote products
15
 *   derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 */
28
 
29
/** @addtogroup console
4439 trochtova 30
 * @{
4419 trochtova 31
 */
32
/** @file
33
 */
34
 
35
#include <ipc/fb.h>
36
#include <ipc/ipc.h>
37
#include <async.h>
38
#include <stdio.h>
39
#include <sys/mman.h>
40
#include <string.h>
41
#include <align.h>
4537 trochtova 42
#include <bool.h>
4419 trochtova 43
 
44
#include "console.h"
45
#include "gcons.h"
46
 
4439 trochtova 47
#define CONSOLE_TOP     66
48
#define CONSOLE_MARGIN  6
4419 trochtova 49
 
4439 trochtova 50
#define STATUS_START   110
51
#define STATUS_TOP     8
52
#define STATUS_SPACE   4
53
#define STATUS_WIDTH   48
54
#define STATUS_HEIGHT  48
4419 trochtova 55
 
4439 trochtova 56
#define MAIN_COLOR  0xffffff
4419 trochtova 57
 
4537 trochtova 58
static bool use_gcons = false;
59
static ipcarg_t xres;
60
static ipcarg_t yres;
4419 trochtova 61
 
62
enum butstate {
63
    CONS_DISCONNECTED = 0,
64
    CONS_SELECTED,
65
    CONS_IDLE,
66
    CONS_HAS_DATA,
67
    CONS_KERNEL,
68
    CONS_DISCONNECTED_SEL,
69
    CONS_LAST
70
};
71
 
72
static int console_vp;
73
static int cstatus_vp[CONSOLE_COUNT];
74
static enum butstate console_state[CONSOLE_COUNT];
75
 
76
static int fbphone;
77
 
78
/** List of pixmaps identifying these icons */
79
static int ic_pixmaps[CONS_LAST] = {-1, -1, -1, -1, -1, -1};
80
static int animation = -1;
81
 
4537 trochtova 82
static size_t active_console = 0;
4419 trochtova 83
 
4537 trochtova 84
size_t mouse_x;
85
size_t mouse_y;
86
 
87
bool btn_pressed;
88
size_t btn_x;
89
size_t btn_y;
90
 
4419 trochtova 91
static void vp_switch(int vp)
92
{
93
    async_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp);
94
}
95
 
96
/** Create view port */
4537 trochtova 97
static int vp_create(size_t x, size_t y, size_t width, size_t height)
4419 trochtova 98
{
99
    return async_req_2_0(fbphone, FB_VIEWPORT_CREATE, (x << 16) | y,
100
        (width << 16) | height);
101
}
102
 
103
static void clear(void)
104
{
105
    async_msg_0(fbphone, FB_CLEAR);
106
}
107
 
4537 trochtova 108
static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
4419 trochtova 109
{
110
    async_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
111
}
112
 
113
/** Transparent putchar */
4537 trochtova 114
static void tran_putch(wchar_t ch, size_t col, size_t row)
4419 trochtova 115
{
4537 trochtova 116
    async_msg_3(fbphone, FB_PUTCHAR, ch, col, row);
4419 trochtova 117
}
118
 
119
/** Redraw the button showing state of a given console */
4537 trochtova 120
static void redraw_state(size_t index)
4419 trochtova 121
{
4537 trochtova 122
    vp_switch(cstatus_vp[index]);
4439 trochtova 123
 
4537 trochtova 124
    enum butstate state = console_state[index];
125
 
4419 trochtova 126
    if (ic_pixmaps[state] != -1)
4537 trochtova 127
        async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index],
4419 trochtova 128
            ic_pixmaps[state]);
4439 trochtova 129
 
4537 trochtova 130
    if ((state != CONS_DISCONNECTED) && (state != CONS_KERNEL)
131
        && (state != CONS_DISCONNECTED_SEL)) {
132
 
133
        char data[5];
134
        snprintf(data, 5, "%u", index + 1);
135
 
136
        size_t i;
137
        for (i = 0; data[i] != 0; i++)
138
            tran_putch(data[i], 2 + i, 1);
4439 trochtova 139
    }
4419 trochtova 140
}
141
 
142
/** Notification run on changing console (except kernel console) */
4537 trochtova 143
void gcons_change_console(size_t index)
4419 trochtova 144
{
145
    if (!use_gcons)
146
        return;
4439 trochtova 147
 
4419 trochtova 148
    if (active_console == KERNEL_CONSOLE) {
4537 trochtova 149
        size_t i;
150
 
4419 trochtova 151
        for (i = 0; i < CONSOLE_COUNT; i++)
152
            redraw_state(i);
4537 trochtova 153
 
4419 trochtova 154
        if (animation != -1)
155
            async_msg_1(fbphone, FB_ANIM_START, animation);
156
    } else {
157
        if (console_state[active_console] == CONS_DISCONNECTED_SEL)
158
            console_state[active_console] = CONS_DISCONNECTED;
159
        else
160
            console_state[active_console] = CONS_IDLE;
4537 trochtova 161
 
4419 trochtova 162
        redraw_state(active_console);
163
    }
4439 trochtova 164
 
4537 trochtova 165
    active_console = index;
4439 trochtova 166
 
4537 trochtova 167
    if ((console_state[index] == CONS_DISCONNECTED)
168
        || (console_state[index] == CONS_DISCONNECTED_SEL))
169
        console_state[index] = CONS_DISCONNECTED_SEL;
170
    else
171
        console_state[index] = CONS_SELECTED;
172
 
173
    redraw_state(index);
4419 trochtova 174
    vp_switch(console_vp);
175
}
176
 
177
/** Notification function that gets called on new output to virtual console */
4537 trochtova 178
void gcons_notify_char(size_t index)
4419 trochtova 179
{
180
    if (!use_gcons)
181
        return;
4439 trochtova 182
 
4537 trochtova 183
    if ((index == active_console)
184
        || (console_state[index] == CONS_HAS_DATA))
4419 trochtova 185
        return;
4439 trochtova 186
 
4537 trochtova 187
    console_state[index] = CONS_HAS_DATA;
4439 trochtova 188
 
4419 trochtova 189
    if (active_console == KERNEL_CONSOLE)
190
        return;
4439 trochtova 191
 
4537 trochtova 192
    redraw_state(index);
4419 trochtova 193
    vp_switch(console_vp);
194
}
195
 
196
/** Notification function called on service disconnect from console */
4537 trochtova 197
void gcons_notify_disconnect(size_t index)
4419 trochtova 198
{
199
    if (!use_gcons)
200
        return;
4439 trochtova 201
 
4537 trochtova 202
    if (index == active_console)
203
        console_state[index] = CONS_DISCONNECTED_SEL;
4419 trochtova 204
    else
4537 trochtova 205
        console_state[index] = CONS_DISCONNECTED;
4419 trochtova 206
 
207
    if (active_console == KERNEL_CONSOLE)
208
        return;
209
 
4537 trochtova 210
    redraw_state(index);
4419 trochtova 211
    vp_switch(console_vp);
212
}
213
 
214
/** Notification function called on console connect */
4537 trochtova 215
void gcons_notify_connect(size_t index)
4419 trochtova 216
{
217
    if (!use_gcons)
218
        return;
4439 trochtova 219
 
4537 trochtova 220
    if (index == active_console)
221
        console_state[index] = CONS_SELECTED;
4419 trochtova 222
    else
4537 trochtova 223
        console_state[index] = CONS_IDLE;
4439 trochtova 224
 
4419 trochtova 225
    if (active_console == KERNEL_CONSOLE)
226
        return;
4439 trochtova 227
 
4537 trochtova 228
    redraw_state(index);
4419 trochtova 229
    vp_switch(console_vp);
230
}
231
 
232
/** Change to kernel console */
233
void gcons_in_kernel(void)
234
{
235
    if (animation != -1)
236
        async_msg_1(fbphone, FB_ANIM_STOP, animation);
237
 
238
    active_console = KERNEL_CONSOLE;
239
    vp_switch(0);
240
}
241
 
4537 trochtova 242
/** Return x, where left <= x <= right && |a-x| == min(|a-x|) is smallest */
243
static inline int limit(size_t a, size_t left, size_t right)
4419 trochtova 244
{
245
    if (a < left)
246
        a = left;
4537 trochtova 247
 
4419 trochtova 248
    if (a >= right)
249
        a = right - 1;
4537 trochtova 250
 
4419 trochtova 251
    return a;
252
}
253
 
254
/** Handle mouse move
255
 *
256
 * @param dx Delta X of mouse move
257
 * @param dy Delta Y of mouse move
258
 */
4537 trochtova 259
void gcons_mouse_move(ssize_t dx, ssize_t dy)
4419 trochtova 260
{
261
    mouse_x = limit(mouse_x + dx, 0, xres);
262
    mouse_y = limit(mouse_y + dy, 0, yres);
4439 trochtova 263
 
4419 trochtova 264
    async_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y);
265
}
266
 
267
static int gcons_find_conbut(int x, int y)
268
{
269
    int status_start = STATUS_START + (xres - 800) / 2;
4439 trochtova 270
 
271
    if ((y < STATUS_TOP) || (y >= STATUS_TOP + STATUS_HEIGHT))
4419 trochtova 272
        return -1;
273
 
274
    if (x < status_start)
275
        return -1;
276
 
277
    if (x >= status_start + (STATUS_WIDTH + STATUS_SPACE) * CONSOLE_COUNT)
278
        return -1;
279
    if (((x - status_start) % (STATUS_WIDTH + STATUS_SPACE)) < STATUS_SPACE)
280
        return -1;
281
 
282
    return (x - status_start) / (STATUS_WIDTH + STATUS_SPACE);
283
}
284
 
285
/** Handle mouse click
286
 *
4537 trochtova 287
 * @param state New state (true - pressed, false - depressed)
4419 trochtova 288
 */
4537 trochtova 289
int gcons_mouse_btn(bool state)
4419 trochtova 290
{
291
    int conbut;
4439 trochtova 292
 
4419 trochtova 293
    if (state) {
294
        conbut = gcons_find_conbut(mouse_x, mouse_y);
295
        if (conbut != -1) {
4537 trochtova 296
            btn_pressed = true;
4419 trochtova 297
            btn_x = mouse_x;
298
            btn_y = mouse_y;
299
        }
300
        return -1;
4439 trochtova 301
    }
302
 
303
    if ((!state) && (!btn_pressed))
4419 trochtova 304
        return -1;
4439 trochtova 305
 
4537 trochtova 306
    btn_pressed = false;
4439 trochtova 307
 
4419 trochtova 308
    conbut = gcons_find_conbut(mouse_x, mouse_y);
309
    if (conbut == gcons_find_conbut(btn_x, btn_y))
310
        return conbut;
4439 trochtova 311
 
4419 trochtova 312
    return -1;
313
}
314
 
315
 
316
/** Draw a PPM pixmap to framebuffer
317
 *
318
 * @param logo Pointer to PPM data
319
 * @param size Size of PPM data
320
 * @param x Coordinate of upper left corner
321
 * @param y Coordinate of upper left corner
322
 */
323
static void draw_pixmap(char *logo, size_t size, int x, int y)
324
{
325
    char *shm;
326
    int rc;
4439 trochtova 327
 
4419 trochtova 328
    /* Create area */
329
    shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
330
        MAP_ANONYMOUS, 0, 0);
331
    if (shm == MAP_FAILED)
332
        return;
4439 trochtova 333
 
4419 trochtova 334
    memcpy(shm, logo, size);
4439 trochtova 335
 
4419 trochtova 336
    /* Send area */
337
    rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (ipcarg_t) shm);
338
    if (rc)
339
        goto exit;
4439 trochtova 340
 
4419 trochtova 341
    rc = ipc_share_out_start(fbphone, shm, PROTO_READ);
342
    if (rc)
343
        goto drop;
4439 trochtova 344
 
4419 trochtova 345
    /* Draw logo */
346
    async_msg_2(fbphone, FB_DRAW_PPM, x, y);
4439 trochtova 347
 
4419 trochtova 348
drop:
349
    /* Drop area */
350
    async_msg_0(fbphone, FB_DROP_SHM);
4439 trochtova 351
 
352
exit:
4419 trochtova 353
    /* Remove area */
354
    munmap(shm, size);
355
}
356
 
4439 trochtova 357
extern char _binary_gfx_helenos_ppm_start[0];
358
extern int _binary_gfx_helenos_ppm_size;
359
extern char _binary_gfx_nameic_ppm_start[0];
360
extern int _binary_gfx_nameic_ppm_size;
4419 trochtova 361
 
362
/** Redraws console graphics */
363
void gcons_redraw_console(void)
364
{
365
    int i;
366
 
367
    if (!use_gcons)
368
        return;
369
 
370
    vp_switch(0);
371
    set_rgb_color(MAIN_COLOR, MAIN_COLOR);
372
    clear();
4439 trochtova 373
    draw_pixmap(_binary_gfx_helenos_ppm_start,
374
        (size_t) &_binary_gfx_helenos_ppm_size, xres - 66, 2);
375
    draw_pixmap(_binary_gfx_nameic_ppm_start,
376
        (size_t) &_binary_gfx_nameic_ppm_size, 5, 17);
4419 trochtova 377
 
378
    for (i = 0; i < CONSOLE_COUNT; i++)
379
        redraw_state(i);
4439 trochtova 380
 
4419 trochtova 381
    vp_switch(console_vp);
382
}
383
 
384
/** Creates a pixmap on framebuffer
385
 *
386
 * @param data PPM data
387
 * @param size PPM data size
4537 trochtova 388
 *
4419 trochtova 389
 * @return Pixmap identification
4537 trochtova 390
 *
4419 trochtova 391
 */
4537 trochtova 392
static int make_pixmap(char *data, size_t size)
4419 trochtova 393
{
394
    char *shm;
395
    int rc;
396
    int pxid = -1;
4439 trochtova 397
 
4419 trochtova 398
    /* Create area */
399
    shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
400
        MAP_ANONYMOUS, 0, 0);
401
    if (shm == MAP_FAILED)
402
        return -1;
4439 trochtova 403
 
4419 trochtova 404
    memcpy(shm, data, size);
4439 trochtova 405
 
4419 trochtova 406
    /* Send area */
407
    rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (ipcarg_t) shm);
408
    if (rc)
409
        goto exit;
4439 trochtova 410
 
4419 trochtova 411
    rc = ipc_share_out_start(fbphone, shm, PROTO_READ);
412
    if (rc)
413
        goto drop;
4439 trochtova 414
 
4419 trochtova 415
    /* Obtain pixmap */
416
    rc = async_req_0_0(fbphone, FB_SHM2PIXMAP);
417
    if (rc < 0)
418
        goto drop;
4439 trochtova 419
 
4419 trochtova 420
    pxid = rc;
4439 trochtova 421
 
4419 trochtova 422
drop:
423
    /* Drop area */
424
    async_msg_0(fbphone, FB_DROP_SHM);
4439 trochtova 425
 
426
exit:
4419 trochtova 427
    /* Remove area */
428
    munmap(shm, size);
4439 trochtova 429
 
4419 trochtova 430
    return pxid;
431
}
432
 
4439 trochtova 433
extern char _binary_gfx_anim_1_ppm_start[0];
434
extern int _binary_gfx_anim_1_ppm_size;
435
extern char _binary_gfx_anim_2_ppm_start[0];
436
extern int _binary_gfx_anim_2_ppm_size;
437
extern char _binary_gfx_anim_3_ppm_start[0];
438
extern int _binary_gfx_anim_3_ppm_size;
439
extern char _binary_gfx_anim_4_ppm_start[0];
440
extern int _binary_gfx_anim_4_ppm_size;
4419 trochtova 441
 
442
static void make_anim(void)
443
{
4439 trochtova 444
    int an = async_req_1_0(fbphone, FB_ANIM_CREATE, cstatus_vp[KERNEL_CONSOLE]);
4419 trochtova 445
    if (an < 0)
446
        return;
4439 trochtova 447
 
448
    int pm = make_pixmap(_binary_gfx_anim_1_ppm_start,
449
        (int) &_binary_gfx_anim_1_ppm_size);
4419 trochtova 450
    async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
4439 trochtova 451
 
452
    pm = make_pixmap(_binary_gfx_anim_2_ppm_start,
453
        (int) &_binary_gfx_anim_2_ppm_size);
4419 trochtova 454
    async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
4439 trochtova 455
 
456
    pm = make_pixmap(_binary_gfx_anim_3_ppm_start,
457
        (int) &_binary_gfx_anim_3_ppm_size);
4419 trochtova 458
    async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
4439 trochtova 459
 
460
    pm = make_pixmap(_binary_gfx_anim_4_ppm_start,
461
        (int) &_binary_gfx_anim_4_ppm_size);
4419 trochtova 462
    async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
4439 trochtova 463
 
4419 trochtova 464
    async_msg_1(fbphone, FB_ANIM_START, an);
4439 trochtova 465
 
4419 trochtova 466
    animation = an;
467
}
468
 
4439 trochtova 469
extern char _binary_gfx_cons_selected_ppm_start[0];
470
extern int _binary_gfx_cons_selected_ppm_size;
471
extern char _binary_gfx_cons_idle_ppm_start[0];
472
extern int _binary_gfx_cons_idle_ppm_size;
473
extern char _binary_gfx_cons_has_data_ppm_start[0];
474
extern int _binary_gfx_cons_has_data_ppm_size;
475
extern char _binary_gfx_cons_kernel_ppm_start[0];
476
extern int _binary_gfx_cons_kernel_ppm_size;
4419 trochtova 477
 
478
/** Initialize nice graphical console environment */
479
void gcons_init(int phone)
480
{
481
    fbphone = phone;
482
 
4537 trochtova 483
    int rc = async_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres);
4419 trochtova 484
    if (rc)
485
        return;
486
 
487
    if ((xres < 800) || (yres < 600))
488
        return;
489
 
4439 trochtova 490
    /* Create console viewport */
491
 
4419 trochtova 492
    /* Align width & height to character size */
493
    console_vp = vp_create(CONSOLE_MARGIN, CONSOLE_TOP,
494
        ALIGN_DOWN(xres - 2 * CONSOLE_MARGIN, 8),
495
        ALIGN_DOWN(yres - (CONSOLE_TOP + CONSOLE_MARGIN), 16));
4537 trochtova 496
 
4419 trochtova 497
    if (console_vp < 0)
498
        return;
499
 
500
    /* Create status buttons */
4537 trochtova 501
    size_t status_start = STATUS_START + (xres - 800) / 2;
502
    size_t i;
4419 trochtova 503
    for (i = 0; i < CONSOLE_COUNT; i++) {
504
        cstatus_vp[i] = vp_create(status_start + CONSOLE_MARGIN +
505
            i * (STATUS_WIDTH + STATUS_SPACE), STATUS_TOP,
506
            STATUS_WIDTH, STATUS_HEIGHT);
4537 trochtova 507
 
4419 trochtova 508
        if (cstatus_vp[i] < 0)
509
            return;
4537 trochtova 510
 
4419 trochtova 511
        vp_switch(cstatus_vp[i]);
512
        set_rgb_color(0x202020, 0xffffff);
513
    }
514
 
515
    /* Initialize icons */
516
    ic_pixmaps[CONS_SELECTED] =
4439 trochtova 517
        make_pixmap(_binary_gfx_cons_selected_ppm_start,
4537 trochtova 518
        (size_t) &_binary_gfx_cons_selected_ppm_size);
4439 trochtova 519
    ic_pixmaps[CONS_IDLE] =
520
        make_pixmap(_binary_gfx_cons_idle_ppm_start,
4537 trochtova 521
        (size_t) &_binary_gfx_cons_idle_ppm_size);
4419 trochtova 522
    ic_pixmaps[CONS_HAS_DATA] =
4439 trochtova 523
        make_pixmap(_binary_gfx_cons_has_data_ppm_start,
4537 trochtova 524
        (size_t) &_binary_gfx_cons_has_data_ppm_size);
4419 trochtova 525
    ic_pixmaps[CONS_DISCONNECTED] =
4439 trochtova 526
        make_pixmap(_binary_gfx_cons_idle_ppm_start,
4537 trochtova 527
        (size_t) &_binary_gfx_cons_idle_ppm_size);
4439 trochtova 528
    ic_pixmaps[CONS_KERNEL] =
529
        make_pixmap(_binary_gfx_cons_kernel_ppm_start,
4537 trochtova 530
        (size_t) &_binary_gfx_cons_kernel_ppm_size);
4419 trochtova 531
    ic_pixmaps[CONS_DISCONNECTED_SEL] = ic_pixmaps[CONS_SELECTED];
532
 
533
    make_anim();
534
 
4537 trochtova 535
    use_gcons = true;
4419 trochtova 536
    console_state[0] = CONS_DISCONNECTED_SEL;
537
    console_state[KERNEL_CONSOLE] = CONS_KERNEL;
4537 trochtova 538
 
539
    vp_switch(console_vp);
4419 trochtova 540
}
541
 
542
/** @}
543
 */