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