gcons.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2006 Ondrej Palkovsky
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00035 #include <ipc/fb.h>
00036 #include <async.h>
00037 #include <stdio.h>
00038 #include <sys/mman.h>
00039 #include <str.h>
00040 #include <align.h>
00041 #include <bool.h>
00042 
00043 #include "console.h"
00044 #include "gcons.h"
00045 
00046 #define CONSOLE_TOP     66
00047 #define CONSOLE_MARGIN  6
00048 
00049 #define STATUS_START   110
00050 #define STATUS_TOP     8
00051 #define STATUS_SPACE   4
00052 #define STATUS_WIDTH   48
00053 #define STATUS_HEIGHT  48
00054 
00055 #define COLOR_MAIN        0xffffff
00056 #define COLOR_FOREGROUND  0x202020
00057 #define COLOR_BACKGROUND  0xffffff
00058 
00059 extern char _binary_gfx_helenos_ppm_start[0];
00060 extern int _binary_gfx_helenos_ppm_size;
00061 extern char _binary_gfx_nameic_ppm_start[0];
00062 extern int _binary_gfx_nameic_ppm_size;
00063 
00064 extern char _binary_gfx_anim_1_ppm_start[0];
00065 extern int _binary_gfx_anim_1_ppm_size;
00066 extern char _binary_gfx_anim_2_ppm_start[0];
00067 extern int _binary_gfx_anim_2_ppm_size;
00068 extern char _binary_gfx_anim_3_ppm_start[0];
00069 extern int _binary_gfx_anim_3_ppm_size;
00070 extern char _binary_gfx_anim_4_ppm_start[0];
00071 extern int _binary_gfx_anim_4_ppm_size;
00072 
00073 extern char _binary_gfx_cons_selected_ppm_start[0];
00074 extern int _binary_gfx_cons_selected_ppm_size;
00075 extern char _binary_gfx_cons_idle_ppm_start[0];
00076 extern int _binary_gfx_cons_idle_ppm_size;
00077 extern char _binary_gfx_cons_has_data_ppm_start[0];
00078 extern int _binary_gfx_cons_has_data_ppm_size;
00079 extern char _binary_gfx_cons_kernel_ppm_start[0];
00080 extern int _binary_gfx_cons_kernel_ppm_size;
00081 
00082 static bool use_gcons = false;
00083 static sysarg_t xres;
00084 static sysarg_t yres;
00085 
00086 enum butstate {
00087         CONS_DISCONNECTED = 0,
00088         CONS_SELECTED,
00089         CONS_IDLE,
00090         CONS_HAS_DATA,
00091         CONS_KERNEL,
00092         CONS_DISCONNECTED_SEL,
00093         CONS_LAST
00094 };
00095 
00096 static int console_vp;
00097 static int cstatus_vp[CONSOLE_COUNT];
00098 static enum butstate console_state[CONSOLE_COUNT];
00099 
00100 static int fbphone;
00101 
00103 static int ic_pixmaps[CONS_LAST] = {-1, -1, -1, -1, -1, -1};
00104 static int animation = -1;
00105 
00106 static size_t active_console = 0;
00107 
00108 static sysarg_t mouse_x = 0;
00109 static sysarg_t mouse_y= 0;
00110 
00111 static bool btn_pressed = false;
00112 static sysarg_t btn_x = 0;
00113 static sysarg_t btn_y = 0;
00114 
00115 static void vp_switch(int vp)
00116 {
00117         async_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp);
00118 }
00119 
00121 static int vp_create(sysarg_t x, sysarg_t y, sysarg_t width, sysarg_t height)
00122 {
00123         return async_req_2_0(fbphone, FB_VIEWPORT_CREATE, (x << 16) | y,
00124             (width << 16) | height);
00125 }
00126 
00127 static void clear(void)
00128 {
00129         async_msg_0(fbphone, FB_CLEAR);
00130 }
00131 
00132 static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
00133 {
00134         async_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
00135 }
00136 
00138 static void tran_putch(wchar_t ch, sysarg_t col, sysarg_t row)
00139 {
00140         async_msg_3(fbphone, FB_PUTCHAR, ch, col, row);
00141 }
00142 
00144 static void redraw_state(size_t index)
00145 {
00146         vp_switch(cstatus_vp[index]);
00147         
00148         enum butstate state = console_state[index];
00149         
00150         if (ic_pixmaps[state] != -1)
00151                 async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index],
00152                     ic_pixmaps[state]);
00153         
00154         if ((state != CONS_DISCONNECTED) && (state != CONS_KERNEL)
00155             && (state != CONS_DISCONNECTED_SEL)) {
00156                 
00157                 char data[5];
00158                 snprintf(data, 5, "%zu", index + 1);
00159                 
00160                 size_t i;
00161                 for (i = 0; data[i] != 0; i++)
00162                         tran_putch(data[i], 2 + i, 1);
00163         }
00164 }
00165 
00167 void gcons_change_console(size_t index)
00168 {
00169         if (!use_gcons)
00170                 return;
00171         
00172         if (active_console == KERNEL_CONSOLE) {
00173                 size_t i;
00174                 
00175                 for (i = 0; i < CONSOLE_COUNT; i++)
00176                         redraw_state(i);
00177                 
00178                 if (animation != -1)
00179                         async_msg_1(fbphone, FB_ANIM_START, animation);
00180         } else {
00181                 if (console_state[active_console] == CONS_DISCONNECTED_SEL)
00182                         console_state[active_console] = CONS_DISCONNECTED;
00183                 else
00184                         console_state[active_console] = CONS_IDLE;
00185                 
00186                 redraw_state(active_console);
00187         }
00188         
00189         active_console = index;
00190         
00191         if ((console_state[index] == CONS_DISCONNECTED)
00192             || (console_state[index] == CONS_DISCONNECTED_SEL))
00193                 console_state[index] = CONS_DISCONNECTED_SEL;
00194         else
00195                 console_state[index] = CONS_SELECTED;
00196         
00197         redraw_state(index);
00198         vp_switch(console_vp);
00199 }
00200 
00202 void gcons_notify_char(size_t index)
00203 {
00204         if (!use_gcons)
00205                 return;
00206         
00207         if ((index == active_console)
00208             || (console_state[index] == CONS_HAS_DATA))
00209                 return;
00210         
00211         console_state[index] = CONS_HAS_DATA;
00212         
00213         if (active_console == KERNEL_CONSOLE)
00214                 return;
00215         
00216         redraw_state(index);
00217         vp_switch(console_vp);
00218 }
00219 
00221 void gcons_notify_disconnect(size_t index)
00222 {
00223         if (!use_gcons)
00224                 return;
00225         
00226         if (index == active_console)
00227                 console_state[index] = CONS_DISCONNECTED_SEL;
00228         else
00229                 console_state[index] = CONS_DISCONNECTED;
00230         
00231         if (active_console == KERNEL_CONSOLE)
00232                 return;
00233         
00234         redraw_state(index);
00235         vp_switch(console_vp);
00236 }
00237 
00239 void gcons_notify_connect(size_t index)
00240 {
00241         if (!use_gcons)
00242                 return;
00243         
00244         if (index == active_console)
00245                 console_state[index] = CONS_SELECTED;
00246         else
00247                 console_state[index] = CONS_IDLE;
00248         
00249         if (active_console == KERNEL_CONSOLE)
00250                 return;
00251         
00252         redraw_state(index);
00253         vp_switch(console_vp);
00254 }
00255 
00257 void gcons_in_kernel(void)
00258 {
00259         if (animation != -1)
00260                 async_msg_1(fbphone, FB_ANIM_STOP, animation);
00261         
00262         active_console = KERNEL_CONSOLE;
00263         vp_switch(0);
00264 }
00265 
00267 static inline ssize_t limit(ssize_t a, ssize_t left, ssize_t right)
00268 {
00269         if (a < left)
00270                 a = left;
00271         
00272         if (a >= right)
00273                 a = right - 1;
00274         
00275         return a;
00276 }
00277 
00283 void gcons_mouse_move(ssize_t dx, ssize_t dy)
00284 {
00285         ssize_t nx = (ssize_t) mouse_x + dx;
00286         ssize_t ny = (ssize_t) mouse_y + dy;
00287         
00288         /* Until gcons is initalized we don't have the screen resolution */
00289         if (xres == 0 || yres == 0)
00290                 return;
00291         
00292         mouse_x = (size_t) limit(nx, 0, xres);
00293         mouse_y = (size_t) limit(ny, 0, yres);
00294         
00295         if (active_console != KERNEL_CONSOLE)
00296                 async_msg_2(fbphone, FB_POINTER_MOVE, mouse_x, mouse_y);
00297 }
00298 
00299 static int gcons_find_conbut(sysarg_t x, sysarg_t y)
00300 {
00301         sysarg_t status_start = STATUS_START + (xres - 800) / 2;
00302         
00303         if ((y < STATUS_TOP) || (y >= STATUS_TOP + STATUS_HEIGHT))
00304                 return -1;
00305         
00306         if (x < status_start)
00307                 return -1;
00308         
00309         if (x >= status_start + (STATUS_WIDTH + STATUS_SPACE) * CONSOLE_COUNT)
00310                 return -1;
00311         
00312         if (((x - status_start) % (STATUS_WIDTH + STATUS_SPACE)) < STATUS_SPACE)
00313                 return -1;
00314         
00315         sysarg_t btn = (x - status_start) / (STATUS_WIDTH + STATUS_SPACE);
00316         
00317         if (btn < CONSOLE_COUNT)
00318                 return btn;
00319         
00320         return -1;
00321 }
00322 
00328 int gcons_mouse_btn(bool state)
00329 {
00330         /* Ignore mouse clicks if no buttons
00331            are drawn at all */
00332         if (xres < 800)
00333                 return -1;
00334         
00335         if (state) {
00336                 int conbut = gcons_find_conbut(mouse_x, mouse_y);
00337                 if (conbut != -1) {
00338                         btn_pressed = true;
00339                         btn_x = mouse_x;
00340                         btn_y = mouse_y;
00341                 }
00342                 return -1;
00343         }
00344         
00345         if ((!state) && (!btn_pressed))
00346                 return -1;
00347         
00348         btn_pressed = false;
00349         
00350         int conbut = gcons_find_conbut(mouse_x, mouse_y);
00351         if (conbut == gcons_find_conbut(btn_x, btn_y))
00352                 return conbut;
00353         
00354         return -1;
00355 }
00356 
00365 static void draw_pixmap(char *logo, size_t size, sysarg_t x, sysarg_t y)
00366 {
00367         /* Create area */
00368         char *shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
00369             MAP_ANONYMOUS, 0, 0);
00370         if (shm == MAP_FAILED)
00371                 return;
00372         
00373         memcpy(shm, logo, size);
00374         
00375         /* Send area */
00376         int rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
00377         if (rc)
00378                 goto exit;
00379         
00380         rc = async_share_out_start(fbphone, shm, PROTO_READ);
00381         if (rc)
00382                 goto drop;
00383         
00384         /* Draw logo */
00385         async_msg_2(fbphone, FB_DRAW_PPM, x, y);
00386         
00387 drop:
00388         /* Drop area */
00389         async_msg_0(fbphone, FB_DROP_SHM);
00390         
00391 exit:
00392         /* Remove area */
00393         munmap(shm, size);
00394 }
00395 
00397 void gcons_redraw_console(void)
00398 {
00399         if (!use_gcons)
00400                 return;
00401         
00402         vp_switch(0);
00403         set_rgb_color(COLOR_MAIN, COLOR_MAIN);
00404         clear();
00405         draw_pixmap(_binary_gfx_helenos_ppm_start,
00406             (size_t) &_binary_gfx_helenos_ppm_size, xres - 66, 2);
00407         draw_pixmap(_binary_gfx_nameic_ppm_start,
00408             (size_t) &_binary_gfx_nameic_ppm_size, 5, 17);
00409         
00410         unsigned int i;
00411         for (i = 0; i < CONSOLE_COUNT; i++)
00412                 redraw_state(i);
00413         
00414         vp_switch(console_vp);
00415 }
00416 
00425 static int make_pixmap(char *data, size_t size)
00426 {
00427         /* Create area */
00428         char *shm = mmap(NULL, size, PROTO_READ | PROTO_WRITE, MAP_SHARED |
00429             MAP_ANONYMOUS, 0, 0);
00430         if (shm == MAP_FAILED)
00431                 return -1;
00432         
00433         memcpy(shm, data, size);
00434         
00435         int pxid = -1;
00436         
00437         /* Send area */
00438         int rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (sysarg_t) shm);
00439         if (rc)
00440                 goto exit;
00441         
00442         rc = async_share_out_start(fbphone, shm, PROTO_READ);
00443         if (rc)
00444                 goto drop;
00445         
00446         /* Obtain pixmap */
00447         rc = async_req_0_0(fbphone, FB_SHM2PIXMAP);
00448         if (rc < 0)
00449                 goto drop;
00450         
00451         pxid = rc;
00452         
00453 drop:
00454         /* Drop area */
00455         async_msg_0(fbphone, FB_DROP_SHM);
00456         
00457 exit:
00458         /* Remove area */
00459         munmap(shm, size);
00460         
00461         return pxid;
00462 }
00463 
00464 static void make_anim(void)
00465 {
00466         int an = async_req_1_0(fbphone, FB_ANIM_CREATE,
00467             cstatus_vp[KERNEL_CONSOLE]);
00468         if (an < 0)
00469                 return;
00470         
00471         int pm = make_pixmap(_binary_gfx_anim_1_ppm_start,
00472             (size_t) &_binary_gfx_anim_1_ppm_size);
00473         async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
00474         
00475         pm = make_pixmap(_binary_gfx_anim_2_ppm_start,
00476             (size_t) &_binary_gfx_anim_2_ppm_size);
00477         async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
00478         
00479         pm = make_pixmap(_binary_gfx_anim_3_ppm_start,
00480             (size_t) &_binary_gfx_anim_3_ppm_size);
00481         async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
00482         
00483         pm = make_pixmap(_binary_gfx_anim_4_ppm_start,
00484             (size_t) &_binary_gfx_anim_4_ppm_size);
00485         async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
00486         
00487         async_msg_1(fbphone, FB_ANIM_START, an);
00488         
00489         animation = an;
00490 }
00491 
00493 void gcons_init(int phone)
00494 {
00495         fbphone = phone;
00496         
00497         int rc = async_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres);
00498         if (rc)
00499                 return;
00500         
00501         if ((xres < 800) || (yres < 600))
00502                 return;
00503         
00504         /* Create console viewport */
00505         
00506         /* Align width & height to character size */
00507         console_vp = vp_create(CONSOLE_MARGIN, CONSOLE_TOP,
00508             ALIGN_DOWN(xres - 2 * CONSOLE_MARGIN, 8),
00509             ALIGN_DOWN(yres - (CONSOLE_TOP + CONSOLE_MARGIN), 16));
00510         
00511         if (console_vp < 0)
00512                 return;
00513         
00514         /* Create status buttons */
00515         sysarg_t status_start = STATUS_START + (xres - 800) / 2;
00516         size_t i;
00517         for (i = 0; i < CONSOLE_COUNT; i++) {
00518                 cstatus_vp[i] = vp_create(status_start + CONSOLE_MARGIN +
00519                     i * (STATUS_WIDTH + STATUS_SPACE), STATUS_TOP,
00520                     STATUS_WIDTH, STATUS_HEIGHT);
00521                 
00522                 if (cstatus_vp[i] < 0)
00523                         return;
00524                 
00525                 vp_switch(cstatus_vp[i]);
00526                 set_rgb_color(COLOR_FOREGROUND, COLOR_BACKGROUND);
00527         }
00528         
00529         /* Initialize icons */
00530         ic_pixmaps[CONS_SELECTED] =
00531             make_pixmap(_binary_gfx_cons_selected_ppm_start,
00532             (size_t) &_binary_gfx_cons_selected_ppm_size);
00533         ic_pixmaps[CONS_IDLE] =
00534             make_pixmap(_binary_gfx_cons_idle_ppm_start,
00535             (size_t) &_binary_gfx_cons_idle_ppm_size);
00536         ic_pixmaps[CONS_HAS_DATA] =
00537             make_pixmap(_binary_gfx_cons_has_data_ppm_start,
00538             (size_t) &_binary_gfx_cons_has_data_ppm_size);
00539         ic_pixmaps[CONS_DISCONNECTED] =
00540             make_pixmap(_binary_gfx_cons_idle_ppm_start,
00541             (size_t) &_binary_gfx_cons_idle_ppm_size);
00542         ic_pixmaps[CONS_KERNEL] =
00543             make_pixmap(_binary_gfx_cons_kernel_ppm_start,
00544             (size_t) &_binary_gfx_cons_kernel_ppm_size);
00545         ic_pixmaps[CONS_DISCONNECTED_SEL] = ic_pixmaps[CONS_SELECTED];
00546         
00547         make_anim();
00548         
00549         use_gcons = true;
00550         console_state[0] = CONS_DISCONNECTED_SEL;
00551         console_state[KERNEL_CONSOLE] = CONS_KERNEL;
00552         
00553         vp_switch(console_vp);
00554 }
00555 

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