blob: 5eb1d40d1636593c40b4012e7ff985233b937b94 [file] [log] [blame]
Marc-André Lureau142ca622021-07-15 11:53:53 +04001/*
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"
Thomas Huth5feed382023-02-10 12:19:31 +010025#include "qemu/error-report.h"
Marc-André Lureau142ca622021-07-15 11:53:53 +040026#include "qapi/error.h"
27#include "ui/input.h"
28#include "ui/kbd-state.h"
29#include "trace.h"
30
Marc-André Lureau29c5c7e2023-06-06 15:56:40 +040031#ifdef G_OS_UNIX
Marc-André Lureau142ca622021-07-15 11:53:53 +040032#include <gio/gunixfdlist.h>
Marc-André Lureau29c5c7e2023-06-06 15:56:40 +040033#endif
Marc-André Lureau142ca622021-07-15 11:53:53 +040034
35#include "dbus.h"
36
Bilal Elmoussaouide9f8442023-06-19 11:53:37 +020037static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX];
38
Marc-André Lureau142ca622021-07-15 11:53:53 +040039struct _DBusDisplayConsole {
40 GDBusObjectSkeleton parent_instance;
41 DisplayChangeListener dcl;
42
43 DBusDisplay *display;
Marc-André Lureau2448ff32024-10-08 16:50:19 +040044 GPtrArray *listeners;
Marc-André Lureau142ca622021-07-15 11:53:53 +040045 QemuDBusDisplay1Console *iface;
46
47 QemuDBusDisplay1Keyboard *iface_kbd;
48 QKbdState *kbd;
49
50 QemuDBusDisplay1Mouse *iface_mouse;
Bilal Elmoussaouide9f8442023-06-19 11:53:37 +020051 QemuDBusDisplay1MultiTouch *iface_touch;
Marc-André Lureau142ca622021-07-15 11:53:53 +040052 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,
Marc-André Lureaubf41ab62023-06-06 15:56:56 +0400101 uint32_t w, uint32_t h,
102 void *d3d_tex2d)
Marc-André Lureau142ca622021-07-15 11:53:53 +0400103{
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{
Dongwon Kim6779a302024-05-08 10:54:00 -0700113 uint32_t width, height;
114
Marc-André Lureau142ca622021-07-15 11:53:53 +0400115 DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl);
116
Dongwon Kim6779a302024-05-08 10:54:00 -0700117 width = qemu_dmabuf_get_width(dmabuf);
118 height = qemu_dmabuf_get_height(dmabuf);
119
120 dbus_display_console_set_size(ddc, width, height);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400121}
122
123static void
124dbus_gl_scanout_update(DisplayChangeListener *dcl,
125 uint32_t x, uint32_t y,
126 uint32_t w, uint32_t h)
127{
128}
129
Marc-André Lureau417a2312022-02-16 22:52:14 +0400130const DisplayChangeListenerOps dbus_console_dcl_ops = {
Marc-André Lureau142ca622021-07-15 11:53:53 +0400131 .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
140static void
141dbus_display_console_init(DBusDisplayConsole *object)
142{
143 DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
144
Marc-André Lureau2448ff32024-10-08 16:50:19 +0400145 ddc->listeners = g_ptr_array_new_with_free_func(g_object_unref);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400146 ddc->dcl.ops = &dbus_console_dcl_ops;
147}
148
149static void
150dbus_display_console_dispose(GObject *object)
151{
152 DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
153
154 unregister_displaychangelistener(&ddc->dcl);
Bilal Elmoussaouicb6ccdc2023-09-01 14:45:07 +0200155 g_clear_object(&ddc->iface_touch);
156 g_clear_object(&ddc->iface_mouse);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400157 g_clear_object(&ddc->iface_kbd);
158 g_clear_object(&ddc->iface);
Marc-André Lureau2448ff32024-10-08 16:50:19 +0400159 g_clear_pointer(&ddc->listeners, g_ptr_array_unref);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400160 g_clear_pointer(&ddc->kbd, qkbd_state_free);
161
162 G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object);
163}
164
165static void
166dbus_display_console_class_init(DBusDisplayConsoleClass *klass)
167{
168 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
169
170 gobject_class->dispose = dbus_display_console_dispose;
171}
172
173static void
174listener_vanished_cb(DBusDisplayListener *listener)
175{
176 DBusDisplayConsole *ddc = dbus_display_listener_get_console(listener);
177 const char *name = dbus_display_listener_get_bus_name(listener);
178
179 trace_dbus_listener_vanished(name);
180
Marc-André Lureau2448ff32024-10-08 16:50:19 +0400181 g_ptr_array_remove_fast(ddc->listeners, listener);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400182 qkbd_state_lift_all_keys(ddc->kbd);
183}
184
185static gboolean
186dbus_console_set_ui_info(DBusDisplayConsole *ddc,
187 GDBusMethodInvocation *invocation,
188 guint16 arg_width_mm,
189 guint16 arg_height_mm,
190 gint arg_xoff,
191 gint arg_yoff,
192 guint arg_width,
193 guint arg_height)
194{
195 QemuUIInfo info = {
196 .width_mm = arg_width_mm,
197 .height_mm = arg_height_mm,
198 .xoff = arg_xoff,
199 .yoff = arg_yoff,
200 .width = arg_width,
201 .height = arg_height,
202 };
203
Marc-André Lureau417a2312022-02-16 22:52:14 +0400204 if (!dpy_ui_info_supported(ddc->dcl.con)) {
Marc-André Lureau142ca622021-07-15 11:53:53 +0400205 g_dbus_method_invocation_return_error(invocation,
206 DBUS_DISPLAY_ERROR,
207 DBUS_DISPLAY_ERROR_UNSUPPORTED,
208 "SetUIInfo is not supported");
209 return DBUS_METHOD_INVOCATION_HANDLED;
210 }
211
Marc-André Lureau417a2312022-02-16 22:52:14 +0400212 dpy_set_ui_info(ddc->dcl.con, &info, false);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400213 qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation);
214 return DBUS_METHOD_INVOCATION_HANDLED;
215}
216
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400217#ifdef G_OS_WIN32
218bool
219dbus_win32_import_socket(GDBusMethodInvocation *invocation,
220 GVariant *arg_listener, int *socket)
221{
222 gsize n;
223 WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1);
224
225 if (!info || n != sizeof(*info)) {
226 g_dbus_method_invocation_return_error(
227 invocation,
228 DBUS_DISPLAY_ERROR,
229 DBUS_DISPLAY_ERROR_FAILED,
230 "Failed to get socket infos");
231 return false;
232 }
233
234 *socket = WSASocketW(FROM_PROTOCOL_INFO,
235 FROM_PROTOCOL_INFO,
236 FROM_PROTOCOL_INFO,
237 info, 0, 0);
238 if (*socket == INVALID_SOCKET) {
239 g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
240 g_dbus_method_invocation_return_error(
241 invocation,
242 DBUS_DISPLAY_ERROR,
243 DBUS_DISPLAY_ERROR_FAILED,
244 "Couldn't create socket: %s", emsg);
245 return false;
246 }
247
248 return true;
249}
250#endif
251
Marc-André Lureau142ca622021-07-15 11:53:53 +0400252static gboolean
253dbus_console_register_listener(DBusDisplayConsole *ddc,
254 GDBusMethodInvocation *invocation,
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400255#ifdef G_OS_UNIX
Marc-André Lureau142ca622021-07-15 11:53:53 +0400256 GUnixFDList *fd_list,
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400257#endif
Marc-André Lureau142ca622021-07-15 11:53:53 +0400258 GVariant *arg_listener)
259{
260 const char *sender = g_dbus_method_invocation_get_sender(invocation);
261 GDBusConnection *listener_conn;
262 g_autoptr(GError) err = NULL;
263 g_autoptr(GSocket) socket = NULL;
264 g_autoptr(GSocketConnection) socket_conn = NULL;
265 g_autofree char *guid = g_dbus_generate_guid();
266 DBusDisplayListener *listener;
267 int fd;
268
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400269#ifdef G_OS_WIN32
270 if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
271 return DBUS_METHOD_INVOCATION_HANDLED;
272 }
273#else
Marc-André Lureau142ca622021-07-15 11:53:53 +0400274 fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
275 if (err) {
276 g_dbus_method_invocation_return_error(
277 invocation,
278 DBUS_DISPLAY_ERROR,
279 DBUS_DISPLAY_ERROR_FAILED,
280 "Couldn't get peer fd: %s", err->message);
281 return DBUS_METHOD_INVOCATION_HANDLED;
282 }
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400283#endif
Marc-André Lureau142ca622021-07-15 11:53:53 +0400284
285 socket = g_socket_new_from_fd(fd, &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 make a socket: %s", err->message);
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400292#ifdef G_OS_WIN32
293 closesocket(fd);
294#else
Marc-André Lureau142ca622021-07-15 11:53:53 +0400295 close(fd);
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400296#endif
Marc-André Lureau142ca622021-07-15 11:53:53 +0400297 return DBUS_METHOD_INVOCATION_HANDLED;
298 }
299 socket_conn = g_socket_connection_factory_create_connection(socket);
300
301 qemu_dbus_display1_console_complete_register_listener(
Marc-André Lureau6cc5a612023-06-06 15:56:42 +0400302 ddc->iface, invocation
303#ifdef G_OS_UNIX
304 , NULL
305#endif
306 );
Marc-André Lureau142ca622021-07-15 11:53:53 +0400307
308 listener_conn = g_dbus_connection_new_sync(
309 G_IO_STREAM(socket_conn),
310 guid,
311 G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
312 NULL, NULL, &err);
313 if (err) {
314 error_report("Failed to setup peer connection: %s", err->message);
315 return DBUS_METHOD_INVOCATION_HANDLED;
316 }
317
318 listener = dbus_display_listener_new(sender, listener_conn, ddc);
319 if (!listener) {
320 return DBUS_METHOD_INVOCATION_HANDLED;
321 }
322
Marc-André Lureau2448ff32024-10-08 16:50:19 +0400323 g_ptr_array_add(ddc->listeners, listener);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400324 g_object_connect(listener_conn,
325 "swapped-signal::closed", listener_vanished_cb, listener,
326 NULL);
327
328 trace_dbus_registered_listener(sender);
329 return DBUS_METHOD_INVOCATION_HANDLED;
330}
331
332static gboolean
333dbus_kbd_press(DBusDisplayConsole *ddc,
334 GDBusMethodInvocation *invocation,
335 guint arg_keycode)
336{
337 QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
338
339 trace_dbus_kbd_press(arg_keycode);
340
341 qkbd_state_key_event(ddc->kbd, qcode, true);
342
343 qemu_dbus_display1_keyboard_complete_press(ddc->iface_kbd, invocation);
344
345 return DBUS_METHOD_INVOCATION_HANDLED;
346}
347
348static gboolean
349dbus_kbd_release(DBusDisplayConsole *ddc,
350 GDBusMethodInvocation *invocation,
351 guint arg_keycode)
352{
353 QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
354
355 trace_dbus_kbd_release(arg_keycode);
356
357 qkbd_state_key_event(ddc->kbd, qcode, false);
358
359 qemu_dbus_display1_keyboard_complete_release(ddc->iface_kbd, invocation);
360
361 return DBUS_METHOD_INVOCATION_HANDLED;
362}
363
364static void
365dbus_kbd_qemu_leds_updated(void *data, int ledstate)
366{
367 DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(data);
368
369 qemu_dbus_display1_keyboard_set_modifiers(ddc->iface_kbd, ledstate);
370}
371
372static gboolean
373dbus_mouse_rel_motion(DBusDisplayConsole *ddc,
374 GDBusMethodInvocation *invocation,
375 int dx, int dy)
376{
377 trace_dbus_mouse_rel_motion(dx, dy);
378
Akihiko Odaki0337e412023-09-21 17:29:34 +0900379 if (qemu_input_is_absolute(ddc->dcl.con)) {
Marc-André Lureau142ca622021-07-15 11:53:53 +0400380 g_dbus_method_invocation_return_error(
381 invocation, DBUS_DISPLAY_ERROR,
382 DBUS_DISPLAY_ERROR_INVALID,
383 "Mouse is not relative");
384 return DBUS_METHOD_INVOCATION_HANDLED;
385 }
386
Marc-André Lureau417a2312022-02-16 22:52:14 +0400387 qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_X, dx);
388 qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_Y, dy);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400389 qemu_input_event_sync();
390
391 qemu_dbus_display1_mouse_complete_rel_motion(ddc->iface_mouse,
392 invocation);
393
394 return DBUS_METHOD_INVOCATION_HANDLED;
395}
396
397static gboolean
Bilal Elmoussaouide9f8442023-06-19 11:53:37 +0200398dbus_touch_send_event(DBusDisplayConsole *ddc,
399 GDBusMethodInvocation *invocation,
400 guint kind, uint64_t num_slot,
401 double x, double y)
402{
403 Error *error = NULL;
404 int width, height;
405 trace_dbus_touch_send_event(kind, num_slot, x, y);
406
407 if (kind != INPUT_MULTI_TOUCH_TYPE_BEGIN &&
408 kind != INPUT_MULTI_TOUCH_TYPE_UPDATE &&
409 kind != INPUT_MULTI_TOUCH_TYPE_CANCEL &&
410 kind != INPUT_MULTI_TOUCH_TYPE_END)
411 {
412 g_dbus_method_invocation_return_error(
413 invocation, DBUS_DISPLAY_ERROR,
414 DBUS_DISPLAY_ERROR_INVALID,
415 "Invalid touch event kind");
416 return DBUS_METHOD_INVOCATION_HANDLED;
417 }
418 width = qemu_console_get_width(ddc->dcl.con, 0);
419 height = qemu_console_get_height(ddc->dcl.con, 0);
420
421 console_handle_touch_event(ddc->dcl.con, touch_slots,
422 num_slot, width, height,
423 x, y, kind, &error);
424 if (error != NULL) {
425 g_dbus_method_invocation_return_error(
426 invocation, DBUS_DISPLAY_ERROR,
427 DBUS_DISPLAY_ERROR_INVALID,
428 error_get_pretty(error), NULL);
429 error_free(error);
430 } else {
431 qemu_dbus_display1_multi_touch_complete_send_event(ddc->iface_touch,
432 invocation);
433 }
434 return DBUS_METHOD_INVOCATION_HANDLED;
435}
436
437static gboolean
Marc-André Lureau142ca622021-07-15 11:53:53 +0400438dbus_mouse_set_pos(DBusDisplayConsole *ddc,
439 GDBusMethodInvocation *invocation,
440 guint x, guint y)
441{
442 int width, height;
443
444 trace_dbus_mouse_set_pos(x, y);
445
Akihiko Odaki0337e412023-09-21 17:29:34 +0900446 if (!qemu_input_is_absolute(ddc->dcl.con)) {
Marc-André Lureau142ca622021-07-15 11:53:53 +0400447 g_dbus_method_invocation_return_error(
448 invocation, DBUS_DISPLAY_ERROR,
449 DBUS_DISPLAY_ERROR_INVALID,
450 "Mouse is not absolute");
451 return DBUS_METHOD_INVOCATION_HANDLED;
452 }
453
Marc-André Lureau417a2312022-02-16 22:52:14 +0400454 width = qemu_console_get_width(ddc->dcl.con, 0);
455 height = qemu_console_get_height(ddc->dcl.con, 0);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400456 if (x >= width || y >= height) {
457 g_dbus_method_invocation_return_error(
458 invocation, DBUS_DISPLAY_ERROR,
459 DBUS_DISPLAY_ERROR_INVALID,
460 "Invalid mouse position");
461 return DBUS_METHOD_INVOCATION_HANDLED;
462 }
Marc-André Lureau417a2312022-02-16 22:52:14 +0400463 qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_X, x, 0, width);
464 qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_Y, y, 0, height);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400465 qemu_input_event_sync();
466
467 qemu_dbus_display1_mouse_complete_set_abs_position(ddc->iface_mouse,
468 invocation);
469
470 return DBUS_METHOD_INVOCATION_HANDLED;
471}
472
473static gboolean
474dbus_mouse_press(DBusDisplayConsole *ddc,
475 GDBusMethodInvocation *invocation,
476 guint button)
477{
478 trace_dbus_mouse_press(button);
479
Marc-André Lureau417a2312022-02-16 22:52:14 +0400480 qemu_input_queue_btn(ddc->dcl.con, button, true);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400481 qemu_input_event_sync();
482
483 qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation);
484
485 return DBUS_METHOD_INVOCATION_HANDLED;
486}
487
488static gboolean
489dbus_mouse_release(DBusDisplayConsole *ddc,
490 GDBusMethodInvocation *invocation,
491 guint button)
492{
493 trace_dbus_mouse_release(button);
494
Marc-André Lureau417a2312022-02-16 22:52:14 +0400495 qemu_input_queue_btn(ddc->dcl.con, button, false);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400496 qemu_input_event_sync();
497
498 qemu_dbus_display1_mouse_complete_release(ddc->iface_mouse, invocation);
499
500 return DBUS_METHOD_INVOCATION_HANDLED;
501}
502
503static void
Marc-André Lureaueb9062d2022-11-15 17:47:40 +0400504dbus_mouse_update_is_absolute(DBusDisplayConsole *ddc)
505{
506 g_object_set(ddc->iface_mouse,
Akihiko Odaki0337e412023-09-21 17:29:34 +0900507 "is-absolute", qemu_input_is_absolute(ddc->dcl.con),
Marc-André Lureaueb9062d2022-11-15 17:47:40 +0400508 NULL);
509}
510
511static void
Marc-André Lureau142ca622021-07-15 11:53:53 +0400512dbus_mouse_mode_change(Notifier *notify, void *data)
513{
514 DBusDisplayConsole *ddc =
515 container_of(notify, DBusDisplayConsole, mouse_mode_notifier);
516
Marc-André Lureaueb9062d2022-11-15 17:47:40 +0400517 dbus_mouse_update_is_absolute(ddc);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400518}
519
520int dbus_display_console_get_index(DBusDisplayConsole *ddc)
521{
Marc-André Lureau417a2312022-02-16 22:52:14 +0400522 return qemu_console_get_index(ddc->dcl.con);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400523}
524
525DBusDisplayConsole *
526dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
527{
528 g_autofree char *path = NULL;
529 g_autofree char *label = NULL;
530 char device_addr[256] = "";
531 DBusDisplayConsole *ddc;
Bilal Elmoussaouide9f8442023-06-19 11:53:37 +0200532 int idx, i;
Marc-André Lureau439e0162023-06-06 15:56:45 +0400533 const char *interfaces[] = {
534 "org.qemu.Display1.Keyboard",
535 "org.qemu.Display1.Mouse",
536 "org.qemu.Display1.MultiTouch",
537 NULL
538 };
Marc-André Lureau142ca622021-07-15 11:53:53 +0400539
540 assert(display);
541 assert(con);
542
543 label = qemu_console_get_label(con);
544 idx = qemu_console_get_index(con);
545 path = g_strdup_printf(DBUS_DISPLAY1_ROOT "/Console_%d", idx);
546 ddc = g_object_new(DBUS_DISPLAY_TYPE_CONSOLE,
547 "g-object-path", path,
548 NULL);
549 ddc->display = display;
Marc-André Lureau417a2312022-02-16 22:52:14 +0400550 ddc->dcl.con = con;
Marc-André Lureau142ca622021-07-15 11:53:53 +0400551 /* handle errors, and skip non graphics? */
552 qemu_console_fill_device_address(
553 con, device_addr, sizeof(device_addr), NULL);
554
555 ddc->iface = qemu_dbus_display1_console_skeleton_new();
556 g_object_set(ddc->iface,
557 "label", label,
558 "type", qemu_console_is_graphic(con) ? "Graphic" : "Text",
559 "head", qemu_console_get_head(con),
560 "width", qemu_console_get_width(con, 0),
561 "height", qemu_console_get_height(con, 0),
562 "device-address", device_addr,
Marc-André Lureau439e0162023-06-06 15:56:45 +0400563 "interfaces", interfaces,
Marc-André Lureau142ca622021-07-15 11:53:53 +0400564 NULL);
565 g_object_connect(ddc->iface,
566 "swapped-signal::handle-register-listener",
567 dbus_console_register_listener, ddc,
568 "swapped-signal::handle-set-uiinfo",
569 dbus_console_set_ui_info, ddc,
570 NULL);
571 g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
572 G_DBUS_INTERFACE_SKELETON(ddc->iface));
573
574 ddc->kbd = qkbd_state_init(con);
575 ddc->iface_kbd = qemu_dbus_display1_keyboard_skeleton_new();
576 qemu_add_led_event_handler(dbus_kbd_qemu_leds_updated, ddc);
577 g_object_connect(ddc->iface_kbd,
578 "swapped-signal::handle-press", dbus_kbd_press, ddc,
579 "swapped-signal::handle-release", dbus_kbd_release, ddc,
580 NULL);
581 g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
582 G_DBUS_INTERFACE_SKELETON(ddc->iface_kbd));
583
584 ddc->iface_mouse = qemu_dbus_display1_mouse_skeleton_new();
585 g_object_connect(ddc->iface_mouse,
586 "swapped-signal::handle-set-abs-position", dbus_mouse_set_pos, ddc,
587 "swapped-signal::handle-rel-motion", dbus_mouse_rel_motion, ddc,
588 "swapped-signal::handle-press", dbus_mouse_press, ddc,
589 "swapped-signal::handle-release", dbus_mouse_release, ddc,
590 NULL);
591 g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
592 G_DBUS_INTERFACE_SKELETON(ddc->iface_mouse));
593
Bilal Elmoussaouide9f8442023-06-19 11:53:37 +0200594 ddc->iface_touch = qemu_dbus_display1_multi_touch_skeleton_new();
595 g_object_connect(ddc->iface_touch,
596 "swapped-signal::handle-send-event", dbus_touch_send_event, ddc,
597 NULL);
598 qemu_dbus_display1_multi_touch_set_max_slots(ddc->iface_touch,
599 INPUT_EVENT_SLOTS_MAX);
600 g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
601 G_DBUS_INTERFACE_SKELETON(ddc->iface_touch));
602
603 for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) {
604 struct touch_slot *slot = &touch_slots[i];
605 slot->tracking_id = -1;
606 }
607
Marc-André Lureau142ca622021-07-15 11:53:53 +0400608 register_displaychangelistener(&ddc->dcl);
609 ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change;
610 qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
Marc-André Lureaueb9062d2022-11-15 17:47:40 +0400611 dbus_mouse_update_is_absolute(ddc);
Marc-André Lureau142ca622021-07-15 11:53:53 +0400612
613 return ddc;
614}