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