symbian-qemu-0.9.1-12/qemu-symbian-svp/curses.c
changeset 1 2fb8b9db1c86
equal deleted inserted replaced
0:ffa851df0825 1:2fb8b9db1c86
       
     1 /*
       
     2  * QEMU curses/ncurses display driver
       
     3  * 
       
     4  * Copyright (c) 2005 Andrzej Zaborowski  <balrog@zabor.org>
       
     5  * 
       
     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
       
     7  * of this software and associated documentation files (the "Software"), to deal
       
     8  * in the Software without restriction, including without limitation the rights
       
     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       
    10  * copies of the Software, and to permit persons to whom the Software is
       
    11  * furnished to do so, subject to the following conditions:
       
    12  *
       
    13  * The above copyright notice and this permission notice shall be included in
       
    14  * all copies or substantial portions of the Software.
       
    15  *
       
    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
       
    19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
       
    22  * THE SOFTWARE.
       
    23  */
       
    24 
       
    25 #include "qemu-common.h"
       
    26 #include "console.h"
       
    27 #include "sysemu.h"
       
    28 #include "gui_host.h"
       
    29 
       
    30 #include <curses.h>
       
    31 
       
    32 #ifndef _WIN32
       
    33 #include <signal.h>
       
    34 #include <sys/ioctl.h>
       
    35 #include <termios.h>
       
    36 #endif
       
    37 
       
    38 #ifdef __OpenBSD__
       
    39 #define resize_term resizeterm
       
    40 #endif
       
    41 
       
    42 #define FONT_HEIGHT 16
       
    43 #define FONT_WIDTH 8
       
    44 
       
    45 static console_ch_t screen[160 * 100];
       
    46 static WINDOW *screenpad = NULL;
       
    47 static int width, height, gwidth, gheight, invalidate;
       
    48 static int px, py, sminx, sminy, smaxx, smaxy;
       
    49 
       
    50 static void curses_update(DisplayState *ds, int x, int y, int w, int h)
       
    51 {
       
    52     chtype *line;
       
    53 
       
    54     line = ((chtype *) screen) + y * width;
       
    55     for (h += y; y < h; y ++, line += width)
       
    56         mvwaddchnstr(screenpad, y, 0, line, width);
       
    57 
       
    58     pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
       
    59     refresh();
       
    60 }
       
    61 
       
    62 static void curses_calc_pad(void)
       
    63 {
       
    64     if (gui_is_fixedsize()) {
       
    65         width = gwidth;
       
    66         height = gheight;
       
    67     } else {
       
    68         width = COLS;
       
    69         height = LINES;
       
    70     }
       
    71 
       
    72     if (screenpad)
       
    73         delwin(screenpad);
       
    74 
       
    75     clear();
       
    76     refresh();
       
    77 
       
    78     screenpad = newpad(height, width);
       
    79 
       
    80     if (width > COLS) {
       
    81         px = (width - COLS) / 2;
       
    82         sminx = 0;
       
    83         smaxx = COLS;
       
    84     } else {
       
    85         px = 0;
       
    86         sminx = (COLS - width) / 2;
       
    87         smaxx = sminx + width;
       
    88     }
       
    89 
       
    90     if (height > LINES) {
       
    91         py = (height - LINES) / 2;
       
    92         sminy = 0;
       
    93         smaxy = LINES;
       
    94     } else {
       
    95         py = 0;
       
    96         sminy = (LINES - height) / 2;
       
    97         smaxy = sminy + height;
       
    98     }
       
    99 }
       
   100 
       
   101 static void curses_resize(DisplayState *ds, int w, int h)
       
   102 {
       
   103     if (w == gwidth && h == gheight)
       
   104         return;
       
   105 
       
   106     gwidth = w;
       
   107     gheight = h;
       
   108 
       
   109     curses_calc_pad();
       
   110 }
       
   111 
       
   112 #ifndef _WIN32
       
   113 #if defined(SIGWINCH) && defined(KEY_RESIZE)
       
   114 static void curses_winch_handler(int signum)
       
   115 {
       
   116     struct winsize {
       
   117         unsigned short ws_row;
       
   118         unsigned short ws_col;
       
   119         unsigned short ws_xpixel;   /* unused */
       
   120         unsigned short ws_ypixel;   /* unused */
       
   121     } ws;
       
   122 
       
   123     /* terminal size changed */
       
   124     if (ioctl(1, TIOCGWINSZ, &ws) == -1)
       
   125         return;
       
   126 
       
   127     resize_term(ws.ws_row, ws.ws_col);
       
   128     curses_calc_pad();
       
   129     invalidate = 1;
       
   130 
       
   131     /* some systems require this */
       
   132     signal(SIGWINCH, curses_winch_handler);
       
   133 }
       
   134 #endif
       
   135 #endif
       
   136 
       
   137 static void curses_cursor_position(DisplayState *ds, int x, int y)
       
   138 {
       
   139     if (x >= 0) {
       
   140         x = sminx + x - px;
       
   141         y = sminy + y - py;
       
   142 
       
   143         if (x >= 0 && y >= 0 && x < COLS && y < LINES) {
       
   144             move(y, x);
       
   145             curs_set(1);
       
   146             /* it seems that curs_set(1) must always be called before
       
   147              * curs_set(2) for the latter to have effect */
       
   148             if (!gui_is_graphic_console())
       
   149                 curs_set(2);
       
   150             return;
       
   151         }
       
   152     }
       
   153 
       
   154     curs_set(0);
       
   155 }
       
   156 
       
   157 /* generic keyboard conversion */
       
   158 
       
   159 #include "curses_keys.h"
       
   160 #include "keymaps.c"
       
   161 
       
   162 static kbd_layout_t *kbd_layout = 0;
       
   163 static int keycode2keysym[CURSES_KEYS];
       
   164 
       
   165 static void curses_refresh(DisplayState *ds)
       
   166 {
       
   167     int chr, nextchr, keysym, keycode;
       
   168 
       
   169     if (invalidate) {
       
   170         clear();
       
   171         refresh();
       
   172         curses_calc_pad();
       
   173         ds->width = FONT_WIDTH * width;
       
   174         ds->height = FONT_HEIGHT * height;
       
   175         /*vga_hw_invalidate(); DFG TODO CHECK! */
       
   176         invalidate = 0;
       
   177     }
       
   178 
       
   179 #if 0
       
   180     DFG TODO
       
   181     vga_hw_text_update(screen);
       
   182 #endif
       
   183 
       
   184     nextchr = ERR;
       
   185     while (1) {
       
   186         /* while there are any pending key strokes to process */
       
   187         if (nextchr == ERR)
       
   188             chr = getch();
       
   189         else {
       
   190             chr = nextchr;
       
   191             nextchr = ERR;
       
   192         }
       
   193 
       
   194         if (chr == ERR)
       
   195             break;
       
   196 
       
   197 #ifdef KEY_RESIZE
       
   198         /* this shouldn't occur when we use a custom SIGWINCH handler */
       
   199         if (chr == KEY_RESIZE) {
       
   200             clear();
       
   201             refresh();
       
   202             curses_calc_pad();
       
   203             curses_update(ds, 0, 0, width, height);
       
   204             ds->width = FONT_WIDTH * width;
       
   205             ds->height = FONT_HEIGHT * height;
       
   206             continue;
       
   207         }
       
   208 #endif
       
   209 
       
   210         keycode = curses2keycode[chr];
       
   211         if (keycode == -1)
       
   212             continue;
       
   213 
       
   214         /* alt key */
       
   215         if (keycode == 1) {
       
   216             nextchr = getch();
       
   217 
       
   218             if (nextchr != ERR) {
       
   219                 keycode = curses2keycode[nextchr];
       
   220                 nextchr = ERR;
       
   221                 if (keycode == -1)
       
   222                     continue;
       
   223 
       
   224                 keycode |= ALT;
       
   225 
       
   226                 /* process keys reserved for qemu */
       
   227                 if (keycode >= QEMU_KEY_CONSOLE0 &&
       
   228                         keycode < QEMU_KEY_CONSOLE0 + 9) {
       
   229                     erase();
       
   230                     wnoutrefresh(stdscr);
       
   231                     console_select(keycode - QEMU_KEY_CONSOLE0);
       
   232 
       
   233                     invalidate = 1;
       
   234                     continue;
       
   235                 }
       
   236             }
       
   237         }
       
   238 
       
   239         if (kbd_layout && !(keycode & GREY)) {
       
   240             keysym = keycode2keysym[keycode & KEY_MASK];
       
   241             if (keysym == -1)
       
   242                 keysym = chr;
       
   243 
       
   244             keycode &= ~KEY_MASK;
       
   245             keycode |= keysym2scancode(kbd_layout, keysym);
       
   246         }
       
   247 
       
   248         if (gui_is_graphic_console()) {
       
   249             /* since terminals don't know about key press and release
       
   250              * events, we need to emit both for each key received */
       
   251             if (keycode & SHIFT)
       
   252                 kbd_put_keycode(SHIFT_CODE);
       
   253             if (keycode & CNTRL)
       
   254                 kbd_put_keycode(CNTRL_CODE);
       
   255             if (keycode & ALT)
       
   256                 kbd_put_keycode(ALT_CODE);
       
   257             if (keycode & GREY)
       
   258                 kbd_put_keycode(GREY_CODE);
       
   259             kbd_put_keycode(keycode & KEY_MASK);
       
   260             if (keycode & GREY)
       
   261                 kbd_put_keycode(GREY_CODE);
       
   262             kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
       
   263             if (keycode & ALT)
       
   264                 kbd_put_keycode(ALT_CODE | KEY_RELEASE);
       
   265             if (keycode & CNTRL)
       
   266                 kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
       
   267             if (keycode & SHIFT)
       
   268                 kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
       
   269         } else {
       
   270             keysym = curses2keysym[chr];
       
   271             if (keysym == -1)
       
   272                 keysym = chr;
       
   273 
       
   274             gui_notify_key(keysym); /*kbd_put_keysym(keysym);*/
       
   275         }
       
   276     }
       
   277 }
       
   278 
       
   279 static void curses_cleanup(void *opaque) 
       
   280 {
       
   281     endwin();
       
   282 }
       
   283 
       
   284 static void curses_atexit(void)
       
   285 {
       
   286     curses_cleanup(NULL);
       
   287 }
       
   288 
       
   289 static void curses_setup(void)
       
   290 {
       
   291     int i, colour_default[8] = {
       
   292         COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
       
   293         COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
       
   294     };
       
   295 
       
   296     /* input as raw as possible, let everything be interpreted
       
   297      * by the guest system */
       
   298     initscr(); noecho(); intrflush(stdscr, FALSE);
       
   299     nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
       
   300     start_color(); raw(); scrollok(stdscr, FALSE);
       
   301 
       
   302     for (i = 0; i < 64; i ++)
       
   303         init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
       
   304 }
       
   305 
       
   306 static void curses_keyboard_setup(void)
       
   307 {
       
   308     int i, keycode, keysym;
       
   309 
       
   310 #if defined(__APPLE__)
       
   311     /* always use generic keymaps */
       
   312     if (!keyboard_layout)
       
   313         keyboard_layout = "en-us";
       
   314 #endif
       
   315     if(keyboard_layout) {
       
   316         kbd_layout = init_keyboard_layout(keyboard_layout);
       
   317         if (!kbd_layout)
       
   318             exit(1);
       
   319     }
       
   320 
       
   321     for (i = 0; i < CURSES_KEYS; i ++)
       
   322         keycode2keysym[i] = -1;
       
   323 
       
   324     for (i = 0; i < CURSES_KEYS; i ++) {
       
   325         if (curses2keycode[i] == -1)
       
   326             continue;
       
   327 
       
   328         keycode = curses2keycode[i] & KEY_MASK;
       
   329         if (keycode2keysym[keycode] >= 0)
       
   330             continue;
       
   331 
       
   332         for (keysym = 0; keysym < CURSES_KEYS; keysym ++)
       
   333             if (curses2keycode[keysym] == keycode) {
       
   334                 keycode2keysym[keycode] = keysym;
       
   335                 break;
       
   336             }
       
   337 
       
   338         if (keysym >= CURSES_KEYS)
       
   339             keycode2keysym[keycode] = i;
       
   340     }
       
   341 }
       
   342 
       
   343 void curses_display_init(DisplayState *ds, int full_screen)
       
   344 {
       
   345 #ifndef _WIN32
       
   346     if (!isatty(1)) {
       
   347         fprintf(stderr, "We need a terminal output\n");
       
   348         exit(1);
       
   349     }
       
   350 #endif
       
   351 
       
   352     curses_setup();
       
   353     curses_keyboard_setup();
       
   354     atexit(curses_atexit);
       
   355 
       
   356 #ifndef _WIN32
       
   357 #if defined(SIGWINCH) && defined(KEY_RESIZE)
       
   358     /* some curses implementations provide a handler, but we
       
   359      * want to be sure this is handled regardless of the library */
       
   360     signal(SIGWINCH, curses_winch_handler);
       
   361 #endif
       
   362 #endif
       
   363 
       
   364     ds->data = (void *) screen;
       
   365     ds->linesize = 0;
       
   366     ds->depth = 0;
       
   367     ds->width = 640;
       
   368     ds->height = 400;
       
   369     ds->dpy_update = curses_update;
       
   370 #if 0
       
   371     DFG TODO
       
   372     ds->dpy_resize = curses_resize;
       
   373     ds->dpy_refresh = curses_refresh;
       
   374 #endif
       
   375     ds->dpy_text_cursor = curses_cursor_position;
       
   376 
       
   377     invalidate = 1;
       
   378 
       
   379     /* Standard VGA initial text mode dimensions */
       
   380     curses_resize(ds, 80, 25);
       
   381 }