|
|
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: if (surface == NULL) {
171: fprintf(stderr, "sdl_create_displaysurface: malloc failed\n");
172: exit(1);
173: }
174:
175: surface->width = width;
176: surface->height = height;
1.1.1.3 root 177:
1.1 root 178: if (scaling_active) {
1.1.1.3 root 179: int linesize;
180: PixelFormat pf;
1.1 root 181: if (host_format.BytesPerPixel != 2 && host_format.BytesPerPixel != 4) {
1.1.1.3 root 182: linesize = width * 4;
183: pf = qemu_default_pixelformat(32);
1.1 root 184: } else {
1.1.1.3 root 185: linesize = width * host_format.BytesPerPixel;
186: pf = sdl_to_qemu_pixelformat(&host_format);
1.1 root 187: }
1.1.1.3 root 188: qemu_alloc_display(surface, width, height, linesize, pf, 0);
1.1 root 189: return surface;
190: }
191:
192: if (host_format.BitsPerPixel == 16)
193: do_sdl_resize(width, height, 16);
194: else
195: do_sdl_resize(width, height, 32);
196:
197: surface->pf = sdl_to_qemu_pixelformat(real_screen->format);
198: surface->linesize = real_screen->pitch;
199: surface->data = real_screen->pixels;
200:
201: #ifdef HOST_WORDS_BIGENDIAN
202: surface->flags = QEMU_REALPIXELS_FLAG | QEMU_BIG_ENDIAN_FLAG;
203: #else
204: surface->flags = QEMU_REALPIXELS_FLAG;
205: #endif
206: allocator = 1;
207:
208: return surface;
209: }
210:
211: static void sdl_free_displaysurface(DisplaySurface *surface)
212: {
213: allocator = 0;
214: if (surface == NULL)
215: return;
216:
217: if (surface->flags & QEMU_ALLOCATED_FLAG)
1.1.1.4 ! root 218: g_free(surface->data);
! 219: g_free(surface);
1.1 root 220: }
221:
222: static DisplaySurface* sdl_resize_displaysurface(DisplaySurface *surface, int width, int height)
223: {
224: sdl_free_displaysurface(surface);
225: return sdl_create_displaysurface(width, height);
226: }
227:
228: /* generic keyboard conversion */
229:
230: #include "sdl_keysym.h"
231:
232: static kbd_layout_t *kbd_layout = NULL;
233:
234: static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
235: {
236: int keysym;
237: /* workaround for X11+SDL bug with AltGR */
238: keysym = ev->keysym.sym;
239: if (keysym == 0 && ev->keysym.scancode == 113)
240: keysym = SDLK_MODE;
241: /* For Japanese key '\' and '|' */
242: if (keysym == 92 && ev->keysym.scancode == 133) {
243: keysym = 0xa5;
244: }
245: return keysym2scancode(kbd_layout, keysym) & SCANCODE_KEYMASK;
246: }
247:
248: /* specific keyboard conversions from scan codes */
249:
250: #if defined(_WIN32)
251:
252: static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
253: {
254: return ev->keysym.scancode;
255: }
256:
257: #else
258:
259: #if defined(SDL_VIDEO_DRIVER_X11)
260: #include <X11/XKBlib.h>
261:
262: static int check_for_evdev(void)
263: {
264: SDL_SysWMinfo info;
265: XkbDescPtr desc = NULL;
266: int has_evdev = 0;
267: char *keycodes = NULL;
268:
269: SDL_VERSION(&info.version);
270: if (!SDL_GetWMInfo(&info)) {
271: return 0;
272: }
273: desc = XkbGetKeyboard(info.info.x11.display,
274: XkbGBN_AllComponentsMask,
275: XkbUseCoreKbd);
276: if (desc && desc->names) {
277: keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
278: if (keycodes == NULL) {
279: fprintf(stderr, "could not lookup keycode name\n");
280: } else if (strstart(keycodes, "evdev", NULL)) {
281: has_evdev = 1;
282: } else if (!strstart(keycodes, "xfree86", NULL)) {
283: fprintf(stderr, "unknown keycodes `%s', please report to "
284: "[email protected]\n", keycodes);
285: }
286: }
287:
288: if (desc) {
289: XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
290: }
291: if (keycodes) {
292: XFree(keycodes);
293: }
294: return has_evdev;
295: }
296: #else
297: static int check_for_evdev(void)
298: {
299: return 0;
300: }
301: #endif
302:
303: static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
304: {
305: int keycode;
306: static int has_evdev = -1;
307:
308: if (has_evdev == -1)
309: has_evdev = check_for_evdev();
310:
311: keycode = ev->keysym.scancode;
312:
313: if (keycode < 9) {
314: keycode = 0;
315: } else if (keycode < 97) {
316: keycode -= 8; /* just an offset */
317: } else if (keycode < 158) {
318: /* use conversion table */
319: if (has_evdev)
320: keycode = translate_evdev_keycode(keycode - 97);
321: else
322: keycode = translate_xfree86_keycode(keycode - 97);
323: } else if (keycode == 208) { /* Hiragana_Katakana */
324: keycode = 0x70;
325: } else if (keycode == 211) { /* backslash */
326: keycode = 0x73;
327: } else {
328: keycode = 0;
329: }
330: return keycode;
331: }
332:
333: #endif
334:
335: static void reset_keys(void)
336: {
337: int i;
338: for(i = 0; i < 256; i++) {
339: if (modifiers_state[i]) {
340: if (i & SCANCODE_GREY)
341: kbd_put_keycode(SCANCODE_EMUL0);
342: kbd_put_keycode(i | SCANCODE_UP);
343: modifiers_state[i] = 0;
344: }
345: }
346: }
347:
348: static void sdl_process_key(SDL_KeyboardEvent *ev)
349: {
350: int keycode, v;
351:
352: if (ev->keysym.sym == SDLK_PAUSE) {
353: /* specific case */
354: v = 0;
355: if (ev->type == SDL_KEYUP)
356: v |= SCANCODE_UP;
357: kbd_put_keycode(0xe1);
358: kbd_put_keycode(0x1d | v);
359: kbd_put_keycode(0x45 | v);
360: return;
361: }
362:
363: if (kbd_layout) {
364: keycode = sdl_keyevent_to_keycode_generic(ev);
365: } else {
366: keycode = sdl_keyevent_to_keycode(ev);
367: }
368:
369: switch(keycode) {
370: case 0x00:
371: /* sent when leaving window: reset the modifiers state */
372: reset_keys();
373: return;
374: case 0x2a: /* Left Shift */
375: case 0x36: /* Right Shift */
376: case 0x1d: /* Left CTRL */
377: case 0x9d: /* Right CTRL */
378: case 0x38: /* Left ALT */
379: case 0xb8: /* Right ALT */
380: if (ev->type == SDL_KEYUP)
381: modifiers_state[keycode] = 0;
382: else
383: modifiers_state[keycode] = 1;
384: break;
1.1.1.2 root 385: #define QEMU_SDL_VERSION ((SDL_MAJOR_VERSION << 8) + SDL_MINOR_VERSION)
386: #if QEMU_SDL_VERSION < 0x102 || QEMU_SDL_VERSION == 0x102 && SDL_PATCHLEVEL < 14
387: /* SDL versions before 1.2.14 don't support key up for caps/num lock. */
1.1 root 388: case 0x45: /* num lock */
389: case 0x3a: /* caps lock */
390: /* SDL does not send the key up event, so we generate it */
391: kbd_put_keycode(keycode);
392: kbd_put_keycode(keycode | SCANCODE_UP);
393: return;
1.1.1.2 root 394: #endif
1.1 root 395: }
396:
397: /* now send the key code */
398: if (keycode & SCANCODE_GREY)
399: kbd_put_keycode(SCANCODE_EMUL0);
400: if (ev->type == SDL_KEYUP)
401: kbd_put_keycode(keycode | SCANCODE_UP);
402: else
403: kbd_put_keycode(keycode & SCANCODE_KEYCODEMASK);
404: }
405:
406: static void sdl_update_caption(void)
407: {
408: char win_title[1024];
409: char icon_title[1024];
410: const char *status = "";
411:
1.1.1.4 ! root 412: if (!runstate_is_running())
1.1 root 413: status = " [Stopped]";
414: else if (gui_grab) {
415: if (alt_grab)
416: status = " - Press Ctrl-Alt-Shift to exit mouse grab";
417: else if (ctrl_grab)
418: status = " - Press Right-Ctrl to exit mouse grab";
419: else
420: status = " - Press Ctrl-Alt to exit mouse grab";
421: }
422:
423: if (qemu_name) {
424: snprintf(win_title, sizeof(win_title), "QEMU (%s)%s", qemu_name, status);
425: snprintf(icon_title, sizeof(icon_title), "QEMU (%s)", qemu_name);
426: } else {
427: snprintf(win_title, sizeof(win_title), "QEMU%s", status);
428: snprintf(icon_title, sizeof(icon_title), "QEMU");
429: }
430:
431: SDL_WM_SetCaption(win_title, icon_title);
432: }
433:
434: static void sdl_hide_cursor(void)
435: {
436: if (!cursor_hide)
437: return;
438:
439: if (kbd_mouse_is_absolute()) {
440: SDL_ShowCursor(1);
441: SDL_SetCursor(sdl_cursor_hidden);
442: } else {
443: SDL_ShowCursor(0);
444: }
445: }
446:
447: static void sdl_show_cursor(void)
448: {
449: if (!cursor_hide)
450: return;
451:
1.1.1.4 ! root 452: if (!kbd_mouse_is_absolute() || !is_graphic_console()) {
1.1 root 453: SDL_ShowCursor(1);
454: if (guest_cursor &&
455: (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
456: SDL_SetCursor(guest_sprite);
457: else
458: SDL_SetCursor(sdl_cursor_normal);
459: }
460: }
461:
462: static void sdl_grab_start(void)
463: {
464: if (guest_cursor) {
465: SDL_SetCursor(guest_sprite);
466: if (!kbd_mouse_is_absolute() && !absolute_enabled)
467: SDL_WarpMouse(guest_x, guest_y);
468: } else
469: sdl_hide_cursor();
470:
471: if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
472: gui_grab = 1;
473: sdl_update_caption();
474: } else
475: sdl_show_cursor();
476: }
477:
478: static void sdl_grab_end(void)
479: {
480: SDL_WM_GrabInput(SDL_GRAB_OFF);
481: gui_grab = 0;
482: sdl_show_cursor();
483: sdl_update_caption();
484: }
485:
1.1.1.3 root 486: static void sdl_mouse_mode_change(Notifier *notify, void *data)
1.1 root 487: {
488: if (kbd_mouse_is_absolute()) {
489: if (!absolute_enabled) {
1.1.1.4 ! root 490: sdl_grab_start();
1.1 root 491: absolute_enabled = 1;
492: }
493: } else if (absolute_enabled) {
1.1.1.4 ! root 494: if (!gui_fullscreen) {
! 495: sdl_grab_end();
! 496: }
! 497: absolute_enabled = 0;
1.1 root 498: }
499: }
500:
501: static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
502: {
1.1.1.4 ! root 503: int buttons = 0;
! 504:
! 505: if (state & SDL_BUTTON(SDL_BUTTON_LEFT)) {
1.1 root 506: buttons |= MOUSE_EVENT_LBUTTON;
1.1.1.4 ! root 507: }
! 508: if (state & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
1.1 root 509: buttons |= MOUSE_EVENT_RBUTTON;
1.1.1.4 ! root 510: }
! 511: if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE)) {
1.1 root 512: buttons |= MOUSE_EVENT_MBUTTON;
1.1.1.4 ! root 513: }
1.1 root 514:
515: if (kbd_mouse_is_absolute()) {
1.1.1.4 ! root 516: dx = x * 0x7FFF / (real_screen->w - 1);
! 517: dy = y * 0x7FFF / (real_screen->h - 1);
1.1 root 518: } else if (guest_cursor) {
519: x -= guest_x;
520: y -= guest_y;
521: guest_x += x;
522: guest_y += y;
523: dx = x;
524: dy = y;
525: }
526:
527: kbd_mouse_event(dx, dy, dz, buttons);
528: }
529:
1.1.1.4 ! root 530: static void sdl_scale(DisplayState *ds, int width, int height)
! 531: {
! 532: int bpp = real_screen->format->BitsPerPixel;
! 533:
! 534: if (bpp != 16 && bpp != 32) {
! 535: bpp = 32;
! 536: }
! 537: do_sdl_resize(width, height, bpp);
! 538: scaling_active = 1;
! 539: if (!is_buffer_shared(ds->surface)) {
! 540: ds->surface = qemu_resize_displaysurface(ds, ds_get_width(ds),
! 541: ds_get_height(ds));
! 542: dpy_resize(ds);
! 543: }
! 544: }
! 545:
1.1 root 546: static void toggle_full_screen(DisplayState *ds)
547: {
548: gui_fullscreen = !gui_fullscreen;
549: if (gui_fullscreen) {
1.1.1.4 ! root 550: gui_saved_width = real_screen->w;
! 551: gui_saved_height = real_screen->h;
! 552: gui_saved_scaling = scaling_active;
! 553:
! 554: do_sdl_resize(ds_get_width(ds), ds_get_height(ds),
! 555: ds_get_bits_per_pixel(ds));
1.1 root 556: scaling_active = 0;
1.1.1.4 ! root 557:
1.1 root 558: gui_saved_grab = gui_grab;
559: sdl_grab_start();
560: } else {
1.1.1.4 ! root 561: if (gui_saved_scaling) {
! 562: sdl_scale(ds, gui_saved_width, gui_saved_height);
! 563: } else {
! 564: do_sdl_resize(ds_get_width(ds), ds_get_height(ds), 0);
! 565: }
! 566: if (!gui_saved_grab || !is_graphic_console()) {
1.1 root 567: sdl_grab_end();
1.1.1.4 ! root 568: }
1.1 root 569: }
570: vga_hw_invalidate();
571: vga_hw_update();
572: }
573:
1.1.1.4 ! root 574: static void absolute_mouse_grab(void)
! 575: {
! 576: int mouse_x, mouse_y;
! 577:
! 578: if (SDL_GetAppState() & SDL_APPINPUTFOCUS) {
! 579: SDL_GetMouseState(&mouse_x, &mouse_y);
! 580: if (mouse_x > 0 && mouse_x < real_screen->w - 1 &&
! 581: mouse_y > 0 && mouse_y < real_screen->h - 1) {
! 582: sdl_grab_start();
! 583: }
! 584: }
! 585: }
! 586:
! 587: static void handle_keydown(DisplayState *ds, SDL_Event *ev)
! 588: {
! 589: int mod_state;
! 590: int keycode;
! 591:
! 592: if (alt_grab) {
! 593: mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
! 594: (gui_grab_code | KMOD_LSHIFT);
! 595: } else if (ctrl_grab) {
! 596: mod_state = (SDL_GetModState() & KMOD_RCTRL) == KMOD_RCTRL;
! 597: } else {
! 598: mod_state = (SDL_GetModState() & gui_grab_code) == gui_grab_code;
! 599: }
! 600: gui_key_modifier_pressed = mod_state;
! 601:
! 602: if (gui_key_modifier_pressed) {
! 603: keycode = sdl_keyevent_to_keycode(&ev->key);
! 604: switch (keycode) {
! 605: case 0x21: /* 'f' key on US keyboard */
! 606: toggle_full_screen(ds);
! 607: gui_keysym = 1;
! 608: break;
! 609: case 0x16: /* 'u' key on US keyboard */
! 610: if (scaling_active) {
! 611: scaling_active = 0;
! 612: sdl_resize(ds);
! 613: vga_hw_invalidate();
! 614: vga_hw_update();
! 615: }
! 616: gui_keysym = 1;
! 617: break;
! 618: case 0x02 ... 0x0a: /* '1' to '9' keys */
! 619: /* Reset the modifiers sent to the current console */
! 620: reset_keys();
! 621: console_select(keycode - 0x02);
! 622: gui_keysym = 1;
! 623: if (gui_fullscreen) {
! 624: break;
! 625: }
! 626: if (!is_graphic_console()) {
! 627: /* release grab if going to a text console */
! 628: if (gui_grab) {
! 629: sdl_grab_end();
! 630: } else if (absolute_enabled) {
! 631: sdl_show_cursor();
! 632: }
! 633: } else if (absolute_enabled) {
! 634: sdl_hide_cursor();
! 635: absolute_mouse_grab();
! 636: }
! 637: break;
! 638: case 0x1b: /* '+' */
! 639: case 0x35: /* '-' */
! 640: if (!gui_fullscreen) {
! 641: int width = MAX(real_screen->w + (keycode == 0x1b ? 50 : -50),
! 642: 160);
! 643: int height = (ds_get_height(ds) * width) / ds_get_width(ds);
! 644:
! 645: sdl_scale(ds, width, height);
! 646: vga_hw_invalidate();
! 647: vga_hw_update();
! 648: gui_keysym = 1;
! 649: }
! 650: default:
! 651: break;
! 652: }
! 653: } else if (!is_graphic_console()) {
! 654: int keysym = 0;
! 655:
! 656: if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
! 657: switch (ev->key.keysym.sym) {
! 658: case SDLK_UP:
! 659: keysym = QEMU_KEY_CTRL_UP;
! 660: break;
! 661: case SDLK_DOWN:
! 662: keysym = QEMU_KEY_CTRL_DOWN;
! 663: break;
! 664: case SDLK_LEFT:
! 665: keysym = QEMU_KEY_CTRL_LEFT;
! 666: break;
! 667: case SDLK_RIGHT:
! 668: keysym = QEMU_KEY_CTRL_RIGHT;
! 669: break;
! 670: case SDLK_HOME:
! 671: keysym = QEMU_KEY_CTRL_HOME;
! 672: break;
! 673: case SDLK_END:
! 674: keysym = QEMU_KEY_CTRL_END;
! 675: break;
! 676: case SDLK_PAGEUP:
! 677: keysym = QEMU_KEY_CTRL_PAGEUP;
! 678: break;
! 679: case SDLK_PAGEDOWN:
! 680: keysym = QEMU_KEY_CTRL_PAGEDOWN;
! 681: break;
! 682: default:
! 683: break;
! 684: }
! 685: } else {
! 686: switch (ev->key.keysym.sym) {
! 687: case SDLK_UP:
! 688: keysym = QEMU_KEY_UP;
! 689: break;
! 690: case SDLK_DOWN:
! 691: keysym = QEMU_KEY_DOWN;
! 692: break;
! 693: case SDLK_LEFT:
! 694: keysym = QEMU_KEY_LEFT;
! 695: break;
! 696: case SDLK_RIGHT:
! 697: keysym = QEMU_KEY_RIGHT;
! 698: break;
! 699: case SDLK_HOME:
! 700: keysym = QEMU_KEY_HOME;
! 701: break;
! 702: case SDLK_END:
! 703: keysym = QEMU_KEY_END;
! 704: break;
! 705: case SDLK_PAGEUP:
! 706: keysym = QEMU_KEY_PAGEUP;
! 707: break;
! 708: case SDLK_PAGEDOWN:
! 709: keysym = QEMU_KEY_PAGEDOWN;
! 710: break;
! 711: case SDLK_BACKSPACE:
! 712: keysym = QEMU_KEY_BACKSPACE;
! 713: break;
! 714: case SDLK_DELETE:
! 715: keysym = QEMU_KEY_DELETE;
! 716: break;
! 717: default:
! 718: break;
! 719: }
! 720: }
! 721: if (keysym) {
! 722: kbd_put_keysym(keysym);
! 723: } else if (ev->key.keysym.unicode != 0) {
! 724: kbd_put_keysym(ev->key.keysym.unicode);
! 725: }
! 726: }
! 727: if (is_graphic_console() && !gui_keysym) {
! 728: sdl_process_key(&ev->key);
! 729: }
! 730: }
! 731:
! 732: static void handle_keyup(DisplayState *ds, SDL_Event *ev)
1.1 root 733: {
734: int mod_state;
1.1.1.4 ! root 735:
! 736: if (!alt_grab) {
! 737: mod_state = (ev->key.keysym.mod & gui_grab_code);
! 738: } else {
! 739: mod_state = (ev->key.keysym.mod & (gui_grab_code | KMOD_LSHIFT));
! 740: }
! 741: if (!mod_state && gui_key_modifier_pressed) {
! 742: gui_key_modifier_pressed = 0;
! 743: if (gui_keysym == 0) {
! 744: /* exit/enter grab if pressing Ctrl-Alt */
! 745: if (!gui_grab) {
! 746: /* If the application is not active, do not try to enter grab
! 747: * state. It prevents 'SDL_WM_GrabInput(SDL_GRAB_ON)' from
! 748: * blocking all the application (SDL bug). */
! 749: if (is_graphic_console() &&
! 750: SDL_GetAppState() & SDL_APPACTIVE) {
! 751: sdl_grab_start();
! 752: }
! 753: } else if (!gui_fullscreen) {
! 754: sdl_grab_end();
! 755: }
! 756: /* SDL does not send back all the modifiers key, so we must
! 757: * correct it. */
! 758: reset_keys();
! 759: return;
! 760: }
! 761: gui_keysym = 0;
! 762: }
! 763: if (is_graphic_console() && !gui_keysym) {
! 764: sdl_process_key(&ev->key);
! 765: }
! 766: }
! 767:
! 768: static void handle_mousemotion(DisplayState *ds, SDL_Event *ev)
! 769: {
! 770: int max_x, max_y;
! 771:
! 772: if (is_graphic_console() &&
! 773: (kbd_mouse_is_absolute() || absolute_enabled)) {
! 774: max_x = real_screen->w - 1;
! 775: max_y = real_screen->h - 1;
! 776: if (gui_grab && (ev->motion.x == 0 || ev->motion.y == 0 ||
! 777: ev->motion.x == max_x || ev->motion.y == max_y)) {
! 778: sdl_grab_end();
! 779: }
! 780: if (!gui_grab && SDL_GetAppState() & SDL_APPINPUTFOCUS &&
! 781: (ev->motion.x > 0 && ev->motion.x < max_x &&
! 782: ev->motion.y > 0 && ev->motion.y < max_y)) {
! 783: sdl_grab_start();
! 784: }
! 785: }
! 786: if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
! 787: sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
! 788: ev->motion.x, ev->motion.y, ev->motion.state);
! 789: }
! 790: }
! 791:
! 792: static void handle_mousebutton(DisplayState *ds, SDL_Event *ev)
! 793: {
1.1 root 794: int buttonstate = SDL_GetMouseState(NULL, NULL);
1.1.1.4 ! root 795: SDL_MouseButtonEvent *bev;
! 796: int dz;
! 797:
! 798: if (!is_graphic_console()) {
! 799: return;
! 800: }
! 801:
! 802: bev = &ev->button;
! 803: if (!gui_grab && !kbd_mouse_is_absolute()) {
! 804: if (ev->type == SDL_MOUSEBUTTONDOWN &&
! 805: (bev->button == SDL_BUTTON_LEFT)) {
! 806: /* start grabbing all events */
! 807: sdl_grab_start();
! 808: }
! 809: } else {
! 810: dz = 0;
! 811: if (ev->type == SDL_MOUSEBUTTONDOWN) {
! 812: buttonstate |= SDL_BUTTON(bev->button);
! 813: } else {
! 814: buttonstate &= ~SDL_BUTTON(bev->button);
! 815: }
! 816: #ifdef SDL_BUTTON_WHEELUP
! 817: if (bev->button == SDL_BUTTON_WHEELUP &&
! 818: ev->type == SDL_MOUSEBUTTONDOWN) {
! 819: dz = -1;
! 820: } else if (bev->button == SDL_BUTTON_WHEELDOWN &&
! 821: ev->type == SDL_MOUSEBUTTONDOWN) {
! 822: dz = 1;
! 823: }
! 824: #endif
! 825: sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
! 826: }
! 827: }
! 828:
! 829: static void handle_activation(DisplayState *ds, SDL_Event *ev)
! 830: {
! 831: if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
! 832: !ev->active.gain && !gui_fullscreen) {
! 833: sdl_grab_end();
! 834: }
! 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.