ia64/xen-unstable

view tools/ioemu/sdl.c @ 17186:854b0704962b

ioemu: Slown down refresh interval when SDL is minimized
as that saves us the VGA refresh scanning.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 05 09:43:03 2008 +0000 (2008-03-05)
parents 69bb0c4af952
children e1898e917373
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 #ifndef _WIN32
29 #include <signal.h>
30 #endif
32 static SDL_Surface *screen;
33 static SDL_Surface *shared = NULL;
34 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
35 static int last_vm_running;
36 static int gui_saved_grab;
37 static int gui_fullscreen;
38 static int gui_key_modifier_pressed;
39 static int gui_keysym;
40 static int gui_fullscreen_initial_grab;
41 static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
42 static uint8_t modifiers_state[256];
43 static int width, height;
44 static SDL_Cursor *sdl_cursor_normal;
45 static SDL_Cursor *sdl_cursor_hidden;
46 static int absolute_enabled = 0;
48 static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
49 {
50 // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
51 if (shared) {
52 SDL_Rect rec;
53 rec.x = x;
54 rec.y = y;
55 rec.w = w;
56 rec.h = h;
57 SDL_BlitSurface(shared, &rec, screen, &rec);
58 }
59 SDL_Flip(screen);
60 }
62 static void sdl_setdata(DisplayState *ds, void *pixels)
63 {
64 uint32_t rmask, gmask, bmask, amask = 0;
65 switch (ds->depth) {
66 case 8:
67 rmask = 0x000000E0;
68 gmask = 0x0000001C;
69 bmask = 0x00000003;
70 break;
71 case 16:
72 rmask = 0x0000F800;
73 gmask = 0x000007E0;
74 bmask = 0x0000001F;
75 break;
76 case 24:
77 rmask = 0x00FF0000;
78 gmask = 0x0000FF00;
79 bmask = 0x000000FF;
80 break;
81 case 32:
82 rmask = 0x00FF0000;
83 gmask = 0x0000FF00;
84 bmask = 0x000000FF;
85 break;
86 default:
87 return;
88 }
89 shared = SDL_CreateRGBSurfaceFrom(pixels, width, height, ds->depth, ds->linesize, rmask , gmask, bmask, amask);
90 ds->data = pixels;
91 }
93 static void sdl_resize(DisplayState *ds, int w, int h)
94 {
95 int flags;
97 // printf("resizing to %d %d\n", w, h);
99 flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_DOUBLEBUF|SDL_HWPALETTE;
100 if (gui_fullscreen)
101 flags |= SDL_FULLSCREEN;
103 width = w;
104 height = h;
106 again:
107 screen = SDL_SetVideoMode(w, h, 0, flags);
108 if (!screen) {
109 fprintf(stderr, "Could not open SDL display\n");
110 exit(1);
111 }
112 if (!screen->pixels && (flags & SDL_HWSURFACE) && (flags & SDL_FULLSCREEN)) {
113 flags &= ~SDL_HWSURFACE;
114 goto again;
115 }
117 if (!screen->pixels) {
118 fprintf(stderr, "Could not open SDL display\n");
119 exit(1);
120 }
121 ds->width = w;
122 ds->height = h;
123 if (!ds->shared_buf) {
124 ds->depth = screen->format->BitsPerPixel;
125 if (ds->depth == 32 && screen->format->Rshift == 0) {
126 ds->bgr = 1;
127 } else {
128 ds->bgr = 0;
129 }
130 ds->data = screen->pixels;
131 ds->linesize = screen->pitch;
132 } else {
133 ds->linesize = (ds->depth / 8) * w;
134 }
135 }
137 static void sdl_colourdepth(DisplayState *ds, int depth)
138 {
139 if (!depth || !ds->depth) return;
140 ds->shared_buf = 1;
141 ds->depth = depth;
142 ds->linesize = width * depth / 8;
143 }
145 /* generic keyboard conversion */
147 #include "sdl_keysym.h"
148 #include "keymaps.c"
150 static kbd_layout_t *kbd_layout = NULL;
152 static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
153 {
154 int keysym;
155 /* workaround for X11+SDL bug with AltGR */
156 keysym = ev->keysym.sym;
157 if (keysym == 0 && ev->keysym.scancode == 113)
158 keysym = SDLK_MODE;
159 /* For Japanese key '\' and '|' */
160 if (keysym == 92 && ev->keysym.scancode == 133) {
161 keysym = 0xa5;
162 }
163 return keysym2scancode(kbd_layout, keysym);
164 }
166 /* specific keyboard conversions from scan codes */
168 #if defined(_WIN32)
170 static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
171 {
172 return ev->keysym.scancode;
173 }
175 #else
177 static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
178 {
179 int keycode;
181 keycode = ev->keysym.scancode;
183 if (keycode < 9) {
184 keycode = 0;
185 } else if (keycode < 97) {
186 keycode -= 8; /* just an offset */
187 } else if (keycode < 212) {
188 /* use conversion table */
189 keycode = _translate_keycode(keycode - 97);
190 } else {
191 keycode = 0;
192 }
193 return keycode;
194 }
196 #endif
198 static void reset_keys(void)
199 {
200 int i;
201 for(i = 0; i < 256; i++) {
202 if (modifiers_state[i]) {
203 if (i & 0x80)
204 kbd_put_keycode(0xe0);
205 kbd_put_keycode(i | 0x80);
206 modifiers_state[i] = 0;
207 }
208 }
209 }
211 static void sdl_process_key(SDL_KeyboardEvent *ev)
212 {
213 int keycode, v;
215 if (ev->keysym.sym == SDLK_PAUSE) {
216 /* specific case */
217 v = 0;
218 if (ev->type == SDL_KEYUP)
219 v |= 0x80;
220 kbd_put_keycode(0xe1);
221 kbd_put_keycode(0x1d | v);
222 kbd_put_keycode(0x45 | v);
223 return;
224 }
226 if (kbd_layout) {
227 keycode = sdl_keyevent_to_keycode_generic(ev);
228 } else {
229 keycode = sdl_keyevent_to_keycode(ev);
230 }
232 switch(keycode) {
233 case 0x00:
234 /* sent when leaving window: reset the modifiers state */
235 reset_keys();
236 return;
237 case 0x2a: /* Left Shift */
238 case 0x36: /* Right Shift */
239 case 0x1d: /* Left CTRL */
240 case 0x9d: /* Right CTRL */
241 case 0x38: /* Left ALT */
242 case 0xb8: /* Right ALT */
243 if (ev->type == SDL_KEYUP)
244 modifiers_state[keycode] = 0;
245 else
246 modifiers_state[keycode] = 1;
247 break;
248 case 0x45: /* num lock */
249 case 0x3a: /* caps lock */
250 /* SDL does not send the key up event, so we generate it */
251 kbd_put_keycode(keycode);
252 kbd_put_keycode(keycode | 0x80);
253 return;
254 }
256 /* now send the key code */
257 if (keycode & 0x80)
258 kbd_put_keycode(0xe0);
259 if (ev->type == SDL_KEYUP)
260 kbd_put_keycode(keycode | 0x80);
261 else
262 kbd_put_keycode(keycode & 0x7f);
263 }
265 static void sdl_update_caption(void)
266 {
267 char buf[1024];
268 strcpy(buf, domain_name);
269 if (!vm_running) {
270 strcat(buf, " [Stopped]");
271 }
272 if (gui_grab) {
273 strcat(buf, " - Press Ctrl-Alt to exit grab");
274 }
275 SDL_WM_SetCaption(buf, domain_name);
276 }
278 static void sdl_hide_cursor(void)
279 {
280 if (kbd_mouse_is_absolute()) {
281 SDL_ShowCursor(1);
282 SDL_SetCursor(sdl_cursor_hidden);
283 } else {
284 SDL_ShowCursor(0);
285 }
286 }
288 static void sdl_show_cursor(void)
289 {
290 if (!kbd_mouse_is_absolute()) {
291 SDL_ShowCursor(1);
292 SDL_SetCursor(sdl_cursor_normal);
293 }
294 }
296 static void sdl_grab_start(void)
297 {
298 sdl_hide_cursor();
299 SDL_WM_GrabInput(SDL_GRAB_ON);
300 /* dummy read to avoid moving the mouse */
301 SDL_GetRelativeMouseState(NULL, NULL);
302 gui_grab = 1;
303 sdl_update_caption();
304 }
306 static void sdl_grab_end(void)
307 {
308 SDL_WM_GrabInput(SDL_GRAB_OFF);
309 sdl_show_cursor();
310 gui_grab = 0;
311 sdl_update_caption();
312 }
314 static void sdl_send_mouse_event(int dx, int dy, int dz, int state)
315 {
316 int buttons = 0;
317 if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
318 buttons |= MOUSE_EVENT_LBUTTON;
319 if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
320 buttons |= MOUSE_EVENT_RBUTTON;
321 if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
322 buttons |= MOUSE_EVENT_MBUTTON;
324 if (kbd_mouse_is_absolute()) {
325 if (!absolute_enabled) {
326 sdl_hide_cursor();
327 if (gui_grab) {
328 sdl_grab_end();
329 }
330 absolute_enabled = 1;
331 }
333 SDL_GetMouseState(&dx, &dy);
334 dx = dx * 0x7FFF / width;
335 dy = dy * 0x7FFF / height;
336 } else if (absolute_enabled) {
337 sdl_show_cursor();
338 absolute_enabled = 0;
339 }
341 kbd_mouse_event(dx, dy, dz, buttons);
342 }
344 static void toggle_full_screen(DisplayState *ds)
345 {
346 gui_fullscreen = !gui_fullscreen;
347 sdl_resize(ds, screen->w, screen->h);
348 if (gui_fullscreen) {
349 gui_saved_grab = gui_grab;
350 sdl_grab_start();
351 } else {
352 if (!gui_saved_grab)
353 sdl_grab_end();
354 }
355 vga_hw_invalidate();
356 vga_hw_update();
357 }
359 static void sdl_refresh(DisplayState *ds)
360 {
361 SDL_Event ev1, *ev = &ev1;
362 int mod_state;
364 if (last_vm_running != vm_running) {
365 last_vm_running = vm_running;
366 sdl_update_caption();
367 }
369 vga_hw_update();
371 while (SDL_PollEvent(ev)) {
372 switch (ev->type) {
373 case SDL_VIDEOEXPOSE:
374 sdl_update(ds, 0, 0, screen->w, screen->h);
375 break;
376 case SDL_KEYDOWN:
377 case SDL_KEYUP:
378 if (ev->type == SDL_KEYDOWN) {
379 mod_state = (SDL_GetModState() & gui_grab_code) ==
380 gui_grab_code;
381 gui_key_modifier_pressed = mod_state;
382 if (gui_key_modifier_pressed) {
383 int keycode;
384 keycode = sdl_keyevent_to_keycode(&ev->key);
385 switch(keycode) {
386 case 0x21: /* 'f' key on US keyboard */
387 toggle_full_screen(ds);
388 gui_keysym = 1;
389 break;
390 case 0x02 ... 0x0a: /* '1' to '9' keys */
391 /* Reset the modifiers sent to the current console */
392 reset_keys();
393 console_select(keycode - 0x02);
394 if (!is_graphic_console()) {
395 /* display grab if going to a text console */
396 if (gui_grab)
397 sdl_grab_end();
398 }
399 gui_keysym = 1;
400 break;
401 default:
402 break;
403 }
404 } else if (!is_graphic_console()) {
405 int keysym;
406 keysym = 0;
407 if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
408 switch(ev->key.keysym.sym) {
409 case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
410 case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
411 case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
412 case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
413 case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
414 case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
415 case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
416 case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
417 default: break;
418 }
419 } else {
420 switch(ev->key.keysym.sym) {
421 case SDLK_UP: keysym = QEMU_KEY_UP; break;
422 case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
423 case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
424 case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
425 case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
426 case SDLK_END: keysym = QEMU_KEY_END; break;
427 case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
428 case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
429 case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break; case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
430 default: break;
431 }
432 }
433 if (keysym) {
434 kbd_put_keysym(keysym);
435 } else if (ev->key.keysym.unicode != 0) {
436 kbd_put_keysym(ev->key.keysym.unicode);
437 }
438 }
439 } else if (ev->type == SDL_KEYUP) {
440 mod_state = (ev->key.keysym.mod & gui_grab_code);
441 if (!mod_state) {
442 if (gui_key_modifier_pressed) {
443 gui_key_modifier_pressed = 0;
444 if (gui_keysym == 0) {
445 /* exit/enter grab if pressing Ctrl-Alt */
446 if (!gui_grab) {
447 /* if the application is not active,
448 do not try to enter grab state. It
449 prevents
450 'SDL_WM_GrabInput(SDL_GRAB_ON)'
451 from blocking all the application
452 (SDL bug). */
453 if (SDL_GetAppState() & SDL_APPACTIVE)
454 sdl_grab_start();
455 } else {
456 sdl_grab_end();
457 }
458 /* SDL does not send back all the
459 modifiers key, so we must correct it */
460 reset_keys();
461 break;
462 }
463 gui_keysym = 0;
464 }
465 }
466 }
467 if (is_graphic_console() && !gui_keysym)
468 sdl_process_key(&ev->key);
469 break;
470 case SDL_QUIT:
471 if (!no_quit) {
472 qemu_system_shutdown_request();
473 }
474 break;
475 case SDL_MOUSEMOTION:
476 if (gui_grab || kbd_mouse_is_absolute() ||
477 absolute_enabled) {
478 int dx, dy, state;
479 state = SDL_GetRelativeMouseState(&dx, &dy);
480 sdl_send_mouse_event(dx, dy, 0, state);
481 }
482 break;
483 case SDL_MOUSEBUTTONUP:
484 if (gui_grab || kbd_mouse_is_absolute()) {
485 int dx, dy, state;
486 state = SDL_GetRelativeMouseState(&dx, &dy);
487 sdl_send_mouse_event(dx, dy, 0, state);
488 }
489 break;
490 case SDL_MOUSEBUTTONDOWN:
491 {
492 SDL_MouseButtonEvent *bev = &ev->button;
493 if (!gui_grab && !kbd_mouse_is_absolute()) {
494 if (ev->type == SDL_MOUSEBUTTONDOWN &&
495 (bev->state & SDL_BUTTON_LMASK)) {
496 /* start grabbing all events */
497 sdl_grab_start();
498 }
499 } else {
500 int dx, dy, dz, state;
501 dz = 0;
502 state = SDL_GetRelativeMouseState(&dx, &dy);
503 #ifdef SDL_BUTTON_WHEELUP
504 if (bev->button == SDL_BUTTON_WHEELUP) {
505 dz = -1;
506 } else if (bev->button == SDL_BUTTON_WHEELDOWN) {
507 dz = 1;
508 } else {
509 state = bev->button | state;
510 }
511 #endif
512 sdl_send_mouse_event(dx, dy, dz, state);
513 }
514 }
515 break;
516 case SDL_ACTIVEEVENT:
517 if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
518 !ev->active.gain && !gui_fullscreen_initial_grab) {
519 sdl_grab_end();
520 }
521 if (ev->active.state & SDL_APPACTIVE) {
522 if (ev->active.gain) {
523 /* Back to default interval */
524 ds->gui_timer_interval = 0;
525 } else {
526 /* Sleeping interval */
527 ds->gui_timer_interval = 500;
528 }
529 }
530 break;
531 default:
532 break;
533 }
534 }
535 }
537 static void sdl_cleanup(void)
538 {
539 SDL_Quit();
540 }
542 void sdl_display_init(DisplayState *ds, int full_screen)
543 {
544 int flags;
545 uint8_t data = 0;
547 #if defined(__APPLE__)
548 /* always use generic keymaps */
549 if (!keyboard_layout)
550 keyboard_layout = "en-us";
551 #endif
552 if(keyboard_layout) {
553 kbd_layout = init_keyboard_layout(keyboard_layout);
554 if (!kbd_layout)
555 exit(1);
556 }
558 flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
559 if (SDL_Init (flags)) {
560 fprintf(stderr, "Could not initialize SDL - exiting\n");
561 exit(1);
562 }
563 #ifndef _WIN32
564 /* NOTE: we still want Ctrl-C to work, so we undo the SDL redirections */
565 signal(SIGINT, SIG_DFL);
566 signal(SIGQUIT, SIG_DFL);
567 #endif
569 ds->dpy_update = sdl_update;
570 ds->dpy_resize = sdl_resize;
571 ds->dpy_refresh = sdl_refresh;
572 ds->dpy_colourdepth = sdl_colourdepth;
573 ds->dpy_setdata = sdl_setdata;
575 sdl_resize(ds, 640, 400);
576 sdl_update_caption();
577 SDL_EnableKeyRepeat(250, 50);
578 SDL_EnableUNICODE(1);
579 gui_grab = 0;
581 sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
582 sdl_cursor_normal = SDL_GetCursor();
584 atexit(sdl_cleanup);
585 if (full_screen) {
586 gui_fullscreen = 1;
587 gui_fullscreen_initial_grab = 1;
588 sdl_grab_start();
589 }
590 }