]> Git Repo - qemu.git/blob - ui/sdl.c
hw/display/milkymist-tmu2: Move inlined code from header to source
[qemu.git] / ui / sdl.c
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
25 /* Avoid compiler warning because macro is redefined in SDL_syswm.h. */
26 #undef WIN32_LEAN_AND_MEAN
27
28 #include "qemu/osdep.h"
29 #include <SDL.h>
30 #include <SDL_syswm.h>
31
32 #include "qapi/error.h"
33 #include "qemu-common.h"
34 #include "qemu/cutils.h"
35 #include "ui/console.h"
36 #include "ui/input.h"
37 #include "sysemu/sysemu.h"
38 #ifndef WIN32
39 #include "x_keymap.h"
40 #endif
41 #include "sdl_zoom.h"
42
43 static DisplayChangeListener *dcl;
44 static DisplaySurface *surface;
45 static DisplayOptions *opts;
46 static SDL_Surface *real_screen;
47 static SDL_Surface *guest_screen = NULL;
48 static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
49 static int last_vm_running;
50 static bool gui_saved_scaling;
51 static int gui_saved_width;
52 static int gui_saved_height;
53 static int gui_saved_grab;
54 static int gui_fullscreen;
55 static int gui_key_modifier_pressed;
56 static int gui_keysym;
57 static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
58 static uint8_t modifiers_state[256];
59 static SDL_Cursor *sdl_cursor_normal;
60 static SDL_Cursor *sdl_cursor_hidden;
61 static int absolute_enabled = 0;
62 static int guest_cursor = 0;
63 static int guest_x, guest_y;
64 static SDL_Cursor *guest_sprite = NULL;
65 static SDL_PixelFormat host_format;
66 static int scaling_active = 0;
67 static Notifier mouse_mode_notifier;
68 static int idle_counter;
69 static const guint16 *keycode_map;
70 static size_t keycode_maplen;
71
72 #define SDL_REFRESH_INTERVAL_BUSY 10
73 #define SDL_MAX_IDLE_COUNT (2 * GUI_REFRESH_INTERVAL_DEFAULT \
74                             / SDL_REFRESH_INTERVAL_BUSY + 1)
75
76 #if 0
77 #define DEBUG_SDL
78 #endif
79
80 static void sdl_update(DisplayChangeListener *dcl,
81                        int x, int y, int w, int h)
82 {
83     SDL_Rect rec;
84     rec.x = x;
85     rec.y = y;
86     rec.w = w;
87     rec.h = h;
88
89 #ifdef DEBUG_SDL
90     printf("SDL: Updating x=%d y=%d w=%d h=%d (scaling: %d)\n",
91            x, y, w, h, scaling_active);
92 #endif
93
94     if (guest_screen) {
95         if (!scaling_active) {
96             SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
97         } else {
98             if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
99                 fprintf(stderr, "Zoom blit failed\n");
100                 exit(1);
101             }
102         }
103     } 
104     SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
105 }
106
107 static void do_sdl_resize(int width, int height, int bpp)
108 {
109     int flags;
110     SDL_Surface *tmp_screen;
111
112 #ifdef DEBUG_SDL
113     printf("SDL: Resizing to %dx%d bpp %d\n", width, height, bpp);
114 #endif
115
116     flags = SDL_HWSURFACE | SDL_ASYNCBLIT | SDL_HWACCEL;
117     if (gui_fullscreen) {
118         flags |= SDL_FULLSCREEN;
119     } else {
120         flags |= SDL_RESIZABLE;
121     }
122     if (no_frame) {
123         flags |= SDL_NOFRAME;
124     }
125
126     tmp_screen = SDL_SetVideoMode(width, height, bpp, flags);
127     if (!real_screen) {
128         if (!tmp_screen) {
129             fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n",
130                     width, height, bpp, SDL_GetError());
131             exit(1);
132         }
133     } else {
134         /*
135          * Revert to the previous video mode if the change of resizing or
136          * resolution failed.
137          */
138         if (!tmp_screen) {
139             fprintf(stderr, "Failed to set SDL display (%dx%dx%d): %s\n",
140                     width, height, bpp, SDL_GetError());
141             return;
142         }
143     }
144
145     real_screen = tmp_screen;
146 }
147
148 static void sdl_switch(DisplayChangeListener *dcl,
149                        DisplaySurface *new_surface)
150 {
151     PixelFormat pf;
152
153     /* temporary hack: allows to call sdl_switch to handle scaling changes */
154     if (new_surface) {
155         surface = new_surface;
156     }
157     pf = qemu_pixelformat_from_pixman(surface->format);
158
159     if (!scaling_active) {
160         do_sdl_resize(surface_width(surface), surface_height(surface), 0);
161     } else if (real_screen->format->BitsPerPixel !=
162                surface_bits_per_pixel(surface)) {
163         do_sdl_resize(real_screen->w, real_screen->h,
164                       surface_bits_per_pixel(surface));
165     }
166
167     if (guest_screen != NULL) {
168         SDL_FreeSurface(guest_screen);
169     }
170
171 #ifdef DEBUG_SDL
172     printf("SDL: Creating surface with masks: %08x %08x %08x %08x\n",
173            pf.rmask, pf.gmask, pf.bmask, pf.amask);
174 #endif
175
176     guest_screen = SDL_CreateRGBSurfaceFrom
177         (surface_data(surface),
178          surface_width(surface), surface_height(surface),
179          surface_bits_per_pixel(surface), surface_stride(surface),
180          pf.rmask, pf.gmask,
181          pf.bmask, pf.amask);
182 }
183
184 static bool sdl_check_format(DisplayChangeListener *dcl,
185                              pixman_format_code_t format)
186 {
187     /*
188      * We let SDL convert for us a few more formats than,
189      * the native ones. Thes are the ones I have tested.
190      */
191     return (format == PIXMAN_x8r8g8b8 ||
192             format == PIXMAN_b8g8r8x8 ||
193             format == PIXMAN_x1r5g5b5 ||
194             format == PIXMAN_r5g6b5);
195 }
196
197 /* generic keyboard conversion */
198
199 #include "sdl_keysym.h"
200
201 static kbd_layout_t *kbd_layout = NULL;
202
203 static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
204 {
205     bool shift = modifiers_state[0x2a] || modifiers_state[0x36];
206     bool altgr = modifiers_state[0xb8];
207     bool ctrl  = modifiers_state[0x1d] || modifiers_state[0x9d];
208     int keysym;
209     /* workaround for X11+SDL bug with AltGR */
210     keysym = ev->keysym.sym;
211     if (keysym == 0 && ev->keysym.scancode == 113)
212         keysym = SDLK_MODE;
213     /* For Japanese key '\' and '|' */
214     if (keysym == 92 && ev->keysym.scancode == 133) {
215         keysym = 0xa5;
216     }
217     return keysym2scancode(kbd_layout, keysym,
218                            shift, altgr, ctrl) & SCANCODE_KEYMASK;
219 }
220
221
222 static const guint16 *sdl_get_keymap(size_t *maplen)
223 {
224 #if defined(WIN32)
225     *maplen = qemu_input_map_atset1_to_qcode_len;
226     return qemu_input_map_atset1_to_qcode;
227 #else
228 #if defined(SDL_VIDEO_DRIVER_X11)
229     SDL_SysWMinfo info;
230
231     SDL_VERSION(&info.version);
232     if (SDL_GetWMInfo(&info) > 0) {
233         return qemu_xkeymap_mapping_table(
234             info.info.x11.display, maplen);
235     }
236 #endif
237     g_warning("Unsupported SDL video driver / platform.\n"
238               "Assuming Linux KBD scancodes, but probably wrong.\n"
239               "Please report to [email protected]\n"
240               "including the following information:\n"
241               "\n"
242               "  - Operating system\n"
243               "  - SDL video driver\n");
244     *maplen = qemu_input_map_xorgkbd_to_qcode_len;
245     return qemu_input_map_xorgkbd_to_qcode;
246 #endif
247 }
248
249 static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
250 {
251     int qcode;
252     if (!keycode_map) {
253         return 0;
254     }
255     if (ev->keysym.scancode > keycode_maplen) {
256         return 0;
257     }
258
259     qcode = keycode_map[ev->keysym.scancode];
260
261     if (qcode > qemu_input_map_qcode_to_qnum_len) {
262         return 0;
263     }
264
265     return qemu_input_map_qcode_to_qnum[qcode];
266 }
267
268 static void reset_keys(void)
269 {
270     int i;
271     for(i = 0; i < 256; i++) {
272         if (modifiers_state[i]) {
273             qemu_input_event_send_key_number(dcl->con, i, false);
274             modifiers_state[i] = 0;
275         }
276     }
277 }
278
279 static void sdl_process_key(SDL_KeyboardEvent *ev)
280 {
281     int keycode;
282
283     if (ev->keysym.sym == SDLK_PAUSE) {
284         /* specific case */
285         qemu_input_event_send_key_qcode(dcl->con, Q_KEY_CODE_PAUSE,
286                                         ev->type == SDL_KEYDOWN);
287         return;
288     }
289
290     if (kbd_layout) {
291         keycode = sdl_keyevent_to_keycode_generic(ev);
292     } else {
293         keycode = sdl_keyevent_to_keycode(ev);
294     }
295
296     switch(keycode) {
297     case 0x00:
298         /* sent when leaving window: reset the modifiers state */
299         reset_keys();
300         return;
301     case 0x2a:                          /* Left Shift */
302     case 0x36:                          /* Right Shift */
303     case 0x1d:                          /* Left CTRL */
304     case 0x9d:                          /* Right CTRL */
305     case 0x38:                          /* Left ALT */
306     case 0xb8:                         /* Right ALT */
307         if (ev->type == SDL_KEYUP)
308             modifiers_state[keycode] = 0;
309         else
310             modifiers_state[keycode] = 1;
311         break;
312 #define QEMU_SDL_VERSION ((SDL_MAJOR_VERSION << 8) + SDL_MINOR_VERSION)
313 #if QEMU_SDL_VERSION < 0x102 || QEMU_SDL_VERSION == 0x102 && SDL_PATCHLEVEL < 14
314         /* SDL versions before 1.2.14 don't support key up for caps/num lock. */
315     case 0x45: /* num lock */
316     case 0x3a: /* caps lock */
317         /* SDL does not send the key up event, so we generate it */
318         qemu_input_event_send_key_number(dcl->con, keycode, true);
319         qemu_input_event_send_key_number(dcl->con, keycode, false);
320         return;
321 #endif
322     }
323
324     /* now send the key code */
325     qemu_input_event_send_key_number(dcl->con, keycode,
326                                      ev->type == SDL_KEYDOWN);
327 }
328
329 static void sdl_update_caption(void)
330 {
331     char win_title[1024];
332     char icon_title[1024];
333     const char *status = "";
334
335     if (!runstate_is_running())
336         status = " [Stopped]";
337     else if (gui_grab) {
338         if (alt_grab)
339             status = " - Press Ctrl-Alt-Shift-G to exit mouse grab";
340         else if (ctrl_grab)
341             status = " - Press Right-Ctrl-G to exit mouse grab";
342         else
343             status = " - Press Ctrl-Alt-G to exit mouse grab";
344     }
345
346     if (qemu_name) {
347         snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
348         snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
349     } else {
350         snprintf(win_title, sizeof(win_title), "QEMU%s", status);
351         snprintf(icon_title, sizeof(icon_title), "QEMU");
352     }
353
354     SDL_WM_SetCaption(win_title, icon_title);
355 }
356
357 static void sdl_hide_cursor(void)
358 {
359     if (!cursor_hide)
360         return;
361
362     if (qemu_input_is_absolute()) {
363         SDL_ShowCursor(1);
364         SDL_SetCursor(sdl_cursor_hidden);
365     } else {
366         SDL_ShowCursor(0);
367     }
368 }
369
370 static void sdl_show_cursor(void)
371 {
372     if (!cursor_hide)
373         return;
374
375     if (!qemu_input_is_absolute() || !qemu_console_is_graphic(NULL)) {
376         SDL_ShowCursor(1);
377         if (guest_cursor &&
378                 (gui_grab || qemu_input_is_absolute() || absolute_enabled))
379             SDL_SetCursor(guest_sprite);
380         else
381             SDL_SetCursor(sdl_cursor_normal);
382     }
383 }
384
385 static void sdl_grab_start(void)
386 {
387     /*
388      * If the application is not active, do not try to enter grab state. This
389      * prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from blocking all the
390      * application (SDL bug).
391      */
392     if (!(SDL_GetAppState() & SDL_APPINPUTFOCUS)) {
393         return;
394     }
395     if (guest_cursor) {
396         SDL_SetCursor(guest_sprite);
397         if (!qemu_input_is_absolute() && !absolute_enabled) {
398             SDL_WarpMouse(guest_x, guest_y);
399         }
400     } else
401         sdl_hide_cursor();
402     SDL_WM_GrabInput(SDL_GRAB_ON);
403     gui_grab = 1;
404     sdl_update_caption();
405 }
406
407 static void sdl_grab_end(void)
408 {
409     SDL_WM_GrabInput(SDL_GRAB_OFF);
410     gui_grab = 0;
411     sdl_show_cursor();
412     sdl_update_caption();
413 }
414
415 static void absolute_mouse_grab(void)
416 {
417     int mouse_x, mouse_y;
418
419     SDL_GetMouseState(&mouse_x, &mouse_y);
420     if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
421         mouse_y > 0 && mouse_y < real_screen->h - 1) {
422         sdl_grab_start();
423     }
424 }
425
426 static void sdl_mouse_mode_change(Notifier *notify, void *data)
427 {
428     if (qemu_input_is_absolute()) {
429         if (!absolute_enabled) {
430             absolute_enabled = 1;
431             if (qemu_console_is_graphic(NULL)) {
432                 absolute_mouse_grab();
433             }
434         }
435     } else if (absolute_enabled) {
436         if (!gui_fullscreen) {
437             sdl_grab_end();
438         }
439         absolute_enabled = 0;
440     }
441 }
442
443 static void sdl_send_mouse_event(int dx, int dy, int x, int y, int state)
444 {
445     static uint32_t bmap[INPUT_BUTTON__MAX] = {
446         [INPUT_BUTTON_LEFT]       = SDL_BUTTON(SDL_BUTTON_LEFT),
447         [INPUT_BUTTON_MIDDLE]     = SDL_BUTTON(SDL_BUTTON_MIDDLE),
448         [INPUT_BUTTON_RIGHT]      = SDL_BUTTON(SDL_BUTTON_RIGHT),
449         [INPUT_BUTTON_WHEEL_UP]   = SDL_BUTTON(SDL_BUTTON_WHEELUP),
450         [INPUT_BUTTON_WHEEL_DOWN] = SDL_BUTTON(SDL_BUTTON_WHEELDOWN),
451     };
452     static uint32_t prev_state;
453
454     if (prev_state != state) {
455         qemu_input_update_buttons(dcl->con, bmap, prev_state, state);
456         prev_state = state;
457     }
458
459     if (qemu_input_is_absolute()) {
460         qemu_input_queue_abs(dcl->con, INPUT_AXIS_X, x,
461                              0, real_screen->w);
462         qemu_input_queue_abs(dcl->con, INPUT_AXIS_Y, y,
463                              0, real_screen->h);
464     } else {
465         if (guest_cursor) {
466             x -= guest_x;
467             y -= guest_y;
468             guest_x += x;
469             guest_y += y;
470             dx = x;
471             dy = y;
472         }
473         qemu_input_queue_rel(dcl->con, INPUT_AXIS_X, dx);
474         qemu_input_queue_rel(dcl->con, INPUT_AXIS_Y, dy);
475     }
476     qemu_input_event_sync();
477 }
478
479 static void sdl_scale(int width, int height)
480 {
481     int bpp = real_screen->format->BitsPerPixel;
482
483 #ifdef DEBUG_SDL
484     printf("SDL: Scaling to %dx%d bpp %d\n", width, height, bpp);
485 #endif
486
487     if (bpp != 16 && bpp != 32) {
488         bpp = 32;
489     }
490     do_sdl_resize(width, height, bpp);
491     scaling_active = 1;
492 }
493
494 static void toggle_full_screen(void)
495 {
496     int width = surface_width(surface);
497     int height = surface_height(surface);
498     int bpp = surface_bits_per_pixel(surface);
499
500     gui_fullscreen = !gui_fullscreen;
501     if (gui_fullscreen) {
502         gui_saved_width = real_screen->w;
503         gui_saved_height = real_screen->h;
504         gui_saved_scaling = scaling_active;
505
506         do_sdl_resize(width, height, bpp);
507         scaling_active = 0;
508
509         gui_saved_grab = gui_grab;
510         sdl_grab_start();
511     } else {
512         if (gui_saved_scaling) {
513             sdl_scale(gui_saved_width, gui_saved_height);
514         } else {
515             do_sdl_resize(width, height, 0);
516         }
517         if (!gui_saved_grab || !qemu_console_is_graphic(NULL)) {
518             sdl_grab_end();
519         }
520     }
521     graphic_hw_invalidate(NULL);
522     graphic_hw_update(NULL);
523 }
524
525 static void handle_keydown(SDL_Event *ev)
526 {
527     int mod_state;
528     int keycode;
529
530     if (alt_grab) {
531         mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
532                     (gui_grab_code | KMOD_LSHIFT);
533     } else if (ctrl_grab) {
534         mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
535     } else {
536         mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code;
537     }
538     gui_key_modifier_pressed = mod_state;
539
540     if (gui_key_modifier_pressed) {
541         keycode = sdl_keyevent_to_keycode(&ev->key);
542         switch (keycode) {
543         case 0x21: /* 'f' key on US keyboard */
544             toggle_full_screen();
545             gui_keysym = 1;
546             break;
547         case 0x22: /* 'g' key */
548             if (!gui_grab) {
549                 if (qemu_console_is_graphic(NULL)) {
550                     sdl_grab_start();
551                 }
552             } else if (!gui_fullscreen) {
553                 sdl_grab_end();
554             }
555             gui_keysym = 1;
556             break;
557         case 0x16: /* 'u' key on US keyboard */
558             if (scaling_active) {
559                 scaling_active = 0;
560                 sdl_switch(dcl, NULL);
561                 graphic_hw_invalidate(NULL);
562                 graphic_hw_update(NULL);
563             }
564             gui_keysym = 1;
565             break;
566         case 0x02 ... 0x0a: /* '1' to '9' keys */
567             /* Reset the modifiers sent to the current console */
568             reset_keys();
569             console_select(keycode - 0x02);
570             gui_keysym = 1;
571             if (gui_fullscreen) {
572                 break;
573             }
574             if (!qemu_console_is_graphic(NULL)) {
575                 /* release grab if going to a text console */
576                 if (gui_grab) {
577                     sdl_grab_end();
578                 } else if (absolute_enabled) {
579                     sdl_show_cursor();
580                 }
581             } else if (absolute_enabled) {
582                 sdl_hide_cursor();
583                 absolute_mouse_grab();
584             }
585             break;
586         case 0x1b: /* '+' */
587         case 0x35: /* '-' */
588             if (!gui_fullscreen) {
589                 int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50),
590                                 160);
591                 int height = (surface_height(surface) * width) /
592                     surface_width(surface);
593
594                 sdl_scale(width, height);
595                 graphic_hw_invalidate(NULL);
596                 graphic_hw_update(NULL);
597                 gui_keysym = 1;
598             }
599         default:
600             break;
601         }
602     } else if (!qemu_console_is_graphic(NULL)) {
603         int keysym = 0;
604
605         if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
606             switch (ev->key.keysym.sym) {
607             case SDLK_UP:
608                 keysym = QEMU_KEY_CTRL_UP;
609                 break;
610             case SDLK_DOWN:
611                 keysym = QEMU_KEY_CTRL_DOWN;
612                 break;
613             case SDLK_LEFT:
614                 keysym = QEMU_KEY_CTRL_LEFT;
615                 break;
616             case SDLK_RIGHT:
617                 keysym = QEMU_KEY_CTRL_RIGHT;
618                 break;
619             case SDLK_HOME:
620                 keysym = QEMU_KEY_CTRL_HOME;
621                 break;
622             case SDLK_END:
623                 keysym = QEMU_KEY_CTRL_END;
624                 break;
625             case SDLK_PAGEUP:
626                 keysym = QEMU_KEY_CTRL_PAGEUP;
627                 break;
628             case SDLK_PAGEDOWN:
629                 keysym = QEMU_KEY_CTRL_PAGEDOWN;
630                 break;
631             default:
632                 break;
633             }
634         } else {
635             switch (ev->key.keysym.sym) {
636             case SDLK_UP:
637                 keysym = QEMU_KEY_UP;
638                 break;
639             case SDLK_DOWN:
640                 keysym = QEMU_KEY_DOWN;
641                 break;
642             case SDLK_LEFT:
643                 keysym = QEMU_KEY_LEFT;
644                 break;
645             case SDLK_RIGHT:
646                 keysym = QEMU_KEY_RIGHT;
647                 break;
648             case SDLK_HOME:
649                 keysym = QEMU_KEY_HOME;
650                 break;
651             case SDLK_END:
652                 keysym = QEMU_KEY_END;
653                 break;
654             case SDLK_PAGEUP:
655                 keysym = QEMU_KEY_PAGEUP;
656                 break;
657             case SDLK_PAGEDOWN:
658                 keysym = QEMU_KEY_PAGEDOWN;
659                 break;
660             case SDLK_BACKSPACE:
661                 keysym = QEMU_KEY_BACKSPACE;
662                 break;
663             case SDLK_DELETE:
664                 keysym = QEMU_KEY_DELETE;
665                 break;
666             default:
667                 break;
668             }
669         }
670         if (keysym) {
671             kbd_put_keysym(keysym);
672         } else if (ev->key.keysym.unicode != 0) {
673             kbd_put_keysym(ev->key.keysym.unicode);
674         }
675     }
676     if (qemu_console_is_graphic(NULL) && !gui_keysym) {
677         sdl_process_key(&ev->key);
678     }
679 }
680
681 static void handle_keyup(SDL_Event *ev)
682 {
683     int mod_state;
684
685     if (!alt_grab) {
686         mod_state = (ev->key.keysym.mod & gui_grab_code);
687     } else {
688         mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT));
689     }
690     if (!mod_state && gui_key_modifier_pressed) {
691         gui_key_modifier_pressed = 0;
692         gui_keysym = 0;
693     }
694     if (qemu_console_is_graphic(NULL) && !gui_keysym) {
695         sdl_process_key(&ev->key);
696     }
697 }
698
699 static void handle_mousemotion(SDL_Event *ev)
700 {
701     int max_x, max_y;
702
703     if (qemu_console_is_graphic(NULL) &&
704         (qemu_input_is_absolute() || absolute_enabled)) {
705         max_x = real_screen->w - 1;
706         max_y = real_screen->h - 1;
707         if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
708             ev->motion.x == max_x || ev->motion.y == max_y)) {
709             sdl_grab_end();
710         }
711         if (!gui_grab &&
712             (ev->motion.x > 0 && ev->motion.x < max_x &&
713             ev->motion.y > 0 && ev->motion.y < max_y)) {
714             sdl_grab_start();
715         }
716     }
717     if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
718         sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel,
719                              ev->motion.x, ev->motion.y, ev->motion.state);
720     }
721 }
722
723 static void handle_mousebutton(SDL_Event *ev)
724 {
725     int buttonstate = SDL_GetMouseState(NULL, NULL);
726     SDL_MouseButtonEvent *bev;
727
728     if (!qemu_console_is_graphic(NULL)) {
729         return;
730     }
731
732     bev = &ev->button;
733     if (!gui_grab && !qemu_input_is_absolute()) {
734         if (ev->type == SDL_MOUSEBUTTONUP && bev->button == SDL_BUTTON_LEFT) {
735             /* start grabbing all events */
736             sdl_grab_start();
737         }
738     } else {
739         if (ev->type == SDL_MOUSEBUTTONDOWN) {
740             buttonstate |= SDL_BUTTON(bev->button);
741         } else {
742             buttonstate &= ~SDL_BUTTON(bev->button);
743         }
744         sdl_send_mouse_event(0, 0, bev->x, bev->y, buttonstate);
745     }
746 }
747
748 static void handle_activation(SDL_Event *ev)
749 {
750 #ifdef _WIN32
751     /* Disable grab if the window no longer has the focus
752      * (Windows-only workaround) */
753     if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
754         !ev->active.gain && !gui_fullscreen) {
755         sdl_grab_end();
756     }
757 #endif
758     if (!gui_grab && ev->active.gain && qemu_console_is_graphic(NULL) &&
759         (qemu_input_is_absolute() || absolute_enabled)) {
760         absolute_mouse_grab();
761     }
762     if (ev->active.state & SDL_APPACTIVE) {
763         if (ev->active.gain) {
764             /* Back to default interval */
765             update_displaychangelistener(dcl, GUI_REFRESH_INTERVAL_DEFAULT);
766         } else {
767             /* Sleeping interval.  Not using the long default here as
768              * sdl_refresh does not only update the guest screen, but
769              * also checks for gui events. */
770             update_displaychangelistener(dcl, 500);
771         }
772     }
773 }
774
775 static void sdl_refresh(DisplayChangeListener *dcl)
776 {
777     SDL_Event ev1, *ev = &ev1;
778     bool allow_close = true;
779     int idle = 1;
780
781     if (last_vm_running != runstate_is_running()) {
782         last_vm_running = runstate_is_running();
783         sdl_update_caption();
784     }
785
786     graphic_hw_update(NULL);
787     SDL_EnableUNICODE(!qemu_console_is_graphic(NULL));
788
789     while (SDL_PollEvent(ev)) {
790         switch (ev->type) {
791         case SDL_VIDEOEXPOSE:
792             sdl_update(dcl, 0, 0, real_screen->w, real_screen->h);
793             break;
794         case SDL_KEYDOWN:
795             idle = 0;
796             handle_keydown(ev);
797             break;
798         case SDL_KEYUP:
799             idle = 0;
800             handle_keyup(ev);
801             break;
802         case SDL_QUIT:
803             if (opts->has_window_close && !opts->window_close) {
804                 allow_close = false;
805             }
806             if (allow_close) {
807                 no_shutdown = 0;
808                 qemu_system_shutdown_request(SHUTDOWN_CAUSE_HOST_UI);
809             }
810             break;
811         case SDL_MOUSEMOTION:
812             idle = 0;
813             handle_mousemotion(ev);
814             break;
815         case SDL_MOUSEBUTTONDOWN:
816         case SDL_MOUSEBUTTONUP:
817             idle = 0;
818             handle_mousebutton(ev);
819             break;
820         case SDL_ACTIVEEVENT:
821             handle_activation(ev);
822             break;
823         case SDL_VIDEORESIZE:
824             sdl_scale(ev->resize.w, ev->resize.h);
825             graphic_hw_invalidate(NULL);
826             graphic_hw_update(NULL);
827             break;
828         default:
829             break;
830         }
831     }
832
833     if (idle) {
834         if (idle_counter < SDL_MAX_IDLE_COUNT) {
835             idle_counter++;
836             if (idle_counter >= SDL_MAX_IDLE_COUNT) {
837                 dcl->update_interval = GUI_REFRESH_INTERVAL_DEFAULT;
838             }
839         }
840     } else {
841         idle_counter = 0;
842         dcl->update_interval = SDL_REFRESH_INTERVAL_BUSY;
843     }
844 }
845
846 static void sdl_mouse_warp(DisplayChangeListener *dcl,
847                            int x, int y, int on)
848 {
849     if (on) {
850         if (!guest_cursor)
851             sdl_show_cursor();
852         if (gui_grab || qemu_input_is_absolute() || absolute_enabled) {
853             SDL_SetCursor(guest_sprite);
854             if (!qemu_input_is_absolute() && !absolute_enabled) {
855                 SDL_WarpMouse(x, y);
856             }
857         }
858     } else if (gui_grab)
859         sdl_hide_cursor();
860     guest_cursor = on;
861     guest_x = x, guest_y = y;
862 }
863
864 static void sdl_mouse_define(DisplayChangeListener *dcl,
865                              QEMUCursor *c)
866 {
867     uint8_t *image, *mask;
868     int bpl;
869
870     if (guest_sprite)
871         SDL_FreeCursor(guest_sprite);
872
873     bpl = cursor_get_mono_bpl(c);
874     image = g_malloc0(bpl * c->height);
875     mask  = g_malloc0(bpl * c->height);
876     cursor_get_mono_image(c, 0x000000, image);
877     cursor_get_mono_mask(c, 0, mask);
878     guest_sprite = SDL_CreateCursor(image, mask, c->width, c->height,
879                                     c->hot_x, c->hot_y);
880     g_free(image);
881     g_free(mask);
882
883     if (guest_cursor &&
884             (gui_grab || qemu_input_is_absolute() || absolute_enabled))
885         SDL_SetCursor(guest_sprite);
886 }
887
888 static void sdl_cleanup(void)
889 {
890     if (guest_sprite)
891         SDL_FreeCursor(guest_sprite);
892     SDL_QuitSubSystem(SDL_INIT_VIDEO);
893 }
894
895 static const DisplayChangeListenerOps dcl_ops = {
896     .dpy_name             = "sdl",
897     .dpy_gfx_update       = sdl_update,
898     .dpy_gfx_switch       = sdl_switch,
899     .dpy_gfx_check_format = sdl_check_format,
900     .dpy_refresh          = sdl_refresh,
901     .dpy_mouse_set        = sdl_mouse_warp,
902     .dpy_cursor_define    = sdl_mouse_define,
903 };
904
905 static void sdl1_display_init(DisplayState *ds, DisplayOptions *o)
906 {
907     int flags;
908     uint8_t data = 0;
909     const SDL_VideoInfo *vi;
910     SDL_SysWMinfo info;
911     char *filename;
912
913     assert(o->type == DISPLAY_TYPE_SDL);
914     opts = o;
915 #if defined(__APPLE__)
916     /* always use generic keymaps */
917     if (!keyboard_layout)
918         keyboard_layout = "en-us";
919 #endif
920     if(keyboard_layout) {
921         kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout,
922                                           &error_fatal);
923     }
924
925     g_printerr("Running QEMU with SDL 1.2 is deprecated, and will be removed\n"
926                "in a future release. Please switch to SDL 2.0 instead\n");
927
928     if (opts->has_full_screen && opts->full_screen) {
929         setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
930     }
931 #ifdef __linux__
932     /* on Linux, SDL may use fbcon|directfb|svgalib when run without
933      * accessible $DISPLAY to open X11 window.  This is often the case
934      * when qemu is run using sudo.  But in this case, and when actually
935      * run in X11 environment, SDL fights with X11 for the video card,
936      * making current display unavailable, often until reboot.
937      * So make x11 the default SDL video driver if this variable is unset.
938      * This is a bit hackish but saves us from bigger problem.
939      * Maybe it's a good idea to fix this in SDL instead.
940      */
941     setenv("SDL_VIDEODRIVER", "x11", 0);
942 #endif
943
944     /* Enable normal up/down events for Caps-Lock and Num-Lock keys.
945      * This requires SDL >= 1.2.14. */
946     setenv("SDL_DISABLE_LOCK_KEYS", "1", 1);
947
948     flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
949     if (SDL_Init (flags)) {
950         fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
951                 SDL_GetError());
952         exit(1);
953     }
954     vi = SDL_GetVideoInfo();
955     host_format = *(vi->vfmt);
956
957     keycode_map = sdl_get_keymap(&keycode_maplen);
958
959     /* Load a 32x32x4 image. White pixels are transparent. */
960     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, "qemu-icon.bmp");
961     if (filename) {
962         SDL_Surface *image = SDL_LoadBMP(filename);
963         if (image) {
964             uint32_t colorkey = SDL_MapRGB(image->format, 255, 255, 255);
965             SDL_SetColorKey(image, SDL_SRCCOLORKEY, colorkey);
966             SDL_WM_SetIcon(image, NULL);
967         }
968         g_free(filename);
969     }
970
971     if (opts->has_full_screen && opts->full_screen) {
972         gui_fullscreen = 1;
973         sdl_grab_start();
974     }
975
976     dcl = g_new0(DisplayChangeListener, 1);
977     dcl->ops = &dcl_ops;
978     register_displaychangelistener(dcl);
979
980     mouse_mode_notifier.notify = sdl_mouse_mode_change;
981     qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
982
983     sdl_update_caption();
984     SDL_EnableKeyRepeat(250, 50);
985     gui_grab = 0;
986
987     sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
988     sdl_cursor_normal = SDL_GetCursor();
989
990     memset(&info, 0, sizeof(info));
991     SDL_VERSION(&info.version);
992     if (SDL_GetWMInfo(&info)) {
993         int i;
994         for (i = 0; ; i++) {
995             /* All consoles share the same window */
996             QemuConsole *con = qemu_console_lookup_by_index(i);
997             if (con) {
998 #if defined(SDL_VIDEO_DRIVER_X11)
999                 qemu_console_set_window_id(con, info.info.x11.wmwindow);
1000 #elif defined(SDL_VIDEO_DRIVER_NANOX) || \
1001       defined(SDL_VIDEO_DRIVER_WINDIB) || defined(SDL_VIDEO_DRIVER_DDRAW) || \
1002       defined(SDL_VIDEO_DRIVER_GAPI) || \
1003       defined(SDL_VIDEO_DRIVER_RISCOS)
1004                 qemu_console_set_window_id(con, (int) (uintptr_t) info.window);
1005 #else
1006                 qemu_console_set_window_id(con, info.data);
1007 #endif
1008             } else {
1009                 break;
1010             }
1011         }
1012     }
1013
1014     atexit(sdl_cleanup);
1015 }
1016
1017 static QemuDisplay qemu_display_sdl1 = {
1018     .type       = DISPLAY_TYPE_SDL,
1019     .init       = sdl1_display_init,
1020 };
1021
1022 static void register_sdl1(void)
1023 {
1024     qemu_display_register(&qemu_display_sdl1);
1025 }
1026
1027 type_init(register_sdl1);
This page took 0.081408 seconds and 4 git commands to generate.