|
|
1.1 root 1: /*
2: * QEMU SDL display driver
3: *
4: * Copyright (c) 2003 Fabrice Bellard
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24: #include <SDL.h>
25: #include <SDL_syswm.h>
26:
27: #ifndef _WIN32
28: #include <signal.h>
29: #endif
30:
31: #include "qemu-common.h"
32: #include "console.h"
33: #include "sysemu.h"
34: #include "x_keymap.h"
35: #include "sdl_zoom.h"
36:
37: static DisplayChangeListener *dcl;
38: static SDL_Surface *real_screen;
39: static SDL_Surface *guest_screen = NULL;
40: static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
41: static int last_vm_running;
42: static int gui_saved_grab;
43: static int gui_fullscreen;
44: static int gui_noframe;
45: static int gui_key_modifier_pressed;
46: static int gui_keysym;
47: static int gui_fullscreen_initial_grab;
48: static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
49: static uint8_t modifiers_state[256];
50: static int width, height;
51: static SDL_Cursor *sdl_cursor_normal;
52: static SDL_Cursor *sdl_cursor_hidden;
53: static int absolute_enabled = 0;
54: static int guest_cursor = 0;
55: static int guest_x, guest_y;
56: static SDL_Cursor *guest_sprite = NULL;
57: static uint8_t allocator;
58: static SDL_PixelFormat host_format;
59: static int scaling_active = 0;
60: static Notifier mouse_mode_notifier;
61:
62: static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
63: {
64: // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
65: SDL_Rect rec;
66: rec.x = x;
67: rec.y = y;
68: rec.w = w;
69: rec.h = h;
70:
71: if (guest_screen) {
72: if (!scaling_active) {
73: SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
74: } else {
75: if (sdl_zoom_blit(guest_screen, real_screen, SMOOTHING_ON, &rec) < 0) {
76: fprintf(stderr, "Zoom blit failed\n");
77: exit(1);
78: }
79: }
80: }
81: SDL_UpdateRect(real_screen, rec.x, rec.y, rec.w, rec.h);
82: }
83:
84: static void sdl_setdata(DisplayState *ds)
85: {
86: SDL_Rect rec;
87: rec.x = 0;
88: rec.y = 0;
89: rec.w = real_screen->w;
90: rec.h = real_screen->h;
91:
92: if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
93:
94: guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
95: ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
96: ds->surface->pf.rmask, ds->surface->pf.gmask,
97: ds->surface->pf.bmask, ds->surface->pf.amask);
98: }
99:
100: static void do_sdl_resize(int new_width, int new_height, int bpp)
101: {
102: int flags;
103:
104: // printf("resizing to %d %d\n", w, h);
105:
106: flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL|SDL_RESIZABLE;
107: if (gui_fullscreen)
108: flags |= SDL_FULLSCREEN;
109: if (gui_noframe)
110: flags |= SDL_NOFRAME;
111:
112: width = new_width;
113: height = new_height;
114: real_screen = SDL_SetVideoMode(width, height, bpp, flags);
115: if (!real_screen) {
116: fprintf(stderr, "Could not open SDL display (%dx%dx%d): %s\n", width,
117: height, bpp, SDL_GetError());
118: exit(1);
119: }
120: }
121:
122: static void sdl_resize(DisplayState *ds)
123: {
124: if (!allocator) {
125: if (!scaling_active)
126: do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
127: else if (real_screen->format->BitsPerPixel != ds_get_bits_per_pixel(ds))
128: do_sdl_resize(real_screen->w, real_screen->h, ds_get_bits_per_pixel(ds));
129: sdl_setdata(ds);
130: } else {
131: if (guest_screen != NULL) {
132: SDL_FreeSurface(guest_screen);
133: guest_screen = NULL;
134: }
135: }
136: }
137:
138: static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf)
139: {
140: PixelFormat qemu_pf;
141:
142: memset(&qemu_pf, 0x00, sizeof(PixelFormat));
143:
144: qemu_pf.bits_per_pixel = sdl_pf->BitsPerPixel;
145: qemu_pf.bytes_per_pixel = sdl_pf->BytesPerPixel;
146: qemu_pf.depth = (qemu_pf.bits_per_pixel) == 32 ? 24 : (qemu_pf.bits_per_pixel);
147:
148: qemu_pf.rmask = sdl_pf->Rmask;
149: qemu_pf.gmask = sdl_pf->Gmask;
150: qemu_pf.bmask = sdl_pf->Bmask;
151: qemu_pf.amask = sdl_pf->Amask;
152:
153: qemu_pf.rshift = sdl_pf->Rshift;
154: qemu_pf.gshift = sdl_pf->Gshift;
155: qemu_pf.bshift = sdl_pf->Bshift;
156: qemu_pf.ashift = sdl_pf->Ashift;
157:
158: qemu_pf.rbits = 8 - sdl_pf->Rloss;
159: qemu_pf.gbits = 8 - sdl_pf->Gloss;
160: qemu_pf.bbits = 8 - sdl_pf->Bloss;
161: qemu_pf.abits = 8 - sdl_pf->Aloss;
162:
163: qemu_pf.rmax = ((1 << qemu_pf.rbits) - 1);
164: qemu_pf.gmax = ((1 << qemu_pf.gbits) - 1);
165: qemu_pf.bmax = ((1 << qemu_pf.bbits) - 1);
166: qemu_pf.amax = ((1 << qemu_pf.abits) - 1);
167:
168: return qemu_pf;
169: }
170:
171: static DisplaySurface* sdl_create_displaysurface(int width, int height)
172: {
173: DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
174: if (surface == NULL) {
175: fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
176: exit(1);
177: }
178:
179: surface->width = width;
180: surface->height = height;
181:
182: if (scaling_active) {
183: if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
184: surface->linesize = width * 4;
185: surface->pf = qemu_default_pixelformat(32);
186: } else {
187: surface->linesize = width * host_format.BytesPerPixel;
188: surface->pf = sdl_to_qemu_pixelformat(&host_format);
189: }
190: #ifdef HOST_WORDS_BIGENDIAN
191: surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
192: #else
193: surface->flags = QEMU_ALLOCATED_FLAG;
194: #endif
195: surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
196:
197: return surface;
198: }
199:
200: if (host_format.BitsPerPixel == 16)
201: do_sdl_resize(width, height, 16);
202: else
203: do_sdl_resize(width, height, 32);
204:
205: surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
206: surface->linesize = real_screen->pitch;
207: surface->data = real_screen->pixels;
208:
209: #ifdef HOST_WORDS_BIGENDIAN
210: surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
211: #else
212: surface->flags = QEMU_REALPIXELS_FLAG;
213: #endif
214: allocator = 1;
215:
216: return surface;
217: }
218:
219: static void sdl_free_displaysurface(DisplaySurface *surface)
220: {
221: allocator = 0;
222: if (surface == NULL)
223: return;
224:
225: if (surface->flags & QEMU_ALLOCATED_FLAG)
226: qemu_free(surface->data);
227: qemu_free(surface);
228: }
229:
230: static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
231: {
232: sdl_free_displaysurface(surface);
233: return sdl_create_displaysurface(width, height);
234: }
235:
236: /* generic keyboard conversion */
237:
238: #include "sdl_keysym.h"
239:
240: static kbd_layout_t *kbd_layout = NULL;
241:
242: static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
243: {
244: int keysym;
245: /* workaround for X11+SDL bug with AltGR */
246: keysym = ev->keysym.sym;
247: if (keysym == 0 && ev->keysym.scancode == 113)
248: keysym = SDLK_MODE;
249: /* For Japanese key '\' and '|' */
250: if (keysym == 92 && ev->keysym.scancode == 133) {
251: keysym = 0xa5;
252: }
253: return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK;
254: }
255:
256: /* specific keyboard conversions from scan codes */
257:
258: #if defined(_WIN32)
259:
260: static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
261: {
262: return ev->keysym.scancode;
263: }
264:
265: #else
266:
267: #if defined(SDL_VIDEO_DRIVER_X11)
268: #include <X11/XKBlib.h>
269:
270: static int check_for_evdev(void)
271: {
272: SDL_SysWMinfo info;
273: XkbDescPtr desc = NULL;
274: int has_evdev = 0;
275: char *keycodes = NULL;
276:
277: SDL_VERSION(&info.version);
278: if (!SDL_GetWMInfo(&info)) {
279: return 0;
280: }
281: desc = XkbGetKeyboard(info.info.x11.display,
282: XkbGBN_AllComponentsMask,
283: XkbUseCoreKbd);
284: if (desc && desc->names) {
285: keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
286: if (keycodes == NULL) {
287: fprintf(stderr, "could not lookup keycode name\n");
288: } else if (strstart(keycodes, "evdev", NULL)) {
289: has_evdev = 1;
290: } else if (!strstart(keycodes, "xfree86", NULL)) {
291: fprintf(stderr, "unknown keycodes `%s', please report to "
292: "[email protected]\n", keycodes);
293: }
294: }
295:
296: if (desc) {
297: XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
298: }
299: if (keycodes) {
300: XFree(keycodes);
301: }
302: return has_evdev;
303: }
304: #else
305: static int check_for_evdev(void)
306: {
307: return 0;
308: }
309: #endif
310:
311: static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
312: {
313: int keycode;
314: static int has_evdev = -1;
315:
316: if (has_evdev == -1)
317: has_evdev = check_for_evdev();
318:
319: keycode = ev->keysym.scancode;
320:
321: if (keycode < 9) {
322: keycode = 0;
323: } else if (keycode < 97) {
324: keycode -= 8; /* just an offset */
325: } else if (keycode < 158) {
326: /* use conversion table */
327: if (has_evdev)
328: keycode = translate_evdev_keycode(keycode - 97);
329: else
330: keycode = translate_xfree86_keycode(keycode - 97);
331: } else if (keycode == 208) { /* Hiragana_Katakana */
332: keycode = 0x70;
333: } else if (keycode == 211) { /* backslash */
334: keycode = 0x73;
335: } else {
336: keycode = 0;
337: }
338: return keycode;
339: }
340:
341: #endif
342:
343: static void reset_keys(void)
344: {
345: int i;
346: for(i = 0; i < 256; i++) {
347: if (modifiers_state[i]) {
348: if (i & SCANCODE_GREY)
349: kbd_put_keycode(SCANCODE_EMUL0);
350: kbd_put_keycode(i | SCANCODE_UP);
351: modifiers_state[i] = 0;
352: }
353: }
354: }
355:
356: static void sdl_process_key(SDL_KeyboardEvent *ev)
357: {
358: int keycode, v;
359:
360: if (ev->keysym.sym == SDLK_PAUSE) {
361: /* specific case */
362: v = 0;
363: if (ev->type == SDL_KEYUP)
364: v |= SCANCODE_UP;
365: kbd_put_keycode(0xe1);
366: kbd_put_keycode(0x1d | v);
367: kbd_put_keycode(0x45 | v);
368: return;
369: }
370:
371: if (kbd_layout) {
372: keycode = sdl_keyevent_to_keycode_generic(ev);
373: } else {
374: keycode = sdl_keyevent_to_keycode(ev);
375: }
376:
377: switch(keycode) {
378: case 0x00:
379: /* sent when leaving window: reset the modifiers state */
380: reset_keys();
381: return;
382: case 0x2a: /* Left Shift */
383: case 0x36: /* Right Shift */
384: case 0x1d: /* Left CTRL */
385: case 0x9d: /* Right CTRL */
386: case 0x38: /* Left ALT */
387: case 0xb8: /* Right ALT */
388: if (ev->type == SDL_KEYUP)
389: modifiers_state[keycode] = 0;
390: else
391: modifiers_state[keycode] = 1;
392: break;
393: case 0x45: /* num lock */
394: case 0x3a: /* caps lock */
395: /* SDL does not send the key up event, so we generate it */
396: kbd_put_keycode(keycode);
397: kbd_put_keycode(keycode | SCANCODE_UP);
398: return;
399: }
400:
401: /* now send the key code */
402: if (keycode & SCANCODE_GREY)
403: kbd_put_keycode(SCANCODE_EMUL0);
404: if (ev->type == SDL_KEYUP)
405: kbd_put_keycode(keycode | SCANCODE_UP);
406: else
407: kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
408: }
409:
410: static void sdl_update_caption(void)
411: {
412: char win_title[1024];
413: char icon_title[1024];
414: const char *status = "";
415:
416: if (!vm_running)
417: status = " [Stopped]";
418: else if (gui_grab) {
419: if (alt_grab)
420: status = " - Press Ctrl-Alt-Shift to exit mouse grab";
421: else if (ctrl_grab)
422: status = " - Press Right-Ctrl to exit mouse grab";
423: else
424: status = " - Press Ctrl-Alt to exit mouse grab";
425: }
426:
427: if (qemu_name) {
428: snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
429: snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
430: } else {
431: snprintf(win_title, sizeof(win_title), "QEMU%s", status);
432: snprintf(icon_title, sizeof(icon_title), "QEMU");
433: }
434:
435: SDL_WM_SetCaption(win_title, icon_title);
436: }
437:
438: static void sdl_hide_cursor(void)
439: {
440: if (!cursor_hide)
441: return;
442:
443: if (kbd_mouse_is_absolute()) {
444: SDL_ShowCursor(1);
445: SDL_SetCursor(sdl_cursor_hidden);
446: } else {
447: SDL_ShowCursor(0);
448: }
449: }
450:
451: static void sdl_show_cursor(void)
452: {
453: if (!cursor_hide)
454: return;
455:
456: if (!kbd_mouse_is_absolute()) {
457: SDL_ShowCursor(1);
458: if (guest_cursor &&
459: (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
460: SDL_SetCursor(guest_sprite);
461: else
462: SDL_SetCursor(sdl_cursor_normal);
463: }
464: }
465:
466: static void sdl_grab_start(void)
467: {
468: if (guest_cursor) {
469: SDL_SetCursor(guest_sprite);
470: if (!kbd_mouse_is_absolute() && !absolute_enabled)
471: SDL_WarpMouse(guest_x, guest_y);
472: } else
473: sdl_hide_cursor();
474:
475: if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
476: gui_grab = 1;
477: sdl_update_caption();
478: } else
479: sdl_show_cursor();
480: }
481:
482: static void sdl_grab_end(void)
483: {
484: SDL_WM_GrabInput(SDL_GRAB_OFF);
485: gui_grab = 0;
486: sdl_show_cursor();
487: sdl_update_caption();
488: }
489:
490: static void sdl_mouse_mode_change(Notifier *notify)
491: {
492: if (kbd_mouse_is_absolute()) {
493: if (!absolute_enabled) {
494: sdl_hide_cursor();
495: if (gui_grab) {
496: sdl_grab_end();
497: }
498: absolute_enabled = 1;
499: }
500: } else if (absolute_enabled) {
501: sdl_show_cursor();
502: absolute_enabled = 0;
503: }
504: }
505:
506: static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
507: {
508: int buttons;
509: buttons = 0;
510: if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
511: buttons |= MOUSE_EVENT_LBUTTON;
512: if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
513: buttons |= MOUSE_EVENT_RBUTTON;
514: if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
515: buttons |= MOUSE_EVENT_MBUTTON;
516:
517: if (kbd_mouse_is_absolute()) {
518: dx = x * 0x7FFF / (width - 1);
519: dy = y * 0x7FFF / (height - 1);
520: } else if (guest_cursor) {
521: x -= guest_x;
522: y -= guest_y;
523: guest_x += x;
524: guest_y += y;
525: dx = x;
526: dy = y;
527: }
528:
529: kbd_mouse_event(dx, dy, dz, buttons);
530: }
531:
532: static void toggle_full_screen(DisplayState *ds)
533: {
534: gui_fullscreen = !gui_fullscreen;
535: do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
536: if (gui_fullscreen) {
537: scaling_active = 0;
538: gui_saved_grab = gui_grab;
539: sdl_grab_start();
540: } else {
541: if (!gui_saved_grab)
542: sdl_grab_end();
543: }
544: vga_hw_invalidate();
545: vga_hw_update();
546: }
547:
548: static void sdl_refresh(DisplayState *ds)
549: {
550: SDL_Event ev1, *ev = &ev1;
551: int mod_state;
552: int buttonstate = SDL_GetMouseState(NULL, NULL);
553:
554: if (last_vm_running != vm_running) {
555: last_vm_running = vm_running;
556: sdl_update_caption();
557: }
558:
559: vga_hw_update();
560: SDL_EnableUNICODE(!is_graphic_console());
561:
562: while (SDL_PollEvent(ev)) {
563: switch (ev->type) {
564: case SDL_VIDEOEXPOSE:
565: sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
566: break;
567: case SDL_KEYDOWN:
568: case SDL_KEYUP:
569: if (ev->type == SDL_KEYDOWN) {
570: if (alt_grab) {
571: mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
572: (gui_grab_code | KMOD_LSHIFT);
573: } else if (ctrl_grab) {
574: mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
575: } else {
576: mod_state = (SDL_GetModState() & gui_grab_code) ==
577: gui_grab_code;
578: }
579: gui_key_modifier_pressed = mod_state;
580: if (gui_key_modifier_pressed) {
581: int keycode;
582: keycode = sdl_keyevent_to_keycode(&ev->key);
583: switch(keycode) {
584: case 0x21: /* 'f' key on US keyboard */
585: toggle_full_screen(ds);
586: gui_keysym = 1;
587: break;
588: case 0x16: /* 'u' key on US keyboard */
589: scaling_active = 0;
590: sdl_resize(ds);
591: vga_hw_invalidate();
592: vga_hw_update();
593: break;
594: case 0x02 ... 0x0a: /* '1' to '9' keys */
595: /* Reset the modifiers sent to the current console */
596: reset_keys();
597: console_select(keycode - 0x02);
598: if (!is_graphic_console()) {
599: /* display grab if going to a text console */
600: if (gui_grab)
601: sdl_grab_end();
602: }
603: gui_keysym = 1;
604: break;
605: default:
606: break;
607: }
608: } else if (!is_graphic_console()) {
609: int keysym;
610: keysym = 0;
611: if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
612: switch(ev->key.keysym.sym) {
613: case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
614: case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
615: case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
616: case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
617: case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
618: case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
619: case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
620: case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
621: default: break;
622: }
623: } else {
624: switch(ev->key.keysym.sym) {
625: case SDLK_UP: keysym = QEMU_KEY_UP; break;
626: case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
627: case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
628: case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
629: case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
630: case SDLK_END: keysym = QEMU_KEY_END; break;
631: case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
632: case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
633: case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
634: case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
635: default: break;
636: }
637: }
638: if (keysym) {
639: kbd_put_keysym(keysym);
640: } else if (ev->key.keysym.unicode != 0) {
641: kbd_put_keysym(ev->key.keysym.unicode);
642: }
643: }
644: } else if (ev->type == SDL_KEYUP) {
645: if (!alt_grab) {
646: mod_state = (ev->key.keysym.mod & gui_grab_code);
647: } else {
648: mod_state = (ev->key.keysym.mod &
649: (gui_grab_code | KMOD_LSHIFT));
650: }
651: if (!mod_state) {
652: if (gui_key_modifier_pressed) {
653: gui_key_modifier_pressed = 0;
654: if (gui_keysym == 0) {
655: /* exit/enter grab if pressing Ctrl-Alt */
656: if (!gui_grab) {
657: /* if the application is not active,
658: do not try to enter grab state. It
659: prevents
660: 'SDL_WM_GrabInput(SDL_GRAB_ON)'
661: from blocking all the application
662: (SDL bug). */
663: if (SDL_GetAppState() & SDL_APPACTIVE)
664: sdl_grab_start();
665: } else {
666: sdl_grab_end();
667: }
668: /* SDL does not send back all the
669: modifiers key, so we must correct it */
670: reset_keys();
671: break;
672: }
673: gui_keysym = 0;
674: }
675: }
676: }
677: if (is_graphic_console() && !gui_keysym)
678: sdl_process_key(&ev->key);
679: break;
680: case SDL_QUIT:
681: if (!no_quit)
682: qemu_system_shutdown_request();
683: break;
684: case SDL_MOUSEMOTION:
685: if (gui_grab || kbd_mouse_is_absolute() ||
686: absolute_enabled) {
687: sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
688: ev->motion.x, ev->motion.y, ev->motion.state);
689: }
690: break;
691: case SDL_MOUSEBUTTONDOWN:
692: case SDL_MOUSEBUTTONUP:
693: {
694: SDL_MouseButtonEvent *bev = &ev->button;
695: if (!gui_grab && !kbd_mouse_is_absolute()) {
696: if (ev->type == SDL_MOUSEBUTTONDOWN &&
697: (bev->button == SDL_BUTTON_LEFT)) {
698: /* start grabbing all events */
699: sdl_grab_start();
700: }
701: } else {
702: int dz;
703: dz = 0;
704: if (ev->type == SDL_MOUSEBUTTONDOWN) {
705: buttonstate |= SDL_BUTTON(bev->button);
706: } else {
707: buttonstate &= ~SDL_BUTTON(bev->button);
708: }
709: #ifdef SDL_BUTTON_WHEELUP
710: if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
711: dz = -1;
712: } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
713: dz = 1;
714: }
715: #endif
716: sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
717: }
718: }
719: break;
720: case SDL_ACTIVEEVENT:
721: if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
722: !ev->active.gain && !gui_fullscreen_initial_grab) {
723: sdl_grab_end();
724: }
725: if (ev->active.state & SDL_APPACTIVE) {
726: if (ev->active.gain) {
727: /* Back to default interval */
728: dcl->gui_timer_interval = 0;
729: dcl->idle = 0;
730: } else {
731: /* Sleeping interval */
732: dcl->gui_timer_interval = 500;
733: dcl->idle = 1;
734: }
735: }
736: break;
737: case SDL_VIDEORESIZE:
738: {
739: SDL_ResizeEvent *rev = &ev->resize;
740: int bpp = real_screen->format->BitsPerPixel;
741: if (bpp != 16 && bpp != 32)
742: bpp = 32;
743: do_sdl_resize(rev->w, rev->h, bpp);
744: scaling_active = 1;
745: if (!is_buffer_shared(ds->surface)) {
746: ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds), ds_get_height(ds));
747: dpy_resize(ds);
748: }
749: vga_hw_invalidate();
750: vga_hw_update();
751: break;
752: }
753: default:
754: break;
755: }
756: }
757: }
758:
759: static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
760: {
761: SDL_Rect dst = { x, y, w, h };
762: SDL_FillRect(real_screen, &dst, c);
763: }
764:
765: static void sdl_mouse_warp(int x, int y, int on)
766: {
767: if (on) {
768: if (!guest_cursor)
769: sdl_show_cursor();
770: if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
771: SDL_SetCursor(guest_sprite);
772: if (!kbd_mouse_is_absolute() && !absolute_enabled)
773: SDL_WarpMouse(x, y);
774: }
775: } else if (gui_grab)
776: sdl_hide_cursor();
777: guest_cursor = on;
778: guest_x = x, guest_y = y;
779: }
780:
781: static void sdl_mouse_define(QEMUCursor *c)
782: {
783: uint8_t *image, *mask;
784: int bpl;
785:
786: if (guest_sprite)
787: SDL_FreeCursor(guest_sprite);
788:
789: bpl = cursor_get_mono_bpl(c);
790: image = qemu_mallocz(bpl * c->height);
791: mask = qemu_mallocz(bpl * c->height);
792: cursor_get_mono_image(c, 0x000000, image);
793: cursor_get_mono_mask(c, 0, mask);
794: guest_sprite = SDL_CreateCursor(image, mask, c->width, c->height,
795: c->hot_x, c->hot_y);
796: qemu_free(image);
797: qemu_free(mask);
798:
799: if (guest_cursor &&
800: (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
801: SDL_SetCursor(guest_sprite);
802: }
803:
804: static void sdl_cleanup(void)
805: {
806: if (guest_sprite)
807: SDL_FreeCursor(guest_sprite);
808: SDL_QuitSubSystem(SDL_INIT_VIDEO);
809: }
810:
811: void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
812: {
813: int flags;
814: uint8_t data = 0;
815: DisplayAllocator *da;
816: const SDL_VideoInfo *vi;
817:
818: #if defined(__APPLE__)
819: /* always use generic keymaps */
820: if (!keyboard_layout)
821: keyboard_layout = "en-us";
822: #endif
823: if(keyboard_layout) {
824: kbd_layout = init_keyboard_layout(name2keysym, keyboard_layout);
825: if (!kbd_layout)
826: exit(1);
827: }
828:
829: if (no_frame)
830: gui_noframe = 1;
831:
832: if (!full_screen) {
833: setenv("SDL_VIDEO_ALLOW_SCREENSAVER", "1", 0);
834: }
835:
836: flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
837: if (SDL_Init (flags)) {
838: fprintf(stderr, "Could not initialize SDL(%s) - exiting\n",
839: SDL_GetError());
840: exit(1);
841: }
842: vi = SDL_GetVideoInfo();
843: host_format = *(vi->vfmt);
844:
845: dcl = qemu_mallocz(sizeof(DisplayChangeListener));
846: dcl->dpy_update = sdl_update;
847: dcl->dpy_resize = sdl_resize;
848: dcl->dpy_refresh = sdl_refresh;
849: dcl->dpy_setdata = sdl_setdata;
850: dcl->dpy_fill = sdl_fill;
851: ds->mouse_set = sdl_mouse_warp;
852: ds->cursor_define = sdl_mouse_define;
853: register_displaychangelistener(ds, dcl);
854:
855: da = qemu_mallocz(sizeof(DisplayAllocator));
856: da->create_displaysurface = sdl_create_displaysurface;
857: da->resize_displaysurface = sdl_resize_displaysurface;
858: da->free_displaysurface = sdl_free_displaysurface;
859: if (register_displayallocator(ds, da) == da) {
860: dpy_resize(ds);
861: }
862:
863: mouse_mode_notifier.notify = sdl_mouse_mode_change;
864: qemu_add_mouse_mode_change_notifier(&mouse_mode_notifier);
865:
866: sdl_update_caption();
867: SDL_EnableKeyRepeat(250, 50);
868: gui_grab = 0;
869:
870: sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
871: sdl_cursor_normal = SDL_GetCursor();
872:
873: atexit(sdl_cleanup);
874: if (full_screen) {
875: gui_fullscreen = 1;
876: gui_fullscreen_initial_grab = 1;
877: sdl_grab_start();
878: }
879: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.