Annotation of qemu/ui/curses.c, revision 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.