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