ia64/xen-unstable

view tools/ioemu/sdl.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 8e5fc5fe636c
children b8ba1bbba882
line source
1 /*
2 * QEMU SDL display driver
3 *
4 * Copyright (c) 2003 Fabrice Bellard
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 "vl.h"
26 #include <SDL.h>
28 /* keyboard stuff */
29 #include <SDL_keysym.h>
30 #include "keysym_adapter_sdl.h"
31 #include "keyboard_rdesktop.c"
33 #ifndef _WIN32
34 #include <signal.h>
35 #endif
37 #if defined(__APPLE__)
38 #define CONFIG_SDL_GENERIC_KBD
39 #endif
41 static SDL_Surface *screen;
42 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
43 static int last_vm_running;
44 static int gui_saved_grab;
45 static int gui_fullscreen;
46 static int gui_key_modifier_pressed;
47 static int gui_keysym;
48 static void* kbd_layout=0;
49 static int gui_fullscreen_initial_grab;
50 static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
51 static uint8_t modifiers_state[256];
53 SDL_PixelFormat* sdl_get_format() {
54 return screen->format;
55 }
57 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
58 {
59 SDL_UpdateRect(screen, x, y, w, h);
60 }
62 static void sdl_resize(DisplayState *ds, int w, int h)
63 {
64 int flags;
66 // printf("resizing to %d %d\n", w, h);
68 flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
69 flags |= SDL_RESIZABLE;
70 if (gui_fullscreen)
71 flags |= SDL_FULLSCREEN;
72 screen = SDL_SetVideoMode(w, h, 0, flags);
73 if (!screen) {
74 fprintf(stderr, "Could not open SDL display\n");
75 exit(1);
76 }
77 ds->data = screen->pixels;
78 ds->linesize = screen->pitch;
79 ds->depth = screen->format->BitsPerPixel;
80 ds->width = w;
81 ds->height = h;
82 }
84 #ifdef CONFIG_SDL_GENERIC_KBD
86 /* XXX: use keymap tables defined in the VNC patch because the
87 following code suppose you have a US keyboard. */
89 static const uint8_t scancodes[SDLK_LAST] = {
90 [SDLK_ESCAPE] = 0x01,
91 [SDLK_1] = 0x02,
92 [SDLK_2] = 0x03,
93 [SDLK_3] = 0x04,
94 [SDLK_4] = 0x05,
95 [SDLK_5] = 0x06,
96 [SDLK_6] = 0x07,
97 [SDLK_7] = 0x08,
98 [SDLK_8] = 0x09,
99 [SDLK_9] = 0x0a,
100 [SDLK_0] = 0x0b,
101 [SDLK_MINUS] = 0x0c,
102 [SDLK_EQUALS] = 0x0d,
103 [SDLK_BACKSPACE] = 0x0e,
104 [SDLK_TAB] = 0x0f,
105 [SDLK_q] = 0x10,
106 [SDLK_w] = 0x11,
107 [SDLK_e] = 0x12,
108 [SDLK_r] = 0x13,
109 [SDLK_t] = 0x14,
110 [SDLK_y] = 0x15,
111 [SDLK_u] = 0x16,
112 [SDLK_i] = 0x17,
113 [SDLK_o] = 0x18,
114 [SDLK_p] = 0x19,
115 [SDLK_LEFTBRACKET] = 0x1a,
116 [SDLK_RIGHTBRACKET] = 0x1b,
117 [SDLK_RETURN] = 0x1c,
118 [SDLK_LCTRL] = 0x1d,
119 [SDLK_a] = 0x1e,
120 [SDLK_s] = 0x1f,
121 [SDLK_d] = 0x20,
122 [SDLK_f] = 0x21,
123 [SDLK_g] = 0x22,
124 [SDLK_h] = 0x23,
125 [SDLK_j] = 0x24,
126 [SDLK_k] = 0x25,
127 [SDLK_l] = 0x26,
128 [SDLK_SEMICOLON] = 0x27,
129 [SDLK_QUOTE] = 0x28,
130 [SDLK_BACKQUOTE] = 0x29,
131 [SDLK_LSHIFT] = 0x2a,
132 [SDLK_BACKSLASH] = 0x2b,
133 [SDLK_z] = 0x2c,
134 [SDLK_x] = 0x2d,
135 [SDLK_c] = 0x2e,
136 [SDLK_v] = 0x2f,
137 [SDLK_b] = 0x30,
138 [SDLK_n] = 0x31,
139 [SDLK_m] = 0x32,
140 [SDLK_COMMA] = 0x33,
141 [SDLK_PERIOD] = 0x34,
142 [SDLK_SLASH] = 0x35,
143 [SDLK_KP_MULTIPLY] = 0x37,
144 [SDLK_LALT] = 0x38,
145 [SDLK_SPACE] = 0x39,
146 [SDLK_CAPSLOCK] = 0x3a,
147 [SDLK_F1] = 0x3b,
148 [SDLK_F2] = 0x3c,
149 [SDLK_F3] = 0x3d,
150 [SDLK_F4] = 0x3e,
151 [SDLK_F5] = 0x3f,
152 [SDLK_F6] = 0x40,
153 [SDLK_F7] = 0x41,
154 [SDLK_F8] = 0x42,
155 [SDLK_F9] = 0x43,
156 [SDLK_F10] = 0x44,
157 [SDLK_NUMLOCK] = 0x45,
158 [SDLK_SCROLLOCK] = 0x46,
159 [SDLK_KP7] = 0x47,
160 [SDLK_KP8] = 0x48,
161 [SDLK_KP9] = 0x49,
162 [SDLK_KP_MINUS] = 0x4a,
163 [SDLK_KP4] = 0x4b,
164 [SDLK_KP5] = 0x4c,
165 [SDLK_KP6] = 0x4d,
166 [SDLK_KP_PLUS] = 0x4e,
167 [SDLK_KP1] = 0x4f,
168 [SDLK_KP2] = 0x50,
169 [SDLK_KP3] = 0x51,
170 [SDLK_KP0] = 0x52,
171 [SDLK_KP_PERIOD] = 0x53,
172 [SDLK_PRINT] = 0x54,
173 [SDLK_LMETA] = 0x56,
175 [SDLK_KP_ENTER] = 0x9c,
176 [SDLK_KP_DIVIDE] = 0xb5,
178 [SDLK_UP] = 0xc8,
179 [SDLK_DOWN] = 0xd0,
180 [SDLK_RIGHT] = 0xcd,
181 [SDLK_LEFT] = 0xcb,
182 [SDLK_INSERT] = 0xd2,
183 [SDLK_HOME] = 0xc7,
184 [SDLK_END] = 0xcf,
185 [SDLK_PAGEUP] = 0xc9,
186 [SDLK_PAGEDOWN] = 0xd1,
187 [SDLK_DELETE] = 0xd3,
188 };
190 static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
191 {
192 return scancodes[ev->keysym.sym];
193 }
195 #elif defined(_WIN32)
197 static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
198 {
199 return ev->keysym.scancode;
200 }
202 #else
204 static const uint8_t x_keycode_to_pc_keycode[61] = {
205 0xc7, /* 97 Home */
206 0xc8, /* 98 Up */
207 0xc9, /* 99 PgUp */
208 0xcb, /* 100 Left */
209 0x4c, /* 101 KP-5 */
210 0xcd, /* 102 Right */
211 0xcf, /* 103 End */
212 0xd0, /* 104 Down */
213 0xd1, /* 105 PgDn */
214 0xd2, /* 106 Ins */
215 0xd3, /* 107 Del */
216 0x9c, /* 108 Enter */
217 0x9d, /* 109 Ctrl-R */
218 0x0, /* 110 Pause */
219 0xb7, /* 111 Print */
220 0xb5, /* 112 Divide */
221 0xb8, /* 113 Alt-R */
222 0xc6, /* 114 Break */
223 0x0, /* 115 */
224 0x0, /* 116 */
225 0x0, /* 117 */
226 0x0, /* 118 */
227 0x0, /* 119 */
228 0x70, /* 120 Hiragana_Katakana */
229 0x0, /* 121 */
230 0x0, /* 122 */
231 0x73, /* 123 backslash */
232 0x0, /* 124 */
233 0x0, /* 125 */
234 0x0, /* 126 */
235 0x0, /* 127 */
236 0x0, /* 128 */
237 0x79, /* 129 Henkan */
238 0x0, /* 130 */
239 0x7b, /* 131 Muhenkan */
240 0x0, /* 132 */
241 0x7d, /* 133 Yen */
242 0x0, /* 134 */
243 0x0, /* 135 */
244 0x47, /* 136 KP_7 */
245 0x48, /* 137 KP_8 */
246 0x49, /* 138 KP_9 */
247 0x4b, /* 139 KP_4 */
248 0x4c, /* 140 KP_5 */
249 0x4d, /* 141 KP_6 */
250 0x4f, /* 142 KP_1 */
251 0x50, /* 143 KP_2 */
252 0x51, /* 144 KP_3 */
253 0x52, /* 145 KP_0 */
254 0x53, /* 146 KP_. */
255 0x47, /* 147 KP_HOME */
256 0x48, /* 148 KP_UP */
257 0x49, /* 149 KP_PgUp */
258 0x4b, /* 150 KP_Left */
259 0x4c, /* 151 KP_ */
260 0x4d, /* 152 KP_Right */
261 0x4f, /* 153 KP_End */
262 0x50, /* 154 KP_Down */
263 0x51, /* 155 KP_PgDn */
264 0x52, /* 156 KP_Ins */
265 0x53, /* 157 KP_Del */
266 };
268 static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
269 {
270 int keycode;
272 keycode = ev->keysym.scancode;
274 if (keycode < 9) {
275 keycode = 0;
276 } else if (keycode < 97) {
277 keycode -= 8; /* just an offset */
278 } else if (keycode < 158) {
279 /* use conversion table */
280 keycode = x_keycode_to_pc_keycode[keycode - 97];
281 } else {
282 keycode = 0;
283 }
284 return keycode;
285 }
287 #endif
289 static void reset_keys(void)
290 {
291 int i;
292 for(i = 0; i < 256; i++) {
293 if (modifiers_state[i]) {
294 if (i & 0x80)
295 kbd_put_keycode(0xe0);
296 kbd_put_keycode(i | 0x80);
297 modifiers_state[i] = 0;
298 }
299 }
300 }
302 static void sdl_process_key(SDL_KeyboardEvent *ev)
303 {
304 int keycode, v;
306 if(kbd_layout)
307 keycode=keysym2scancode(kbd_layout, ev->keysym.sym);
308 else {
310 if (ev->keysym.sym == SDLK_PAUSE) {
311 /* specific case */
312 v = 0;
313 if (ev->type == SDL_KEYUP)
314 v |= 0x80;
315 kbd_put_keycode(0xe1);
316 kbd_put_keycode(0x1d | v);
317 kbd_put_keycode(0x45 | v);
318 return;
319 }
321 /* XXX: not portable, but avoids complicated mappings */
322 keycode = sdl_keyevent_to_keycode(ev);
324 switch(keycode) {
325 case 0x00:
326 /* sent when leaving window: reset the modifiers state */
327 reset_keys();
328 return;
329 case 0x2a: /* Left Shift */
330 case 0x36: /* Right Shift */
331 case 0x1d: /* Left CTRL */
332 case 0x9d: /* Right CTRL */
333 case 0x38: /* Left ALT */
334 case 0xb8: /* Right ALT */
335 if (ev->type == SDL_KEYUP)
336 modifiers_state[keycode] = 0;
337 else
338 modifiers_state[keycode] = 1;
339 break;
340 case 0x45: /* num lock */
341 case 0x3a: /* caps lock */
342 /* SDL does not send the key up event, so we generate it */
343 kbd_put_keycode(keycode);
344 kbd_put_keycode(keycode | 0x80);
345 return;
346 }
347 }
349 /* now send the key code */
350 if (keycode & 0x80)
351 kbd_put_keycode(0xe0);
352 if (ev->type == SDL_KEYUP)
353 kbd_put_keycode(keycode | 0x80);
354 else
355 kbd_put_keycode(keycode & 0x7f);
356 }
358 static void sdl_update_caption(void)
359 {
360 char buf[1024];
361 strcpy(buf, "VTXen");
362 if (!vm_running) {
363 strcat(buf, " [Stopped]");
364 }
365 if (gui_grab) {
366 strcat(buf, " - Press Ctrl-Alt to exit grab");
367 }
368 SDL_WM_SetCaption(buf, "VTXen");
369 }
371 static void sdl_grab_start(void)
372 {
373 SDL_ShowCursor(0);
374 SDL_WM_GrabInput(SDL_GRAB_ON);
375 /* dummy read to avoid moving the mouse */
376 SDL_GetRelativeMouseState(NULL, NULL);
377 gui_grab = 1;
378 sdl_update_caption();
379 }
381 static void sdl_grab_end(void)
382 {
383 SDL_WM_GrabInput(SDL_GRAB_OFF);
384 SDL_ShowCursor(1);
385 gui_grab = 0;
386 sdl_update_caption();
387 }
389 static void sdl_send_mouse_event(void)
390 {
391 int dx, dy, dz, state, buttons;
392 state = SDL_GetRelativeMouseState(&dx, &dy);
393 buttons = 0;
394 if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
395 buttons |= MOUSE_EVENT_LBUTTON;
396 if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
397 buttons |= MOUSE_EVENT_RBUTTON;
398 if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
399 buttons |= MOUSE_EVENT_MBUTTON;
400 /* XXX: test wheel */
401 dz = 0;
402 #ifdef SDL_BUTTON_WHEELUP
403 if (state & SDL_BUTTON(SDL_BUTTON_WHEELUP))
404 dz--;
405 if (state & SDL_BUTTON(SDL_BUTTON_WHEELDOWN))
406 dz++;
407 #endif
408 kbd_mouse_event(dx, dy, dz, buttons);
409 }
411 static void toggle_full_screen(DisplayState *ds)
412 {
413 gui_fullscreen = !gui_fullscreen;
414 sdl_resize(ds, screen->w, screen->h);
415 if (gui_fullscreen) {
416 gui_saved_grab = gui_grab;
417 sdl_grab_start();
418 } else {
419 if (!gui_saved_grab)
420 sdl_grab_end();
421 }
422 vga_invalidate_display();
423 vga_update_display();
424 }
426 static void sdl_refresh(DisplayState *ds)
427 {
428 SDL_Event ev1, *ev = &ev1;
429 int mod_state;
431 if (last_vm_running != vm_running) {
432 last_vm_running = vm_running;
433 sdl_update_caption();
434 }
436 if (is_active_console(vga_console))
437 vga_update_display();
439 while (SDL_PollEvent(ev)) {
440 switch (ev->type) {
441 case SDL_VIDEOEXPOSE:
442 sdl_update(ds, 0, 0, screen->w, screen->h);
443 break;
444 case SDL_KEYDOWN:
445 case SDL_KEYUP:
446 if (ev->type == SDL_KEYDOWN) {
447 mod_state = (SDL_GetModState() & gui_grab_code) ==
448 gui_grab_code;
449 gui_key_modifier_pressed = mod_state;
450 if (gui_key_modifier_pressed) {
451 int keycode;
452 keycode = sdl_keyevent_to_keycode(&ev->key);
453 switch(keycode) {
454 case 0x21: /* 'f' key on US keyboard */
455 toggle_full_screen(ds);
456 gui_keysym = 1;
457 break;
458 case 0x02 ... 0x0a: /* '1' to '9' keys */
459 console_select(keycode - 0x02);
460 if (is_active_console(vga_console)) {
461 /* tell the vga console to redisplay itself */
462 vga_invalidate_display();
463 } else {
464 /* display grab if going to a text console */
465 if (gui_grab)
466 sdl_grab_end();
467 }
468 gui_keysym = 1;
469 break;
470 default:
471 break;
472 }
473 } else if (!is_active_console(vga_console)) {
474 int keysym;
475 keysym = 0;
476 if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
477 switch(ev->key.keysym.sym) {
478 case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
479 case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
480 case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
481 case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
482 case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
483 case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
484 case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
485 case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
486 default: break;
487 }
488 } else {
489 switch(ev->key.keysym.sym) {
490 case SDLK_UP: keysym = QEMU_KEY_UP; break;
491 case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
492 case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
493 case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
494 case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
495 case SDLK_END: keysym = QEMU_KEY_END; break;
496 case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
497 case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
498 case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break; case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
499 default: break;
500 }
501 }
502 if (keysym) {
503 kbd_put_keysym(keysym);
504 } else if (ev->key.keysym.unicode != 0) {
505 kbd_put_keysym(ev->key.keysym.unicode);
506 }
507 }
508 } else if (ev->type == SDL_KEYUP) {
509 mod_state = (ev->key.keysym.mod & gui_grab_code);
510 if (!mod_state) {
511 if (gui_key_modifier_pressed) {
512 gui_key_modifier_pressed = 0;
513 if (gui_keysym == 0) {
514 /* exit/enter grab if pressing Ctrl-Alt */
515 if (!gui_grab)
516 sdl_grab_start();
517 else
518 sdl_grab_end();
519 /* SDL does not send back all the
520 modifiers key, so we must correct it */
521 reset_keys();
522 break;
523 }
524 gui_keysym = 0;
525 }
526 }
527 }
528 if (is_active_console(vga_console))
529 sdl_process_key(&ev->key);
530 break;
531 case SDL_QUIT:
532 qemu_system_shutdown_request();
533 break;
534 case SDL_MOUSEMOTION:
535 if (gui_grab) {
536 sdl_send_mouse_event();
537 }
538 break;
539 case SDL_MOUSEBUTTONDOWN:
540 case SDL_MOUSEBUTTONUP:
541 {
542 SDL_MouseButtonEvent *bev = &ev->button;
543 if (!gui_grab) {
544 if (ev->type == SDL_MOUSEBUTTONDOWN &&
545 (bev->state & SDL_BUTTON_LMASK)) {
546 /* start grabbing all events */
547 sdl_grab_start();
548 }
549 } else {
550 sdl_send_mouse_event();
551 }
552 }
553 break;
554 case SDL_ACTIVEEVENT:
555 if (gui_grab && (ev->active.gain & SDL_ACTIVEEVENTMASK) == 0 &&
556 !gui_fullscreen_initial_grab) {
557 sdl_grab_end();
558 }
559 break;
560 default:
561 break;
562 }
563 }
564 }
566 static void sdl_cleanup(void)
567 {
568 SDL_Quit();
569 }
571 void sdl_display_init(DisplayState *ds, int full_screen)
572 {
573 int flags;
575 if(keyboard_layout)
576 kbd_layout=init_keyboard_layout(keyboard_layout);
578 flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
579 if (SDL_Init (flags)) {
580 fprintf(stderr, "Could not initialize SDL - exiting\n");
581 exit(1);
582 }
583 #ifndef _WIN32
584 /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
585 signal(SIGINT, SIG_DFL);
586 signal(SIGQUIT, SIG_DFL);
587 #endif
589 ds->dpy_update = sdl_update;
590 ds->dpy_resize = sdl_resize;
591 ds->dpy_refresh = sdl_refresh;
593 sdl_resize(ds, 640, 400);
594 sdl_update_caption();
595 SDL_EnableKeyRepeat(250, 50);
596 SDL_EnableUNICODE(1);
597 gui_grab = 0;
599 atexit(sdl_cleanup);
600 if (full_screen) {
601 gui_fullscreen = 1;
602 gui_fullscreen_initial_grab = 1;
603 sdl_grab_start();
604 }
605 }