dbus-console.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624
  1. /*
  2. * QEMU DBus display console
  3. *
  4. * Copyright (c) 2021 Marc-André Lureau <marcandre.lureau@redhat.com>
  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/osdep.h"
  25. #include "qemu/error-report.h"
  26. #include "qapi/error.h"
  27. #include "ui/input.h"
  28. #include "ui/kbd-state.h"
  29. #include "trace.h"
  30. #ifdef G_OS_UNIX
  31. #include <gio/gunixfdlist.h>
  32. #endif
  33. #include "dbus.h"
  34. static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX];
  35. struct _DBusDisplayConsole {
  36. GDBusObjectSkeleton parent_instance;
  37. DisplayChangeListener dcl;
  38. DBusDisplay *display;
  39. GHashTable *listeners;
  40. QemuDBusDisplay1Console *iface;
  41. QemuDBusDisplay1Keyboard *iface_kbd;
  42. QKbdState *kbd;
  43. QemuDBusDisplay1Mouse *iface_mouse;
  44. QemuDBusDisplay1MultiTouch *iface_touch;
  45. gboolean last_set;
  46. guint last_x;
  47. guint last_y;
  48. Notifier mouse_mode_notifier;
  49. };
  50. G_DEFINE_TYPE(DBusDisplayConsole,
  51. dbus_display_console,
  52. G_TYPE_DBUS_OBJECT_SKELETON)
  53. static void
  54. dbus_display_console_set_size(DBusDisplayConsole *ddc,
  55. uint32_t width, uint32_t height)
  56. {
  57. g_object_set(ddc->iface,
  58. "width", width,
  59. "height", height,
  60. NULL);
  61. }
  62. static void
  63. dbus_gfx_switch(DisplayChangeListener *dcl,
  64. struct DisplaySurface *new_surface)
  65. {
  66. DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl);
  67. dbus_display_console_set_size(ddc,
  68. surface_width(new_surface),
  69. surface_height(new_surface));
  70. }
  71. static void
  72. dbus_gfx_update(DisplayChangeListener *dcl,
  73. int x, int y, int w, int h)
  74. {
  75. }
  76. static void
  77. dbus_gl_scanout_disable(DisplayChangeListener *dcl)
  78. {
  79. }
  80. static void
  81. dbus_gl_scanout_texture(DisplayChangeListener *dcl,
  82. uint32_t tex_id,
  83. bool backing_y_0_top,
  84. uint32_t backing_width,
  85. uint32_t backing_height,
  86. uint32_t x, uint32_t y,
  87. uint32_t w, uint32_t h,
  88. void *d3d_tex2d)
  89. {
  90. DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl);
  91. dbus_display_console_set_size(ddc, w, h);
  92. }
  93. static void
  94. dbus_gl_scanout_dmabuf(DisplayChangeListener *dcl,
  95. QemuDmaBuf *dmabuf)
  96. {
  97. DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl);
  98. dbus_display_console_set_size(ddc,
  99. dmabuf->width,
  100. dmabuf->height);
  101. }
  102. static void
  103. dbus_gl_scanout_update(DisplayChangeListener *dcl,
  104. uint32_t x, uint32_t y,
  105. uint32_t w, uint32_t h)
  106. {
  107. }
  108. const DisplayChangeListenerOps dbus_console_dcl_ops = {
  109. .dpy_name = "dbus-console",
  110. .dpy_gfx_switch = dbus_gfx_switch,
  111. .dpy_gfx_update = dbus_gfx_update,
  112. .dpy_gl_scanout_disable = dbus_gl_scanout_disable,
  113. .dpy_gl_scanout_texture = dbus_gl_scanout_texture,
  114. .dpy_gl_scanout_dmabuf = dbus_gl_scanout_dmabuf,
  115. .dpy_gl_update = dbus_gl_scanout_update,
  116. };
  117. static void
  118. dbus_display_console_init(DBusDisplayConsole *object)
  119. {
  120. DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
  121. ddc->listeners = g_hash_table_new_full(g_str_hash, g_str_equal,
  122. NULL, g_object_unref);
  123. ddc->dcl.ops = &dbus_console_dcl_ops;
  124. }
  125. static void
  126. dbus_display_console_dispose(GObject *object)
  127. {
  128. DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
  129. unregister_displaychangelistener(&ddc->dcl);
  130. g_clear_object(&ddc->iface_touch);
  131. g_clear_object(&ddc->iface_mouse);
  132. g_clear_object(&ddc->iface_kbd);
  133. g_clear_object(&ddc->iface);
  134. g_clear_pointer(&ddc->listeners, g_hash_table_unref);
  135. g_clear_pointer(&ddc->kbd, qkbd_state_free);
  136. G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object);
  137. }
  138. static void
  139. dbus_display_console_class_init(DBusDisplayConsoleClass *klass)
  140. {
  141. GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
  142. gobject_class->dispose = dbus_display_console_dispose;
  143. }
  144. static void
  145. listener_vanished_cb(DBusDisplayListener *listener)
  146. {
  147. DBusDisplayConsole *ddc = dbus_display_listener_get_console(listener);
  148. const char *name = dbus_display_listener_get_bus_name(listener);
  149. trace_dbus_listener_vanished(name);
  150. g_hash_table_remove(ddc->listeners, name);
  151. qkbd_state_lift_all_keys(ddc->kbd);
  152. }
  153. static gboolean
  154. dbus_console_set_ui_info(DBusDisplayConsole *ddc,
  155. GDBusMethodInvocation *invocation,
  156. guint16 arg_width_mm,
  157. guint16 arg_height_mm,
  158. gint arg_xoff,
  159. gint arg_yoff,
  160. guint arg_width,
  161. guint arg_height)
  162. {
  163. QemuUIInfo info = {
  164. .width_mm = arg_width_mm,
  165. .height_mm = arg_height_mm,
  166. .xoff = arg_xoff,
  167. .yoff = arg_yoff,
  168. .width = arg_width,
  169. .height = arg_height,
  170. };
  171. if (!dpy_ui_info_supported(ddc->dcl.con)) {
  172. g_dbus_method_invocation_return_error(invocation,
  173. DBUS_DISPLAY_ERROR,
  174. DBUS_DISPLAY_ERROR_UNSUPPORTED,
  175. "SetUIInfo is not supported");
  176. return DBUS_METHOD_INVOCATION_HANDLED;
  177. }
  178. dpy_set_ui_info(ddc->dcl.con, &info, false);
  179. qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation);
  180. return DBUS_METHOD_INVOCATION_HANDLED;
  181. }
  182. #ifdef G_OS_WIN32
  183. bool
  184. dbus_win32_import_socket(GDBusMethodInvocation *invocation,
  185. GVariant *arg_listener, int *socket)
  186. {
  187. gsize n;
  188. WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1);
  189. if (!info || n != sizeof(*info)) {
  190. g_dbus_method_invocation_return_error(
  191. invocation,
  192. DBUS_DISPLAY_ERROR,
  193. DBUS_DISPLAY_ERROR_FAILED,
  194. "Failed to get socket infos");
  195. return false;
  196. }
  197. *socket = WSASocketW(FROM_PROTOCOL_INFO,
  198. FROM_PROTOCOL_INFO,
  199. FROM_PROTOCOL_INFO,
  200. info, 0, 0);
  201. if (*socket == INVALID_SOCKET) {
  202. g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
  203. g_dbus_method_invocation_return_error(
  204. invocation,
  205. DBUS_DISPLAY_ERROR,
  206. DBUS_DISPLAY_ERROR_FAILED,
  207. "Couldn't create socket: %s", emsg);
  208. return false;
  209. }
  210. return true;
  211. }
  212. #endif
  213. static gboolean
  214. dbus_console_register_listener(DBusDisplayConsole *ddc,
  215. GDBusMethodInvocation *invocation,
  216. #ifdef G_OS_UNIX
  217. GUnixFDList *fd_list,
  218. #endif
  219. GVariant *arg_listener)
  220. {
  221. const char *sender = g_dbus_method_invocation_get_sender(invocation);
  222. GDBusConnection *listener_conn;
  223. g_autoptr(GError) err = NULL;
  224. g_autoptr(GSocket) socket = NULL;
  225. g_autoptr(GSocketConnection) socket_conn = NULL;
  226. g_autofree char *guid = g_dbus_generate_guid();
  227. DBusDisplayListener *listener;
  228. int fd;
  229. if (sender && g_hash_table_contains(ddc->listeners, sender)) {
  230. g_dbus_method_invocation_return_error(
  231. invocation,
  232. DBUS_DISPLAY_ERROR,
  233. DBUS_DISPLAY_ERROR_INVALID,
  234. "`%s` is already registered!",
  235. sender);
  236. return DBUS_METHOD_INVOCATION_HANDLED;
  237. }
  238. #ifdef G_OS_WIN32
  239. if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
  240. return DBUS_METHOD_INVOCATION_HANDLED;
  241. }
  242. #else
  243. fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
  244. if (err) {
  245. g_dbus_method_invocation_return_error(
  246. invocation,
  247. DBUS_DISPLAY_ERROR,
  248. DBUS_DISPLAY_ERROR_FAILED,
  249. "Couldn't get peer fd: %s", err->message);
  250. return DBUS_METHOD_INVOCATION_HANDLED;
  251. }
  252. #endif
  253. socket = g_socket_new_from_fd(fd, &err);
  254. if (err) {
  255. g_dbus_method_invocation_return_error(
  256. invocation,
  257. DBUS_DISPLAY_ERROR,
  258. DBUS_DISPLAY_ERROR_FAILED,
  259. "Couldn't make a socket: %s", err->message);
  260. #ifdef G_OS_WIN32
  261. closesocket(fd);
  262. #else
  263. close(fd);
  264. #endif
  265. return DBUS_METHOD_INVOCATION_HANDLED;
  266. }
  267. socket_conn = g_socket_connection_factory_create_connection(socket);
  268. qemu_dbus_display1_console_complete_register_listener(
  269. ddc->iface, invocation
  270. #ifdef G_OS_UNIX
  271. , NULL
  272. #endif
  273. );
  274. listener_conn = g_dbus_connection_new_sync(
  275. G_IO_STREAM(socket_conn),
  276. guid,
  277. G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
  278. NULL, NULL, &err);
  279. if (err) {
  280. error_report("Failed to setup peer connection: %s", err->message);
  281. return DBUS_METHOD_INVOCATION_HANDLED;
  282. }
  283. listener = dbus_display_listener_new(sender, listener_conn, ddc);
  284. if (!listener) {
  285. return DBUS_METHOD_INVOCATION_HANDLED;
  286. }
  287. g_hash_table_insert(ddc->listeners,
  288. (gpointer)dbus_display_listener_get_bus_name(listener),
  289. listener);
  290. g_object_connect(listener_conn,
  291. "swapped-signal::closed", listener_vanished_cb, listener,
  292. NULL);
  293. trace_dbus_registered_listener(sender);
  294. return DBUS_METHOD_INVOCATION_HANDLED;
  295. }
  296. static gboolean
  297. dbus_kbd_press(DBusDisplayConsole *ddc,
  298. GDBusMethodInvocation *invocation,
  299. guint arg_keycode)
  300. {
  301. QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
  302. trace_dbus_kbd_press(arg_keycode);
  303. qkbd_state_key_event(ddc->kbd, qcode, true);
  304. qemu_dbus_display1_keyboard_complete_press(ddc->iface_kbd, invocation);
  305. return DBUS_METHOD_INVOCATION_HANDLED;
  306. }
  307. static gboolean
  308. dbus_kbd_release(DBusDisplayConsole *ddc,
  309. GDBusMethodInvocation *invocation,
  310. guint arg_keycode)
  311. {
  312. QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
  313. trace_dbus_kbd_release(arg_keycode);
  314. qkbd_state_key_event(ddc->kbd, qcode, false);
  315. qemu_dbus_display1_keyboard_complete_release(ddc->iface_kbd, invocation);
  316. return DBUS_METHOD_INVOCATION_HANDLED;
  317. }
  318. static void
  319. dbus_kbd_qemu_leds_updated(void *data, int ledstate)
  320. {
  321. DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(data);
  322. qemu_dbus_display1_keyboard_set_modifiers(ddc->iface_kbd, ledstate);
  323. }
  324. static gboolean
  325. dbus_mouse_rel_motion(DBusDisplayConsole *ddc,
  326. GDBusMethodInvocation *invocation,
  327. int dx, int dy)
  328. {
  329. trace_dbus_mouse_rel_motion(dx, dy);
  330. if (qemu_input_is_absolute(ddc->dcl.con)) {
  331. g_dbus_method_invocation_return_error(
  332. invocation, DBUS_DISPLAY_ERROR,
  333. DBUS_DISPLAY_ERROR_INVALID,
  334. "Mouse is not relative");
  335. return DBUS_METHOD_INVOCATION_HANDLED;
  336. }
  337. qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_X, dx);
  338. qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_Y, dy);
  339. qemu_input_event_sync();
  340. qemu_dbus_display1_mouse_complete_rel_motion(ddc->iface_mouse,
  341. invocation);
  342. return DBUS_METHOD_INVOCATION_HANDLED;
  343. }
  344. static gboolean
  345. dbus_touch_send_event(DBusDisplayConsole *ddc,
  346. GDBusMethodInvocation *invocation,
  347. guint kind, uint64_t num_slot,
  348. double x, double y)
  349. {
  350. Error *error = NULL;
  351. int width, height;
  352. trace_dbus_touch_send_event(kind, num_slot, x, y);
  353. if (kind != INPUT_MULTI_TOUCH_TYPE_BEGIN &&
  354. kind != INPUT_MULTI_TOUCH_TYPE_UPDATE &&
  355. kind != INPUT_MULTI_TOUCH_TYPE_CANCEL &&
  356. kind != INPUT_MULTI_TOUCH_TYPE_END)
  357. {
  358. g_dbus_method_invocation_return_error(
  359. invocation, DBUS_DISPLAY_ERROR,
  360. DBUS_DISPLAY_ERROR_INVALID,
  361. "Invalid touch event kind");
  362. return DBUS_METHOD_INVOCATION_HANDLED;
  363. }
  364. width = qemu_console_get_width(ddc->dcl.con, 0);
  365. height = qemu_console_get_height(ddc->dcl.con, 0);
  366. console_handle_touch_event(ddc->dcl.con, touch_slots,
  367. num_slot, width, height,
  368. x, y, kind, &error);
  369. if (error != NULL) {
  370. g_dbus_method_invocation_return_error(
  371. invocation, DBUS_DISPLAY_ERROR,
  372. DBUS_DISPLAY_ERROR_INVALID,
  373. error_get_pretty(error), NULL);
  374. error_free(error);
  375. } else {
  376. qemu_dbus_display1_multi_touch_complete_send_event(ddc->iface_touch,
  377. invocation);
  378. }
  379. return DBUS_METHOD_INVOCATION_HANDLED;
  380. }
  381. static gboolean
  382. dbus_mouse_set_pos(DBusDisplayConsole *ddc,
  383. GDBusMethodInvocation *invocation,
  384. guint x, guint y)
  385. {
  386. int width, height;
  387. trace_dbus_mouse_set_pos(x, y);
  388. if (!qemu_input_is_absolute(ddc->dcl.con)) {
  389. g_dbus_method_invocation_return_error(
  390. invocation, DBUS_DISPLAY_ERROR,
  391. DBUS_DISPLAY_ERROR_INVALID,
  392. "Mouse is not absolute");
  393. return DBUS_METHOD_INVOCATION_HANDLED;
  394. }
  395. width = qemu_console_get_width(ddc->dcl.con, 0);
  396. height = qemu_console_get_height(ddc->dcl.con, 0);
  397. if (x >= width || y >= height) {
  398. g_dbus_method_invocation_return_error(
  399. invocation, DBUS_DISPLAY_ERROR,
  400. DBUS_DISPLAY_ERROR_INVALID,
  401. "Invalid mouse position");
  402. return DBUS_METHOD_INVOCATION_HANDLED;
  403. }
  404. qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_X, x, 0, width);
  405. qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_Y, y, 0, height);
  406. qemu_input_event_sync();
  407. qemu_dbus_display1_mouse_complete_set_abs_position(ddc->iface_mouse,
  408. invocation);
  409. return DBUS_METHOD_INVOCATION_HANDLED;
  410. }
  411. static gboolean
  412. dbus_mouse_press(DBusDisplayConsole *ddc,
  413. GDBusMethodInvocation *invocation,
  414. guint button)
  415. {
  416. trace_dbus_mouse_press(button);
  417. qemu_input_queue_btn(ddc->dcl.con, button, true);
  418. qemu_input_event_sync();
  419. qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation);
  420. return DBUS_METHOD_INVOCATION_HANDLED;
  421. }
  422. static gboolean
  423. dbus_mouse_release(DBusDisplayConsole *ddc,
  424. GDBusMethodInvocation *invocation,
  425. guint button)
  426. {
  427. trace_dbus_mouse_release(button);
  428. qemu_input_queue_btn(ddc->dcl.con, button, false);
  429. qemu_input_event_sync();
  430. qemu_dbus_display1_mouse_complete_release(ddc->iface_mouse, invocation);
  431. return DBUS_METHOD_INVOCATION_HANDLED;
  432. }
  433. static void
  434. dbus_mouse_update_is_absolute(DBusDisplayConsole *ddc)
  435. {
  436. g_object_set(ddc->iface_mouse,
  437. "is-absolute", qemu_input_is_absolute(ddc->dcl.con),
  438. NULL);
  439. }
  440. static void
  441. dbus_mouse_mode_change(Notifier *notify, void *data)
  442. {
  443. DBusDisplayConsole *ddc =
  444. container_of(notify, DBusDisplayConsole, mouse_mode_notifier);
  445. dbus_mouse_update_is_absolute(ddc);
  446. }
  447. int dbus_display_console_get_index(DBusDisplayConsole *ddc)
  448. {
  449. return qemu_console_get_index(ddc->dcl.con);
  450. }
  451. DBusDisplayConsole *
  452. dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
  453. {
  454. g_autofree char *path = NULL;
  455. g_autofree char *label = NULL;
  456. char device_addr[256] = "";
  457. DBusDisplayConsole *ddc;
  458. int idx, i;
  459. const char *interfaces[] = {
  460. "org.qemu.Display1.Keyboard",
  461. "org.qemu.Display1.Mouse",
  462. "org.qemu.Display1.MultiTouch",
  463. NULL
  464. };
  465. assert(display);
  466. assert(con);
  467. label = qemu_console_get_label(con);
  468. idx = qemu_console_get_index(con);
  469. path = g_strdup_printf(DBUS_DISPLAY1_ROOT "/Console_%d", idx);
  470. ddc = g_object_new(DBUS_DISPLAY_TYPE_CONSOLE,
  471. "g-object-path", path,
  472. NULL);
  473. ddc->display = display;
  474. ddc->dcl.con = con;
  475. /* handle errors, and skip non graphics? */
  476. qemu_console_fill_device_address(
  477. con, device_addr, sizeof(device_addr), NULL);
  478. ddc->iface = qemu_dbus_display1_console_skeleton_new();
  479. g_object_set(ddc->iface,
  480. "label", label,
  481. "type", qemu_console_is_graphic(con) ? "Graphic" : "Text",
  482. "head", qemu_console_get_head(con),
  483. "width", qemu_console_get_width(con, 0),
  484. "height", qemu_console_get_height(con, 0),
  485. "device-address", device_addr,
  486. "interfaces", interfaces,
  487. NULL);
  488. g_object_connect(ddc->iface,
  489. "swapped-signal::handle-register-listener",
  490. dbus_console_register_listener, ddc,
  491. "swapped-signal::handle-set-uiinfo",
  492. dbus_console_set_ui_info, ddc,
  493. NULL);
  494. g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
  495. G_DBUS_INTERFACE_SKELETON(ddc->iface));
  496. ddc->kbd = qkbd_state_init(con);
  497. ddc->iface_kbd = qemu_dbus_display1_keyboard_skeleton_new();
  498. qemu_add_led_event_handler(dbus_kbd_qemu_leds_updated, ddc);
  499. g_object_connect(ddc->iface_kbd,
  500. "swapped-signal::handle-press", dbus_kbd_press, ddc,
  501. "swapped-signal::handle-release", dbus_kbd_release, ddc,
  502. NULL);
  503. g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
  504. G_DBUS_INTERFACE_SKELETON(ddc->iface_kbd));
  505. ddc->iface_mouse = qemu_dbus_display1_mouse_skeleton_new();
  506. g_object_connect(ddc->iface_mouse,
  507. "swapped-signal::handle-set-abs-position", dbus_mouse_set_pos, ddc,
  508. "swapped-signal::handle-rel-motion", dbus_mouse_rel_motion, ddc,
  509. "swapped-signal::handle-press", dbus_mouse_press, ddc,
  510. "swapped-signal::handle-release", dbus_mouse_release, ddc,
  511. NULL);
  512. g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
  513. G_DBUS_INTERFACE_SKELETON(ddc->iface_mouse));
  514. ddc->iface_touch = qemu_dbus_display1_multi_touch_skeleton_new();
  515. g_object_connect(ddc->iface_touch,
  516. "swapped-signal::handle-send-event", dbus_touch_send_event, ddc,
  517. NULL);
  518. qemu_dbus_display1_multi_touch_set_max_slots(ddc->iface_touch,
  519. INPUT_EVENT_SLOTS_MAX);
  520. g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
  521. G_DBUS_INTERFACE_SKELETON(ddc->iface_touch));
  522. for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) {
  523. struct touch_slot *slot = &touch_slots[i];
  524. slot->tracking_id = -1;
  525. }
  526. register_displaychangelistener(&ddc->dcl);
  527. ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change;
  528. qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
  529. dbus_mouse_update_is_absolute(ddc);
  530. return ddc;
  531. }