Subversion Repositories HelenOS

Rev

Rev 4338 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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
  30.  * @{
  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>
  42. #include <bool.h>
  43.  
  44. #include "console.h"
  45. #include "gcons.h"
  46.  
  47. #define CONSOLE_TOP     66
  48. #define CONSOLE_MARGIN  6
  49.  
  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
  55.  
  56. #define MAIN_COLOR  0xffffff
  57.  
  58. static bool use_gcons = false;
  59. static ipcarg_t xres;
  60. static ipcarg_t yres;
  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.  
  82. static size_t active_console = 0;
  83.  
  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.  
  91. static void vp_switch(int vp)
  92. {
  93.     async_msg_1(fbphone, FB_VIEWPORT_SWITCH, vp);
  94. }
  95.  
  96. /** Create view port */
  97. static int vp_create(size_t x, size_t y, size_t width, size_t height)
  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.  
  108. static void set_rgb_color(uint32_t fgcolor, uint32_t bgcolor)
  109. {
  110.     async_msg_2(fbphone, FB_SET_RGB_COLOR, fgcolor, bgcolor);
  111. }
  112.  
  113. /** Transparent putchar */
  114. static void tran_putch(wchar_t ch, size_t col, size_t row)
  115. {
  116.     async_msg_3(fbphone, FB_PUTCHAR, ch, col, row);
  117. }
  118.  
  119. /** Redraw the button showing state of a given console */
  120. static void redraw_state(size_t index)
  121. {
  122.     vp_switch(cstatus_vp[index]);
  123.    
  124.     enum butstate state = console_state[index];
  125.    
  126.     if (ic_pixmaps[state] != -1)
  127.         async_msg_2(fbphone, FB_VP_DRAW_PIXMAP, cstatus_vp[index],
  128.             ic_pixmaps[state]);
  129.    
  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);
  139.     }
  140. }
  141.  
  142. /** Notification run on changing console (except kernel console) */
  143. void gcons_change_console(size_t index)
  144. {
  145.     if (!use_gcons)
  146.         return;
  147.    
  148.     if (active_console == KERNEL_CONSOLE) {
  149.         size_t i;
  150.        
  151.         for (i = 0; i < CONSOLE_COUNT; i++)
  152.             redraw_state(i);
  153.        
  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;
  161.        
  162.         redraw_state(active_console);
  163.     }
  164.    
  165.     active_console = index;
  166.    
  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);
  174.     vp_switch(console_vp);
  175. }
  176.  
  177. /** Notification function that gets called on new output to virtual console */
  178. void gcons_notify_char(size_t index)
  179. {
  180.     if (!use_gcons)
  181.         return;
  182.    
  183.     if ((index == active_console)
  184.         || (console_state[index] == CONS_HAS_DATA))
  185.         return;
  186.    
  187.     console_state[index] = CONS_HAS_DATA;
  188.    
  189.     if (active_console == KERNEL_CONSOLE)
  190.         return;
  191.    
  192.     redraw_state(index);
  193.     vp_switch(console_vp);
  194. }
  195.  
  196. /** Notification function called on service disconnect from console */
  197. void gcons_notify_disconnect(size_t index)
  198. {
  199.     if (!use_gcons)
  200.         return;
  201.    
  202.     if (index == active_console)
  203.         console_state[index] = CONS_DISCONNECTED_SEL;
  204.     else
  205.         console_state[index] = CONS_DISCONNECTED;
  206.    
  207.     if (active_console == KERNEL_CONSOLE)
  208.         return;
  209.    
  210.     redraw_state(index);
  211.     vp_switch(console_vp);
  212. }
  213.  
  214. /** Notification function called on console connect */
  215. void gcons_notify_connect(size_t index)
  216. {
  217.     if (!use_gcons)
  218.         return;
  219.    
  220.     if (index == active_console)
  221.         console_state[index] = CONS_SELECTED;
  222.     else
  223.         console_state[index] = CONS_IDLE;
  224.    
  225.     if (active_console == KERNEL_CONSOLE)
  226.         return;
  227.    
  228.     redraw_state(index);
  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.  
  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)
  244. {
  245.     if (a < left)
  246.         a = left;
  247.    
  248.     if (a >= right)
  249.         a = right - 1;
  250.    
  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.  */
  259. void gcons_mouse_move(ssize_t dx, ssize_t dy)
  260. {
  261.     mouse_x = limit(mouse_x + dx, 0, xres);
  262.     mouse_y = limit(mouse_y + dy, 0, yres);
  263.    
  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;
  270.    
  271.     if ((y < STATUS_TOP) || (y >= STATUS_TOP + STATUS_HEIGHT))
  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.  *
  287.  * @param state New state (true - pressed, false - depressed)
  288.  */
  289. int gcons_mouse_btn(bool state)
  290. {
  291.     int conbut;
  292.    
  293.     if (state) {
  294.         conbut = gcons_find_conbut(mouse_x, mouse_y);
  295.         if (conbut != -1) {
  296.             btn_pressed = true;
  297.             btn_x = mouse_x;
  298.             btn_y = mouse_y;
  299.         }
  300.         return -1;
  301.     }
  302.    
  303.     if ((!state) && (!btn_pressed))
  304.         return -1;
  305.    
  306.     btn_pressed = false;
  307.    
  308.     conbut = gcons_find_conbut(mouse_x, mouse_y);
  309.     if (conbut == gcons_find_conbut(btn_x, btn_y))
  310.         return conbut;
  311.    
  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;
  327.    
  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;
  333.    
  334.     memcpy(shm, logo, size);
  335.    
  336.     /* Send area */
  337.     rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (ipcarg_t) shm);
  338.     if (rc)
  339.         goto exit;
  340.    
  341.     rc = ipc_share_out_start(fbphone, shm, PROTO_READ);
  342.     if (rc)
  343.         goto drop;
  344.    
  345.     /* Draw logo */
  346.     async_msg_2(fbphone, FB_DRAW_PPM, x, y);
  347.    
  348. drop:
  349.     /* Drop area */
  350.     async_msg_0(fbphone, FB_DROP_SHM);
  351.    
  352. exit:
  353.     /* Remove area */
  354.     munmap(shm, size);
  355. }
  356.  
  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;
  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();
  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);
  377.    
  378.     for (i = 0; i < CONSOLE_COUNT; i++)
  379.         redraw_state(i);
  380.    
  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
  388.  *
  389.  * @return Pixmap identification
  390.  *
  391.  */
  392. static int make_pixmap(char *data, size_t size)
  393. {
  394.     char *shm;
  395.     int rc;
  396.     int pxid = -1;
  397.    
  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;
  403.    
  404.     memcpy(shm, data, size);
  405.    
  406.     /* Send area */
  407.     rc = async_req_1_0(fbphone, FB_PREPARE_SHM, (ipcarg_t) shm);
  408.     if (rc)
  409.         goto exit;
  410.    
  411.     rc = ipc_share_out_start(fbphone, shm, PROTO_READ);
  412.     if (rc)
  413.         goto drop;
  414.    
  415.     /* Obtain pixmap */
  416.     rc = async_req_0_0(fbphone, FB_SHM2PIXMAP);
  417.     if (rc < 0)
  418.         goto drop;
  419.    
  420.     pxid = rc;
  421.    
  422. drop:
  423.     /* Drop area */
  424.     async_msg_0(fbphone, FB_DROP_SHM);
  425.    
  426. exit:
  427.     /* Remove area */
  428.     munmap(shm, size);
  429.    
  430.     return pxid;
  431. }
  432.  
  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;
  441.  
  442. static void make_anim(void)
  443. {
  444.     int an = async_req_1_0(fbphone, FB_ANIM_CREATE, cstatus_vp[KERNEL_CONSOLE]);
  445.     if (an < 0)
  446.         return;
  447.    
  448.     int pm = make_pixmap(_binary_gfx_anim_1_ppm_start,
  449.         (int) &_binary_gfx_anim_1_ppm_size);
  450.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  451.    
  452.     pm = make_pixmap(_binary_gfx_anim_2_ppm_start,
  453.         (int) &_binary_gfx_anim_2_ppm_size);
  454.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  455.    
  456.     pm = make_pixmap(_binary_gfx_anim_3_ppm_start,
  457.         (int) &_binary_gfx_anim_3_ppm_size);
  458.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  459.    
  460.     pm = make_pixmap(_binary_gfx_anim_4_ppm_start,
  461.         (int) &_binary_gfx_anim_4_ppm_size);
  462.     async_msg_2(fbphone, FB_ANIM_ADDPIXMAP, an, pm);
  463.    
  464.     async_msg_1(fbphone, FB_ANIM_START, an);
  465.    
  466.     animation = an;
  467. }
  468.  
  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;
  477.  
  478. /** Initialize nice graphical console environment */
  479. void gcons_init(int phone)
  480. {
  481.     fbphone = phone;
  482.    
  483.     int rc = async_req_0_2(phone, FB_GET_RESOLUTION, &xres, &yres);
  484.     if (rc)
  485.         return;
  486.    
  487.     if ((xres < 800) || (yres < 600))
  488.         return;
  489.    
  490.     /* Create console viewport */
  491.    
  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));
  496.    
  497.     if (console_vp < 0)
  498.         return;
  499.    
  500.     /* Create status buttons */
  501.     size_t status_start = STATUS_START + (xres - 800) / 2;
  502.     size_t i;
  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);
  507.        
  508.         if (cstatus_vp[i] < 0)
  509.             return;
  510.        
  511.         vp_switch(cstatus_vp[i]);
  512.         set_rgb_color(0x202020, 0xffffff);
  513.     }
  514.    
  515.     /* Initialize icons */
  516.     ic_pixmaps[CONS_SELECTED] =
  517.         make_pixmap(_binary_gfx_cons_selected_ppm_start,
  518.         (size_t) &_binary_gfx_cons_selected_ppm_size);
  519.     ic_pixmaps[CONS_IDLE] =
  520.         make_pixmap(_binary_gfx_cons_idle_ppm_start,
  521.         (size_t) &_binary_gfx_cons_idle_ppm_size);
  522.     ic_pixmaps[CONS_HAS_DATA] =
  523.         make_pixmap(_binary_gfx_cons_has_data_ppm_start,
  524.         (size_t) &_binary_gfx_cons_has_data_ppm_size);
  525.     ic_pixmaps[CONS_DISCONNECTED] =
  526.         make_pixmap(_binary_gfx_cons_idle_ppm_start,
  527.         (size_t) &_binary_gfx_cons_idle_ppm_size);
  528.     ic_pixmaps[CONS_KERNEL] =
  529.         make_pixmap(_binary_gfx_cons_kernel_ppm_start,
  530.         (size_t) &_binary_gfx_cons_kernel_ppm_size);
  531.     ic_pixmaps[CONS_DISCONNECTED_SEL] = ic_pixmaps[CONS_SELECTED];
  532.    
  533.     make_anim();
  534.    
  535.     use_gcons = true;
  536.     console_state[0] = CONS_DISCONNECTED_SEL;
  537.     console_state[KERNEL_CONSOLE] = CONS_KERNEL;
  538.    
  539.     vp_switch(console_vp);
  540. }
  541.  
  542. /** @}
  543.  */
  544.