Annotation of qemu/ui/curses.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * QEMU curses/ncurses display driver
                      3:  * 
                      4:  * Copyright (c) 2005 Andrzej Zaborowski  <[email protected]>
                      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: #include <curses.h>
                     25: 
                     26: #ifndef _WIN32
                     27: #include <signal.h>
                     28: #include <sys/ioctl.h>
                     29: #include <termios.h>
                     30: #endif
                     31: 
                     32: #ifdef __OpenBSD__
                     33: #define resize_term resizeterm
                     34: #endif
                     35: 
                     36: #include "qemu-common.h"
                     37: #include "console.h"
                     38: #include "sysemu.h"
                     39: 
                     40: #define FONT_HEIGHT 16
                     41: #define FONT_WIDTH 8
                     42: 
                     43: static console_ch_t screen[160 * 100];
                     44: static WINDOW *screenpad = NULL;
                     45: static int width, height, gwidth, gheight, invalidate;
                     46: static int px, py, sminx, sminy, smaxx, smaxy;
                     47: 
                     48: static void curses_update(DisplayState *ds, int x, int y, int w, int h)
                     49: {
                     50:     chtype *line;
                     51: 
                     52:     line = ((chtype *) screen) + y * width;
                     53:     for (h += y; y < h; y ++, line += width)
                     54:         mvwaddchnstr(screenpad, y, 0, line, width);
                     55: 
                     56:     pnoutrefresh(screenpad, py, px, sminy, sminx, smaxy - 1, smaxx - 1);
                     57:     refresh();
                     58: }
                     59: 
                     60: static void curses_calc_pad(void)
                     61: {
                     62:     if (is_fixedsize_console()) {
                     63:         width = gwidth;
                     64:         height = gheight;
                     65:     } else {
                     66:         width = COLS;
                     67:         height = LINES;
                     68:     }
                     69: 
                     70:     if (screenpad)
                     71:         delwin(screenpad);
                     72: 
                     73:     clear();
                     74:     refresh();
                     75: 
                     76:     screenpad = newpad(height, width);
                     77: 
                     78:     if (width > COLS) {
                     79:         px = (width - COLS) / 2;
                     80:         sminx = 0;
                     81:         smaxx = COLS;
                     82:     } else {
                     83:         px = 0;
                     84:         sminx = (COLS - width) / 2;
                     85:         smaxx = sminx + width;
                     86:     }
                     87: 
                     88:     if (height > LINES) {
                     89:         py = (height - LINES) / 2;
                     90:         sminy = 0;
                     91:         smaxy = LINES;
                     92:     } else {
                     93:         py = 0;
                     94:         sminy = (LINES - height) / 2;
                     95:         smaxy = sminy + height;
                     96:     }
                     97: }
                     98: 
                     99: static void curses_resize(DisplayState *ds)
                    100: {
                    101:     if (ds_get_width(ds) == gwidth && ds_get_height(ds) == gheight)
                    102:         return;
                    103: 
                    104:     gwidth = ds_get_width(ds);
                    105:     gheight = ds_get_height(ds);
                    106: 
                    107:     curses_calc_pad();
                    108:     ds->surface->width = width * FONT_WIDTH;
                    109:     ds->surface->height = height * FONT_HEIGHT;
                    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 (!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: 
                    161: static kbd_layout_t *kbd_layout = NULL;
                    162: 
                    163: static void curses_refresh(DisplayState *ds)
                    164: {
                    165:     int chr, nextchr, keysym, keycode, keycode_alt;
                    166: 
                    167:     if (invalidate) {
                    168:         clear();
                    169:         refresh();
                    170:         curses_calc_pad();
                    171:         ds->surface->width = FONT_WIDTH * width;
                    172:         ds->surface->height = FONT_HEIGHT * height;
                    173:         vga_hw_invalidate();
                    174:         invalidate = 0;
                    175:     }
                    176: 
                    177:     vga_hw_text_update(screen);
                    178: 
                    179:     nextchr = ERR;
                    180:     while (1) {
                    181:         /* while there are any pending key strokes to process */
                    182:         if (nextchr == ERR)
                    183:             chr = getch();
                    184:         else {
                    185:             chr = nextchr;
                    186:             nextchr = ERR;
                    187:         }
                    188: 
                    189:         if (chr == ERR)
                    190:             break;
                    191: 
                    192: #ifdef KEY_RESIZE
                    193:         /* this shouldn't occur when we use a custom SIGWINCH handler */
                    194:         if (chr == KEY_RESIZE) {
                    195:             clear();
                    196:             refresh();
                    197:             curses_calc_pad();
                    198:             curses_update(ds, 0, 0, width, height);
                    199:             ds->surface->width = FONT_WIDTH * width;
                    200:             ds->surface->height = FONT_HEIGHT * height;
                    201:             continue;
                    202:         }
                    203: #endif
                    204: 
                    205:         keycode = curses2keycode[chr];
                    206:         keycode_alt = 0;
                    207: 
                    208:         /* alt key */
                    209:         if (keycode == 1) {
                    210:             nextchr = getch();
                    211: 
                    212:             if (nextchr != ERR) {
                    213:                 chr = nextchr;
                    214:                 keycode_alt = ALT;
                    215:                 keycode = curses2keycode[nextchr];
                    216:                 nextchr = ERR;
                    217: 
                    218:                 if (keycode != -1) {
                    219:                     keycode |= ALT;
                    220: 
                    221:                     /* process keys reserved for qemu */
                    222:                     if (keycode >= QEMU_KEY_CONSOLE0 &&
                    223:                             keycode < QEMU_KEY_CONSOLE0 + 9) {
                    224:                         erase();
                    225:                         wnoutrefresh(stdscr);
                    226:                         console_select(keycode - QEMU_KEY_CONSOLE0);
                    227: 
                    228:                         invalidate = 1;
                    229:                         continue;
                    230:                     }
                    231:                 }
                    232:             }
                    233:         }
                    234: 
                    235:         if (kbd_layout) {
                    236:             keysym = -1;
                    237:             if (chr < CURSES_KEYS)
                    238:                 keysym = curses2keysym[chr];
                    239: 
                    240:             if (keysym == -1) {
                    241:                 if (chr < ' ')
                    242:                     keysym = (chr + '@' - 'A' + 'a') | KEYSYM_CNTRL;
                    243:                 else
                    244:                     keysym = chr;
                    245:             }
                    246: 
                    247:             keycode = keysym2scancode(kbd_layout, keysym & KEYSYM_MASK);
                    248:             if (keycode == 0)
                    249:                 continue;
                    250: 
                    251:             keycode |= (keysym & ~KEYSYM_MASK) >> 16;
                    252:             keycode |= keycode_alt;
                    253:         }
                    254: 
                    255:         if (keycode == -1)
                    256:             continue;
                    257: 
                    258:         if (is_graphic_console()) {
                    259:             /* since terminals don't know about key press and release
                    260:              * events, we need to emit both for each key received */
                    261:             if (keycode & SHIFT)
                    262:                 kbd_put_keycode(SHIFT_CODE);
                    263:             if (keycode & CNTRL)
                    264:                 kbd_put_keycode(CNTRL_CODE);
                    265:             if (keycode & ALT)
                    266:                 kbd_put_keycode(ALT_CODE);
                    267:             if (keycode & ALTGR) {
                    268:                 kbd_put_keycode(SCANCODE_EMUL0);
                    269:                 kbd_put_keycode(ALT_CODE);
                    270:             }
                    271:             if (keycode & GREY)
                    272:                 kbd_put_keycode(GREY_CODE);
                    273:             kbd_put_keycode(keycode & KEY_MASK);
                    274:             if (keycode & GREY)
                    275:                 kbd_put_keycode(GREY_CODE);
                    276:             kbd_put_keycode((keycode & KEY_MASK) | KEY_RELEASE);
                    277:             if (keycode & ALTGR) {
                    278:                 kbd_put_keycode(SCANCODE_EMUL0);
                    279:                 kbd_put_keycode(ALT_CODE | KEY_RELEASE);
                    280:             }
                    281:             if (keycode & ALT)
                    282:                 kbd_put_keycode(ALT_CODE | KEY_RELEASE);
                    283:             if (keycode & CNTRL)
                    284:                 kbd_put_keycode(CNTRL_CODE | KEY_RELEASE);
                    285:             if (keycode & SHIFT)
                    286:                 kbd_put_keycode(SHIFT_CODE | KEY_RELEASE);
                    287:         } else {
                    288:             keysym = curses2qemu[chr];
                    289:             if (keysym == -1)
                    290:                 keysym = chr;
                    291: 
                    292:             kbd_put_keysym(keysym);
                    293:         }
                    294:     }
                    295: }
                    296: 
                    297: static void curses_atexit(void)
                    298: {
                    299:     endwin();
                    300: }
                    301: 
                    302: static void curses_setup(void)
                    303: {
                    304:     int i, colour_default[8] = {
                    305:         COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN,
                    306:         COLOR_RED, COLOR_MAGENTA, COLOR_YELLOW, COLOR_WHITE,
                    307:     };
                    308: 
                    309:     /* input as raw as possible, let everything be interpreted
                    310:      * by the guest system */
                    311:     initscr(); noecho(); intrflush(stdscr, FALSE);
                    312:     nodelay(stdscr, TRUE); nonl(); keypad(stdscr, TRUE);
                    313:     start_color(); raw(); scrollok(stdscr, FALSE);
                    314: 
                    315:     for (i = 0; i < 64; i ++)
                    316:         init_pair(i, colour_default[i & 7], colour_default[i >> 3]);
                    317: }
                    318: 
                    319: static void curses_keyboard_setup(void)
                    320: {
                    321: #if defined(__APPLE__)
                    322:     /* always use generic keymaps */
                    323:     if (!keyboard_layout)
                    324:         keyboard_layout = "en-us";
                    325: #endif
                    326:     if(keyboard_layout) {
                    327:         kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
                    328:         if (!kbd_layout)
                    329:             exit(1);
                    330:     }
                    331: }
                    332: 
                    333: void curses_display_init(DisplayState *ds, int full_screen)
                    334: {
                    335:     DisplayChangeListener *dcl;
                    336: #ifndef _WIN32
                    337:     if (!isatty(1)) {
                    338:         fprintf(stderr, "We need a terminal output\n");
                    339:         exit(1);
                    340:     }
                    341: #endif
                    342: 
                    343:     curses_setup();
                    344:     curses_keyboard_setup();
                    345:     atexit(curses_atexit);
                    346: 
                    347: #ifndef _WIN32
                    348: #if defined(SIGWINCH) && defined(KEY_RESIZE)
                    349:     /* some curses implementations provide a handler, but we
                    350:      * want to be sure this is handled regardless of the library */
                    351:     signal(SIGWINCH, curses_winch_handler);
                    352: #endif
                    353: #endif
                    354: 
                    355:     dcl = (DisplayChangeListener *) qemu_mallocz(sizeof(DisplayChangeListener));
                    356:     dcl->dpy_update = curses_update;
                    357:     dcl->dpy_resize = curses_resize;
                    358:     dcl->dpy_refresh = curses_refresh;
                    359:     dcl->dpy_text_cursor = curses_cursor_position;
                    360:     register_displaychangelistener(ds, dcl);
                    361:     qemu_free_displaysurface(ds);
                    362:     ds->surface = qemu_create_displaysurface_from(640, 400, 0, 0, (uint8_t*) screen);
                    363: 
                    364:     invalidate = 1;
                    365: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.