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