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