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