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