sdl.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  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 "qemu-common.h"
  25. #include "console.h"
  26. #include "sysemu.h"
  27. #include "x_keymap.h"
  28. #include <SDL.h>
  29. #include <SDL_syswm.h>
  30. #ifndef _WIN32
  31. #include <signal.h>
  32. #endif
  33. static DisplayChangeListener *dcl;
  34. static SDL_Surface *real_screen;
  35. static SDL_Surface *guest_screen = NULL;
  36. static int gui_grab; /* if true, all keyboard/mouse events are grabbed */
  37. static int last_vm_running;
  38. static int gui_saved_grab;
  39. static int gui_fullscreen;
  40. static int gui_noframe;
  41. static int gui_key_modifier_pressed;
  42. static int gui_keysym;
  43. static int gui_fullscreen_initial_grab;
  44. static int gui_grab_code = KMOD_LALT | KMOD_LCTRL;
  45. static uint8_t modifiers_state[256];
  46. static int width, height;
  47. static SDL_Cursor *sdl_cursor_normal;
  48. static SDL_Cursor *sdl_cursor_hidden;
  49. static int absolute_enabled = 0;
  50. static int guest_cursor = 0;
  51. static int guest_x, guest_y;
  52. static SDL_Cursor *guest_sprite = 0;
  53. static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
  54. {
  55. SDL_Rect rec;
  56. rec.x = x;
  57. rec.y = y;
  58. rec.w = w;
  59. rec.h = h;
  60. // printf("updating x=%d y=%d w=%d h=%d\n", x, y, w, h);
  61. SDL_BlitSurface(guest_screen, &rec, real_screen, &rec);
  62. SDL_UpdateRect(real_screen, x, y, w, h);
  63. }
  64. static void sdl_setdata(DisplayState *ds)
  65. {
  66. SDL_Rect rec;
  67. rec.x = 0;
  68. rec.y = 0;
  69. rec.w = real_screen->w;
  70. rec.h = real_screen->h;
  71. if (guest_screen != NULL) SDL_FreeSurface(guest_screen);
  72. guest_screen = SDL_CreateRGBSurfaceFrom(ds_get_data(ds), ds_get_width(ds), ds_get_height(ds),
  73. ds_get_bits_per_pixel(ds), ds_get_linesize(ds),
  74. ds->surface->pf.rmask, ds->surface->pf.gmask,
  75. ds->surface->pf.bmask, ds->surface->pf.amask);
  76. }
  77. static void sdl_resize(DisplayState *ds)
  78. {
  79. int flags;
  80. // printf("resizing to %d %d\n", w, h);
  81. flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
  82. if (gui_fullscreen)
  83. flags |= SDL_FULLSCREEN;
  84. if (gui_noframe)
  85. flags |= SDL_NOFRAME;
  86. width = ds_get_width(ds);
  87. height = ds_get_height(ds);
  88. real_screen = SDL_SetVideoMode(width, height, 0, flags);
  89. if (!real_screen) {
  90. fprintf(stderr, "Could not open SDL display\n");
  91. exit(1);
  92. }
  93. sdl_setdata(ds);
  94. }
  95. /* generic keyboard conversion */
  96. #include "sdl_keysym.h"
  97. #include "keymaps.c"
  98. static kbd_layout_t *kbd_layout = NULL;
  99. static uint8_t sdl_keyevent_to_keycode_generic(const SDL_KeyboardEvent *ev)
  100. {
  101. int keysym;
  102. /* workaround for X11+SDL bug with AltGR */
  103. keysym = ev->keysym.sym;
  104. if (keysym == 0 && ev->keysym.scancode == 113)
  105. keysym = SDLK_MODE;
  106. /* For Japanese key '\' and '|' */
  107. if (keysym == 92 && ev->keysym.scancode == 133) {
  108. keysym = 0xa5;
  109. }
  110. return keysym2scancode(kbd_layout, keysym);
  111. }
  112. /* specific keyboard conversions from scan codes */
  113. #if defined(_WIN32)
  114. static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
  115. {
  116. return ev->keysym.scancode;
  117. }
  118. #else
  119. #if defined(SDL_VIDEO_DRIVER_X11)
  120. #include <X11/XKBlib.h>
  121. static int check_for_evdev(void)
  122. {
  123. SDL_SysWMinfo info;
  124. XkbDescPtr desc = NULL;
  125. int has_evdev = 0;
  126. char *keycodes = NULL;
  127. SDL_VERSION(&info.version);
  128. if (!SDL_GetWMInfo(&info)) {
  129. return 0;
  130. }
  131. desc = XkbGetKeyboard(info.info.x11.display,
  132. XkbGBN_AllComponentsMask,
  133. XkbUseCoreKbd);
  134. if (desc && desc->names) {
  135. keycodes = XGetAtomName(info.info.x11.display, desc->names->keycodes);
  136. if (keycodes == NULL) {
  137. fprintf(stderr, "could not lookup keycode name\n");
  138. } else if (strstart(keycodes, "evdev", NULL)) {
  139. has_evdev = 1;
  140. } else if (!strstart(keycodes, "xfree86", NULL)) {
  141. fprintf(stderr, "unknown keycodes `%s', please report to "
  142. "qemu-devel@nongnu.org\n", keycodes);
  143. }
  144. }
  145. if (desc) {
  146. XkbFreeKeyboard(desc, XkbGBN_AllComponentsMask, True);
  147. }
  148. if (keycodes) {
  149. XFree(keycodes);
  150. }
  151. return has_evdev;
  152. }
  153. #else
  154. static int check_for_evdev(void)
  155. {
  156. return 0;
  157. }
  158. #endif
  159. static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
  160. {
  161. int keycode;
  162. static int has_evdev = -1;
  163. if (has_evdev == -1)
  164. has_evdev = check_for_evdev();
  165. keycode = ev->keysym.scancode;
  166. if (keycode < 9) {
  167. keycode = 0;
  168. } else if (keycode < 97) {
  169. keycode -= 8; /* just an offset */
  170. } else if (keycode < 158) {
  171. /* use conversion table */
  172. if (has_evdev)
  173. keycode = translate_evdev_keycode(keycode - 97);
  174. else
  175. keycode = translate_xfree86_keycode(keycode - 97);
  176. } else if (keycode == 208) { /* Hiragana_Katakana */
  177. keycode = 0x70;
  178. } else if (keycode == 211) { /* backslash */
  179. keycode = 0x73;
  180. } else {
  181. keycode = 0;
  182. }
  183. return keycode;
  184. }
  185. #endif
  186. static void reset_keys(void)
  187. {
  188. int i;
  189. for(i = 0; i < 256; i++) {
  190. if (modifiers_state[i]) {
  191. if (i & 0x80)
  192. kbd_put_keycode(0xe0);
  193. kbd_put_keycode(i | 0x80);
  194. modifiers_state[i] = 0;
  195. }
  196. }
  197. }
  198. static void sdl_process_key(SDL_KeyboardEvent *ev)
  199. {
  200. int keycode, v;
  201. if (ev->keysym.sym == SDLK_PAUSE) {
  202. /* specific case */
  203. v = 0;
  204. if (ev->type == SDL_KEYUP)
  205. v |= 0x80;
  206. kbd_put_keycode(0xe1);
  207. kbd_put_keycode(0x1d | v);
  208. kbd_put_keycode(0x45 | v);
  209. return;
  210. }
  211. if (kbd_layout) {
  212. keycode = sdl_keyevent_to_keycode_generic(ev);
  213. } else {
  214. keycode = sdl_keyevent_to_keycode(ev);
  215. }
  216. switch(keycode) {
  217. case 0x00:
  218. /* sent when leaving window: reset the modifiers state */
  219. reset_keys();
  220. return;
  221. case 0x2a: /* Left Shift */
  222. case 0x36: /* Right Shift */
  223. case 0x1d: /* Left CTRL */
  224. case 0x9d: /* Right CTRL */
  225. case 0x38: /* Left ALT */
  226. case 0xb8: /* Right ALT */
  227. if (ev->type == SDL_KEYUP)
  228. modifiers_state[keycode] = 0;
  229. else
  230. modifiers_state[keycode] = 1;
  231. break;
  232. case 0x45: /* num lock */
  233. case 0x3a: /* caps lock */
  234. /* SDL does not send the key up event, so we generate it */
  235. kbd_put_keycode(keycode);
  236. kbd_put_keycode(keycode | 0x80);
  237. return;
  238. }
  239. /* now send the key code */
  240. if (keycode & 0x80)
  241. kbd_put_keycode(0xe0);
  242. if (ev->type == SDL_KEYUP)
  243. kbd_put_keycode(keycode | 0x80);
  244. else
  245. kbd_put_keycode(keycode & 0x7f);
  246. }
  247. static void sdl_update_caption(void)
  248. {
  249. char buf[1024];
  250. const char *status = "";
  251. if (!vm_running)
  252. status = " [Stopped]";
  253. else if (gui_grab) {
  254. if (!alt_grab)
  255. status = " - Press Ctrl-Alt to exit grab";
  256. else
  257. status = " - Press Ctrl-Alt-Shift to exit grab";
  258. }
  259. if (qemu_name)
  260. snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status);
  261. else
  262. snprintf(buf, sizeof(buf), "QEMU%s", status);
  263. SDL_WM_SetCaption(buf, "QEMU");
  264. }
  265. static void sdl_hide_cursor(void)
  266. {
  267. if (!cursor_hide)
  268. return;
  269. if (kbd_mouse_is_absolute()) {
  270. SDL_ShowCursor(1);
  271. SDL_SetCursor(sdl_cursor_hidden);
  272. } else {
  273. SDL_ShowCursor(0);
  274. }
  275. }
  276. static void sdl_show_cursor(void)
  277. {
  278. if (!cursor_hide)
  279. return;
  280. if (!kbd_mouse_is_absolute()) {
  281. SDL_ShowCursor(1);
  282. if (guest_cursor &&
  283. (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
  284. SDL_SetCursor(guest_sprite);
  285. else
  286. SDL_SetCursor(sdl_cursor_normal);
  287. }
  288. }
  289. static void sdl_grab_start(void)
  290. {
  291. if (guest_cursor) {
  292. SDL_SetCursor(guest_sprite);
  293. if (!kbd_mouse_is_absolute() && !absolute_enabled)
  294. SDL_WarpMouse(guest_x, guest_y);
  295. } else
  296. sdl_hide_cursor();
  297. if (SDL_WM_GrabInput(SDL_GRAB_ON) == SDL_GRAB_ON) {
  298. gui_grab = 1;
  299. sdl_update_caption();
  300. } else
  301. sdl_show_cursor();
  302. }
  303. static void sdl_grab_end(void)
  304. {
  305. SDL_WM_GrabInput(SDL_GRAB_OFF);
  306. gui_grab = 0;
  307. sdl_show_cursor();
  308. sdl_update_caption();
  309. }
  310. static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state)
  311. {
  312. int buttons;
  313. buttons = 0;
  314. if (state & SDL_BUTTON(SDL_BUTTON_LEFT))
  315. buttons |= MOUSE_EVENT_LBUTTON;
  316. if (state & SDL_BUTTON(SDL_BUTTON_RIGHT))
  317. buttons |= MOUSE_EVENT_RBUTTON;
  318. if (state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
  319. buttons |= MOUSE_EVENT_MBUTTON;
  320. if (kbd_mouse_is_absolute()) {
  321. if (!absolute_enabled) {
  322. sdl_hide_cursor();
  323. if (gui_grab) {
  324. sdl_grab_end();
  325. }
  326. absolute_enabled = 1;
  327. }
  328. dx = x * 0x7FFF / (width - 1);
  329. dy = y * 0x7FFF / (height - 1);
  330. } else if (absolute_enabled) {
  331. sdl_show_cursor();
  332. absolute_enabled = 0;
  333. } else if (guest_cursor) {
  334. x -= guest_x;
  335. y -= guest_y;
  336. guest_x += x;
  337. guest_y += y;
  338. dx = x;
  339. dy = y;
  340. }
  341. kbd_mouse_event(dx, dy, dz, buttons);
  342. }
  343. static void toggle_full_screen(DisplayState *ds)
  344. {
  345. gui_fullscreen = !gui_fullscreen;
  346. sdl_resize(ds);
  347. if (gui_fullscreen) {
  348. gui_saved_grab = gui_grab;
  349. sdl_grab_start();
  350. } else {
  351. if (!gui_saved_grab)
  352. sdl_grab_end();
  353. }
  354. vga_hw_invalidate();
  355. vga_hw_update();
  356. }
  357. static void sdl_refresh(DisplayState *ds)
  358. {
  359. SDL_Event ev1, *ev = &ev1;
  360. int mod_state;
  361. int buttonstate = SDL_GetMouseState(NULL, NULL);
  362. if (last_vm_running != vm_running) {
  363. last_vm_running = vm_running;
  364. sdl_update_caption();
  365. }
  366. vga_hw_update();
  367. SDL_EnableUNICODE(!is_graphic_console());
  368. while (SDL_PollEvent(ev)) {
  369. switch (ev->type) {
  370. case SDL_VIDEOEXPOSE:
  371. sdl_update(ds, 0, 0, real_screen->w, real_screen->h);
  372. break;
  373. case SDL_KEYDOWN:
  374. case SDL_KEYUP:
  375. if (ev->type == SDL_KEYDOWN) {
  376. if (!alt_grab) {
  377. mod_state = (SDL_GetModState() & gui_grab_code) ==
  378. gui_grab_code;
  379. } else {
  380. mod_state = (SDL_GetModState() & (gui_grab_code | KMOD_LSHIFT)) ==
  381. (gui_grab_code | KMOD_LSHIFT);
  382. }
  383. gui_key_modifier_pressed = mod_state;
  384. if (gui_key_modifier_pressed) {
  385. int keycode;
  386. keycode = sdl_keyevent_to_keycode(&ev->key);
  387. switch(keycode) {
  388. case 0x21: /* 'f' key on US keyboard */
  389. toggle_full_screen(ds);
  390. gui_keysym = 1;
  391. break;
  392. case 0x02 ... 0x0a: /* '1' to '9' keys */
  393. /* Reset the modifiers sent to the current console */
  394. reset_keys();
  395. console_select(keycode - 0x02);
  396. if (!is_graphic_console()) {
  397. /* display grab if going to a text console */
  398. if (gui_grab)
  399. sdl_grab_end();
  400. }
  401. gui_keysym = 1;
  402. break;
  403. default:
  404. break;
  405. }
  406. } else if (!is_graphic_console()) {
  407. int keysym;
  408. keysym = 0;
  409. if (ev->key.keysym.mod & (KMOD_LCTRL | KMOD_RCTRL)) {
  410. switch(ev->key.keysym.sym) {
  411. case SDLK_UP: keysym = QEMU_KEY_CTRL_UP; break;
  412. case SDLK_DOWN: keysym = QEMU_KEY_CTRL_DOWN; break;
  413. case SDLK_LEFT: keysym = QEMU_KEY_CTRL_LEFT; break;
  414. case SDLK_RIGHT: keysym = QEMU_KEY_CTRL_RIGHT; break;
  415. case SDLK_HOME: keysym = QEMU_KEY_CTRL_HOME; break;
  416. case SDLK_END: keysym = QEMU_KEY_CTRL_END; break;
  417. case SDLK_PAGEUP: keysym = QEMU_KEY_CTRL_PAGEUP; break;
  418. case SDLK_PAGEDOWN: keysym = QEMU_KEY_CTRL_PAGEDOWN; break;
  419. default: break;
  420. }
  421. } else {
  422. switch(ev->key.keysym.sym) {
  423. case SDLK_UP: keysym = QEMU_KEY_UP; break;
  424. case SDLK_DOWN: keysym = QEMU_KEY_DOWN; break;
  425. case SDLK_LEFT: keysym = QEMU_KEY_LEFT; break;
  426. case SDLK_RIGHT: keysym = QEMU_KEY_RIGHT; break;
  427. case SDLK_HOME: keysym = QEMU_KEY_HOME; break;
  428. case SDLK_END: keysym = QEMU_KEY_END; break;
  429. case SDLK_PAGEUP: keysym = QEMU_KEY_PAGEUP; break;
  430. case SDLK_PAGEDOWN: keysym = QEMU_KEY_PAGEDOWN; break;
  431. case SDLK_BACKSPACE: keysym = QEMU_KEY_BACKSPACE; break;
  432. case SDLK_DELETE: keysym = QEMU_KEY_DELETE; break;
  433. default: break;
  434. }
  435. }
  436. if (keysym) {
  437. kbd_put_keysym(keysym);
  438. } else if (ev->key.keysym.unicode != 0) {
  439. kbd_put_keysym(ev->key.keysym.unicode);
  440. }
  441. }
  442. } else if (ev->type == SDL_KEYUP) {
  443. if (!alt_grab) {
  444. mod_state = (ev->key.keysym.mod & gui_grab_code);
  445. } else {
  446. mod_state = (ev->key.keysym.mod &
  447. (gui_grab_code | KMOD_LSHIFT));
  448. }
  449. if (!mod_state) {
  450. if (gui_key_modifier_pressed) {
  451. gui_key_modifier_pressed = 0;
  452. if (gui_keysym == 0) {
  453. /* exit/enter grab if pressing Ctrl-Alt */
  454. if (!gui_grab) {
  455. /* if the application is not active,
  456. do not try to enter grab state. It
  457. prevents
  458. 'SDL_WM_GrabInput(SDL_GRAB_ON)'
  459. from blocking all the application
  460. (SDL bug). */
  461. if (SDL_GetAppState() & SDL_APPACTIVE)
  462. sdl_grab_start();
  463. } else {
  464. sdl_grab_end();
  465. }
  466. /* SDL does not send back all the
  467. modifiers key, so we must correct it */
  468. reset_keys();
  469. break;
  470. }
  471. gui_keysym = 0;
  472. }
  473. }
  474. }
  475. if (is_graphic_console() && !gui_keysym)
  476. sdl_process_key(&ev->key);
  477. break;
  478. case SDL_QUIT:
  479. if (!no_quit)
  480. qemu_system_shutdown_request();
  481. break;
  482. case SDL_MOUSEMOTION:
  483. if (gui_grab || kbd_mouse_is_absolute() ||
  484. absolute_enabled) {
  485. sdl_send_mouse_event(ev->motion.xrel, ev->motion.yrel, 0,
  486. ev->motion.x, ev->motion.y, ev->motion.state);
  487. }
  488. break;
  489. case SDL_MOUSEBUTTONDOWN:
  490. case SDL_MOUSEBUTTONUP:
  491. {
  492. SDL_MouseButtonEvent *bev = &ev->button;
  493. if (!gui_grab && !kbd_mouse_is_absolute()) {
  494. if (ev->type == SDL_MOUSEBUTTONDOWN &&
  495. (bev->button == SDL_BUTTON_LEFT)) {
  496. /* start grabbing all events */
  497. sdl_grab_start();
  498. }
  499. } else {
  500. int dz;
  501. dz = 0;
  502. if (ev->type == SDL_MOUSEBUTTONDOWN) {
  503. buttonstate |= SDL_BUTTON(bev->button);
  504. } else {
  505. buttonstate &= ~SDL_BUTTON(bev->button);
  506. }
  507. #ifdef SDL_BUTTON_WHEELUP
  508. if (bev->button == SDL_BUTTON_WHEELUP && ev->type == SDL_MOUSEBUTTONDOWN) {
  509. dz = -1;
  510. } else if (bev->button == SDL_BUTTON_WHEELDOWN && ev->type == SDL_MOUSEBUTTONDOWN) {
  511. dz = 1;
  512. }
  513. #endif
  514. sdl_send_mouse_event(0, 0, dz, bev->x, bev->y, buttonstate);
  515. }
  516. }
  517. break;
  518. case SDL_ACTIVEEVENT:
  519. if (gui_grab && ev->active.state == SDL_APPINPUTFOCUS &&
  520. !ev->active.gain && !gui_fullscreen_initial_grab) {
  521. sdl_grab_end();
  522. }
  523. if (ev->active.state & SDL_APPACTIVE) {
  524. if (ev->active.gain) {
  525. /* Back to default interval */
  526. dcl->gui_timer_interval = 0;
  527. dcl->idle = 0;
  528. } else {
  529. /* Sleeping interval */
  530. dcl->gui_timer_interval = 500;
  531. dcl->idle = 1;
  532. }
  533. }
  534. break;
  535. default:
  536. break;
  537. }
  538. }
  539. }
  540. static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
  541. {
  542. SDL_Rect dst = { x, y, w, h };
  543. SDL_FillRect(real_screen, &dst, c);
  544. }
  545. static void sdl_mouse_warp(int x, int y, int on)
  546. {
  547. if (on) {
  548. if (!guest_cursor)
  549. sdl_show_cursor();
  550. if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
  551. SDL_SetCursor(guest_sprite);
  552. if (!kbd_mouse_is_absolute() && !absolute_enabled)
  553. SDL_WarpMouse(x, y);
  554. }
  555. } else if (gui_grab)
  556. sdl_hide_cursor();
  557. guest_cursor = on;
  558. guest_x = x, guest_y = y;
  559. }
  560. static void sdl_mouse_define(int width, int height, int bpp,
  561. int hot_x, int hot_y,
  562. uint8_t *image, uint8_t *mask)
  563. {
  564. uint8_t sprite[256], *line;
  565. int x, y, dst, bypl, src = 0;
  566. if (guest_sprite)
  567. SDL_FreeCursor(guest_sprite);
  568. memset(sprite, 0, 256);
  569. bypl = ((width * bpp + 31) >> 5) << 2;
  570. for (y = 0, dst = 0; y < height; y ++, image += bypl) {
  571. line = image;
  572. for (x = 0; x < width; x ++, dst ++) {
  573. switch (bpp) {
  574. case 24:
  575. src = *(line ++); src |= *(line ++); src |= *(line ++);
  576. break;
  577. case 16:
  578. case 15:
  579. src = *(line ++); src |= *(line ++);
  580. break;
  581. case 8:
  582. src = *(line ++);
  583. break;
  584. case 4:
  585. src = 0xf & (line[x >> 1] >> ((x & 1)) << 2);
  586. break;
  587. case 2:
  588. src = 3 & (line[x >> 2] >> ((x & 3)) << 1);
  589. break;
  590. case 1:
  591. src = 1 & (line[x >> 3] >> (x & 7));
  592. break;
  593. }
  594. if (!src)
  595. sprite[dst >> 3] |= (1 << (~dst & 7)) & mask[dst >> 3];
  596. }
  597. }
  598. guest_sprite = SDL_CreateCursor(sprite, mask, width, height, hot_x, hot_y);
  599. if (guest_cursor &&
  600. (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
  601. SDL_SetCursor(guest_sprite);
  602. }
  603. static void sdl_cleanup(void)
  604. {
  605. if (guest_sprite)
  606. SDL_FreeCursor(guest_sprite);
  607. SDL_Quit();
  608. }
  609. void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
  610. {
  611. int flags;
  612. uint8_t data = 0;
  613. #if defined(__APPLE__)
  614. /* always use generic keymaps */
  615. if (!keyboard_layout)
  616. keyboard_layout = "en-us";
  617. #endif
  618. if(keyboard_layout) {
  619. kbd_layout = init_keyboard_layout(keyboard_layout);
  620. if (!kbd_layout)
  621. exit(1);
  622. }
  623. if (no_frame)
  624. gui_noframe = 1;
  625. flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
  626. if (SDL_Init (flags)) {
  627. fprintf(stderr, "Could not initialize SDL - exiting\n");
  628. exit(1);
  629. }
  630. dcl = qemu_mallocz(sizeof(DisplayChangeListener));
  631. dcl->dpy_update = sdl_update;
  632. dcl->dpy_resize = sdl_resize;
  633. dcl->dpy_refresh = sdl_refresh;
  634. dcl->dpy_setdata = sdl_setdata;
  635. dcl->dpy_fill = sdl_fill;
  636. ds->mouse_set = sdl_mouse_warp;
  637. ds->cursor_define = sdl_mouse_define;
  638. register_displaychangelistener(ds, dcl);
  639. sdl_update_caption();
  640. SDL_EnableKeyRepeat(250, 50);
  641. gui_grab = 0;
  642. sdl_cursor_hidden = SDL_CreateCursor(&data, &data, 8, 1, 0, 0);
  643. sdl_cursor_normal = SDL_GetCursor();
  644. atexit(sdl_cleanup);
  645. if (full_screen) {
  646. gui_fullscreen = 1;
  647. gui_fullscreen_initial_grab = 1;
  648. sdl_grab_start();
  649. }
  650. }