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

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

unix.superglobalmegacorp.com

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