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