1142ca628SMarc-André Lureau /* 2142ca628SMarc-André Lureau * QEMU DBus display console 3142ca628SMarc-André Lureau * 4142ca628SMarc-André Lureau * Copyright (c) 2021 Marc-André Lureau <marcandre.lureau@redhat.com> 5142ca628SMarc-André Lureau * 6142ca628SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy 7142ca628SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal 8142ca628SMarc-André Lureau * in the Software without restriction, including without limitation the rights 9142ca628SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10142ca628SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is 11142ca628SMarc-André Lureau * furnished to do so, subject to the following conditions: 12142ca628SMarc-André Lureau * 13142ca628SMarc-André Lureau * The above copyright notice and this permission notice shall be included in 14142ca628SMarc-André Lureau * all copies or substantial portions of the Software. 15142ca628SMarc-André Lureau * 16142ca628SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17142ca628SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18142ca628SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19142ca628SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20142ca628SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21142ca628SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22142ca628SMarc-André Lureau * THE SOFTWARE. 23142ca628SMarc-André Lureau */ 24142ca628SMarc-André Lureau #include "qemu/osdep.h" 255feed38cSThomas Huth #include "qemu/error-report.h" 26142ca628SMarc-André Lureau #include "qapi/error.h" 27142ca628SMarc-André Lureau #include "ui/input.h" 28142ca628SMarc-André Lureau #include "ui/kbd-state.h" 29142ca628SMarc-André Lureau #include "trace.h" 30142ca628SMarc-André Lureau 3129c5c7e5SMarc-André Lureau #ifdef G_OS_UNIX 32142ca628SMarc-André Lureau #include <gio/gunixfdlist.h> 3329c5c7e5SMarc-André Lureau #endif 34142ca628SMarc-André Lureau 35142ca628SMarc-André Lureau #include "dbus.h" 36142ca628SMarc-André Lureau 37de9f844cSBilal Elmoussaoui static struct touch_slot touch_slots[INPUT_EVENT_SLOTS_MAX]; 38de9f844cSBilal Elmoussaoui 39142ca628SMarc-André Lureau struct _DBusDisplayConsole { 40142ca628SMarc-André Lureau GDBusObjectSkeleton parent_instance; 41142ca628SMarc-André Lureau DisplayChangeListener dcl; 42142ca628SMarc-André Lureau 43142ca628SMarc-André Lureau DBusDisplay *display; 44142ca628SMarc-André Lureau GHashTable *listeners; 45142ca628SMarc-André Lureau QemuDBusDisplay1Console *iface; 46142ca628SMarc-André Lureau 47142ca628SMarc-André Lureau QemuDBusDisplay1Keyboard *iface_kbd; 48142ca628SMarc-André Lureau QKbdState *kbd; 49142ca628SMarc-André Lureau 50142ca628SMarc-André Lureau QemuDBusDisplay1Mouse *iface_mouse; 51de9f844cSBilal Elmoussaoui QemuDBusDisplay1MultiTouch *iface_touch; 52142ca628SMarc-André Lureau gboolean last_set; 53142ca628SMarc-André Lureau guint last_x; 54142ca628SMarc-André Lureau guint last_y; 55142ca628SMarc-André Lureau Notifier mouse_mode_notifier; 56142ca628SMarc-André Lureau }; 57142ca628SMarc-André Lureau 58142ca628SMarc-André Lureau G_DEFINE_TYPE(DBusDisplayConsole, 59142ca628SMarc-André Lureau dbus_display_console, 60142ca628SMarc-André Lureau G_TYPE_DBUS_OBJECT_SKELETON) 61142ca628SMarc-André Lureau 62142ca628SMarc-André Lureau static void 63142ca628SMarc-André Lureau dbus_display_console_set_size(DBusDisplayConsole *ddc, 64142ca628SMarc-André Lureau uint32_t width, uint32_t height) 65142ca628SMarc-André Lureau { 66142ca628SMarc-André Lureau g_object_set(ddc->iface, 67142ca628SMarc-André Lureau "width", width, 68142ca628SMarc-André Lureau "height", height, 69142ca628SMarc-André Lureau NULL); 70142ca628SMarc-André Lureau } 71142ca628SMarc-André Lureau 72142ca628SMarc-André Lureau static void 73142ca628SMarc-André Lureau dbus_gfx_switch(DisplayChangeListener *dcl, 74142ca628SMarc-André Lureau struct DisplaySurface *new_surface) 75142ca628SMarc-André Lureau { 76142ca628SMarc-André Lureau DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl); 77142ca628SMarc-André Lureau 78142ca628SMarc-André Lureau dbus_display_console_set_size(ddc, 79142ca628SMarc-André Lureau surface_width(new_surface), 80142ca628SMarc-André Lureau surface_height(new_surface)); 81142ca628SMarc-André Lureau } 82142ca628SMarc-André Lureau 83142ca628SMarc-André Lureau static void 84142ca628SMarc-André Lureau dbus_gfx_update(DisplayChangeListener *dcl, 85142ca628SMarc-André Lureau int x, int y, int w, int h) 86142ca628SMarc-André Lureau { 87142ca628SMarc-André Lureau } 88142ca628SMarc-André Lureau 89142ca628SMarc-André Lureau static void 90142ca628SMarc-André Lureau dbus_gl_scanout_disable(DisplayChangeListener *dcl) 91142ca628SMarc-André Lureau { 92142ca628SMarc-André Lureau } 93142ca628SMarc-André Lureau 94142ca628SMarc-André Lureau static void 95142ca628SMarc-André Lureau dbus_gl_scanout_texture(DisplayChangeListener *dcl, 96142ca628SMarc-André Lureau uint32_t tex_id, 97142ca628SMarc-André Lureau bool backing_y_0_top, 98142ca628SMarc-André Lureau uint32_t backing_width, 99142ca628SMarc-André Lureau uint32_t backing_height, 100142ca628SMarc-André Lureau uint32_t x, uint32_t y, 101bf41ab61SMarc-André Lureau uint32_t w, uint32_t h, 102bf41ab61SMarc-André Lureau void *d3d_tex2d) 103142ca628SMarc-André Lureau { 104142ca628SMarc-André Lureau DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl); 105142ca628SMarc-André Lureau 106142ca628SMarc-André Lureau dbus_display_console_set_size(ddc, w, h); 107142ca628SMarc-André Lureau } 108142ca628SMarc-André Lureau 109142ca628SMarc-André Lureau static void 110142ca628SMarc-André Lureau dbus_gl_scanout_dmabuf(DisplayChangeListener *dcl, 111142ca628SMarc-André Lureau QemuDmaBuf *dmabuf) 112142ca628SMarc-André Lureau { 113142ca628SMarc-André Lureau DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl); 114142ca628SMarc-André Lureau 115142ca628SMarc-André Lureau dbus_display_console_set_size(ddc, 116142ca628SMarc-André Lureau dmabuf->width, 117142ca628SMarc-André Lureau dmabuf->height); 118142ca628SMarc-André Lureau } 119142ca628SMarc-André Lureau 120142ca628SMarc-André Lureau static void 121142ca628SMarc-André Lureau dbus_gl_scanout_update(DisplayChangeListener *dcl, 122142ca628SMarc-André Lureau uint32_t x, uint32_t y, 123142ca628SMarc-André Lureau uint32_t w, uint32_t h) 124142ca628SMarc-André Lureau { 125142ca628SMarc-André Lureau } 126142ca628SMarc-André Lureau 127417a2319SMarc-André Lureau const DisplayChangeListenerOps dbus_console_dcl_ops = { 128142ca628SMarc-André Lureau .dpy_name = "dbus-console", 129142ca628SMarc-André Lureau .dpy_gfx_switch = dbus_gfx_switch, 130142ca628SMarc-André Lureau .dpy_gfx_update = dbus_gfx_update, 131142ca628SMarc-André Lureau .dpy_gl_scanout_disable = dbus_gl_scanout_disable, 132142ca628SMarc-André Lureau .dpy_gl_scanout_texture = dbus_gl_scanout_texture, 133142ca628SMarc-André Lureau .dpy_gl_scanout_dmabuf = dbus_gl_scanout_dmabuf, 134142ca628SMarc-André Lureau .dpy_gl_update = dbus_gl_scanout_update, 135142ca628SMarc-André Lureau }; 136142ca628SMarc-André Lureau 137142ca628SMarc-André Lureau static void 138142ca628SMarc-André Lureau dbus_display_console_init(DBusDisplayConsole *object) 139142ca628SMarc-André Lureau { 140142ca628SMarc-André Lureau DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object); 141142ca628SMarc-André Lureau 142142ca628SMarc-André Lureau ddc->listeners = g_hash_table_new_full(g_str_hash, g_str_equal, 143142ca628SMarc-André Lureau NULL, g_object_unref); 144142ca628SMarc-André Lureau ddc->dcl.ops = &dbus_console_dcl_ops; 145142ca628SMarc-André Lureau } 146142ca628SMarc-André Lureau 147142ca628SMarc-André Lureau static void 148142ca628SMarc-André Lureau dbus_display_console_dispose(GObject *object) 149142ca628SMarc-André Lureau { 150142ca628SMarc-André Lureau DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object); 151142ca628SMarc-André Lureau 152142ca628SMarc-André Lureau unregister_displaychangelistener(&ddc->dcl); 153cb6ccdc9SBilal Elmoussaoui g_clear_object(&ddc->iface_touch); 154cb6ccdc9SBilal Elmoussaoui g_clear_object(&ddc->iface_mouse); 155142ca628SMarc-André Lureau g_clear_object(&ddc->iface_kbd); 156142ca628SMarc-André Lureau g_clear_object(&ddc->iface); 157142ca628SMarc-André Lureau g_clear_pointer(&ddc->listeners, g_hash_table_unref); 158142ca628SMarc-André Lureau g_clear_pointer(&ddc->kbd, qkbd_state_free); 159142ca628SMarc-André Lureau 160142ca628SMarc-André Lureau G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object); 161142ca628SMarc-André Lureau } 162142ca628SMarc-André Lureau 163142ca628SMarc-André Lureau static void 164142ca628SMarc-André Lureau dbus_display_console_class_init(DBusDisplayConsoleClass *klass) 165142ca628SMarc-André Lureau { 166142ca628SMarc-André Lureau GObjectClass *gobject_class = G_OBJECT_CLASS(klass); 167142ca628SMarc-André Lureau 168142ca628SMarc-André Lureau gobject_class->dispose = dbus_display_console_dispose; 169142ca628SMarc-André Lureau } 170142ca628SMarc-André Lureau 171142ca628SMarc-André Lureau static void 172142ca628SMarc-André Lureau listener_vanished_cb(DBusDisplayListener *listener) 173142ca628SMarc-André Lureau { 174142ca628SMarc-André Lureau DBusDisplayConsole *ddc = dbus_display_listener_get_console(listener); 175142ca628SMarc-André Lureau const char *name = dbus_display_listener_get_bus_name(listener); 176142ca628SMarc-André Lureau 177142ca628SMarc-André Lureau trace_dbus_listener_vanished(name); 178142ca628SMarc-André Lureau 179142ca628SMarc-André Lureau g_hash_table_remove(ddc->listeners, name); 180142ca628SMarc-André Lureau qkbd_state_lift_all_keys(ddc->kbd); 181142ca628SMarc-André Lureau } 182142ca628SMarc-André Lureau 183142ca628SMarc-André Lureau static gboolean 184142ca628SMarc-André Lureau dbus_console_set_ui_info(DBusDisplayConsole *ddc, 185142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 186142ca628SMarc-André Lureau guint16 arg_width_mm, 187142ca628SMarc-André Lureau guint16 arg_height_mm, 188142ca628SMarc-André Lureau gint arg_xoff, 189142ca628SMarc-André Lureau gint arg_yoff, 190142ca628SMarc-André Lureau guint arg_width, 191142ca628SMarc-André Lureau guint arg_height) 192142ca628SMarc-André Lureau { 193142ca628SMarc-André Lureau QemuUIInfo info = { 194142ca628SMarc-André Lureau .width_mm = arg_width_mm, 195142ca628SMarc-André Lureau .height_mm = arg_height_mm, 196142ca628SMarc-André Lureau .xoff = arg_xoff, 197142ca628SMarc-André Lureau .yoff = arg_yoff, 198142ca628SMarc-André Lureau .width = arg_width, 199142ca628SMarc-André Lureau .height = arg_height, 200142ca628SMarc-André Lureau }; 201142ca628SMarc-André Lureau 202417a2319SMarc-André Lureau if (!dpy_ui_info_supported(ddc->dcl.con)) { 203142ca628SMarc-André Lureau g_dbus_method_invocation_return_error(invocation, 204142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR, 205142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_UNSUPPORTED, 206142ca628SMarc-André Lureau "SetUIInfo is not supported"); 207142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 208142ca628SMarc-André Lureau } 209142ca628SMarc-André Lureau 210417a2319SMarc-André Lureau dpy_set_ui_info(ddc->dcl.con, &info, false); 211142ca628SMarc-André Lureau qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation); 212142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 213142ca628SMarc-André Lureau } 214142ca628SMarc-André Lureau 2156cc5a615SMarc-André Lureau #ifdef G_OS_WIN32 2166cc5a615SMarc-André Lureau bool 2176cc5a615SMarc-André Lureau dbus_win32_import_socket(GDBusMethodInvocation *invocation, 2186cc5a615SMarc-André Lureau GVariant *arg_listener, int *socket) 2196cc5a615SMarc-André Lureau { 2206cc5a615SMarc-André Lureau gsize n; 2216cc5a615SMarc-André Lureau WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1); 2226cc5a615SMarc-André Lureau 2236cc5a615SMarc-André Lureau if (!info || n != sizeof(*info)) { 2246cc5a615SMarc-André Lureau g_dbus_method_invocation_return_error( 2256cc5a615SMarc-André Lureau invocation, 2266cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR, 2276cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED, 2286cc5a615SMarc-André Lureau "Failed to get socket infos"); 2296cc5a615SMarc-André Lureau return false; 2306cc5a615SMarc-André Lureau } 2316cc5a615SMarc-André Lureau 2326cc5a615SMarc-André Lureau *socket = WSASocketW(FROM_PROTOCOL_INFO, 2336cc5a615SMarc-André Lureau FROM_PROTOCOL_INFO, 2346cc5a615SMarc-André Lureau FROM_PROTOCOL_INFO, 2356cc5a615SMarc-André Lureau info, 0, 0); 2366cc5a615SMarc-André Lureau if (*socket == INVALID_SOCKET) { 2376cc5a615SMarc-André Lureau g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError()); 2386cc5a615SMarc-André Lureau g_dbus_method_invocation_return_error( 2396cc5a615SMarc-André Lureau invocation, 2406cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR, 2416cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED, 2426cc5a615SMarc-André Lureau "Couldn't create socket: %s", emsg); 2436cc5a615SMarc-André Lureau return false; 2446cc5a615SMarc-André Lureau } 2456cc5a615SMarc-André Lureau 2466cc5a615SMarc-André Lureau return true; 2476cc5a615SMarc-André Lureau } 2486cc5a615SMarc-André Lureau #endif 2496cc5a615SMarc-André Lureau 250142ca628SMarc-André Lureau static gboolean 251142ca628SMarc-André Lureau dbus_console_register_listener(DBusDisplayConsole *ddc, 252142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 2536cc5a615SMarc-André Lureau #ifdef G_OS_UNIX 254142ca628SMarc-André Lureau GUnixFDList *fd_list, 2556cc5a615SMarc-André Lureau #endif 256142ca628SMarc-André Lureau GVariant *arg_listener) 257142ca628SMarc-André Lureau { 258142ca628SMarc-André Lureau const char *sender = g_dbus_method_invocation_get_sender(invocation); 259142ca628SMarc-André Lureau GDBusConnection *listener_conn; 260142ca628SMarc-André Lureau g_autoptr(GError) err = NULL; 261142ca628SMarc-André Lureau g_autoptr(GSocket) socket = NULL; 262142ca628SMarc-André Lureau g_autoptr(GSocketConnection) socket_conn = NULL; 263142ca628SMarc-André Lureau g_autofree char *guid = g_dbus_generate_guid(); 264142ca628SMarc-André Lureau DBusDisplayListener *listener; 265142ca628SMarc-André Lureau int fd; 266142ca628SMarc-André Lureau 26799997823SMarc-André Lureau if (sender && g_hash_table_contains(ddc->listeners, sender)) { 268142ca628SMarc-André Lureau g_dbus_method_invocation_return_error( 269142ca628SMarc-André Lureau invocation, 270142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR, 271142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_INVALID, 272142ca628SMarc-André Lureau "`%s` is already registered!", 273142ca628SMarc-André Lureau sender); 274142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 275142ca628SMarc-André Lureau } 276142ca628SMarc-André Lureau 2776cc5a615SMarc-André Lureau #ifdef G_OS_WIN32 2786cc5a615SMarc-André Lureau if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) { 2796cc5a615SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 2806cc5a615SMarc-André Lureau } 2816cc5a615SMarc-André Lureau #else 282142ca628SMarc-André Lureau fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err); 283142ca628SMarc-André Lureau if (err) { 284142ca628SMarc-André Lureau g_dbus_method_invocation_return_error( 285142ca628SMarc-André Lureau invocation, 286142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR, 287142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED, 288142ca628SMarc-André Lureau "Couldn't get peer fd: %s", err->message); 289142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 290142ca628SMarc-André Lureau } 2916cc5a615SMarc-André Lureau #endif 292142ca628SMarc-André Lureau 293142ca628SMarc-André Lureau socket = g_socket_new_from_fd(fd, &err); 294142ca628SMarc-André Lureau if (err) { 295142ca628SMarc-André Lureau g_dbus_method_invocation_return_error( 296142ca628SMarc-André Lureau invocation, 297142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR, 298142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED, 299142ca628SMarc-André Lureau "Couldn't make a socket: %s", err->message); 3006cc5a615SMarc-André Lureau #ifdef G_OS_WIN32 3016cc5a615SMarc-André Lureau closesocket(fd); 3026cc5a615SMarc-André Lureau #else 303142ca628SMarc-André Lureau close(fd); 3046cc5a615SMarc-André Lureau #endif 305142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 306142ca628SMarc-André Lureau } 307142ca628SMarc-André Lureau socket_conn = g_socket_connection_factory_create_connection(socket); 308142ca628SMarc-André Lureau 309142ca628SMarc-André Lureau qemu_dbus_display1_console_complete_register_listener( 3106cc5a615SMarc-André Lureau ddc->iface, invocation 3116cc5a615SMarc-André Lureau #ifdef G_OS_UNIX 3126cc5a615SMarc-André Lureau , NULL 3136cc5a615SMarc-André Lureau #endif 3146cc5a615SMarc-André Lureau ); 315142ca628SMarc-André Lureau 316142ca628SMarc-André Lureau listener_conn = g_dbus_connection_new_sync( 317142ca628SMarc-André Lureau G_IO_STREAM(socket_conn), 318142ca628SMarc-André Lureau guid, 319142ca628SMarc-André Lureau G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER, 320142ca628SMarc-André Lureau NULL, NULL, &err); 321142ca628SMarc-André Lureau if (err) { 322142ca628SMarc-André Lureau error_report("Failed to setup peer connection: %s", err->message); 323142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 324142ca628SMarc-André Lureau } 325142ca628SMarc-André Lureau 326142ca628SMarc-André Lureau listener = dbus_display_listener_new(sender, listener_conn, ddc); 327142ca628SMarc-André Lureau if (!listener) { 328142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 329142ca628SMarc-André Lureau } 330142ca628SMarc-André Lureau 331142ca628SMarc-André Lureau g_hash_table_insert(ddc->listeners, 332142ca628SMarc-André Lureau (gpointer)dbus_display_listener_get_bus_name(listener), 333142ca628SMarc-André Lureau listener); 334142ca628SMarc-André Lureau g_object_connect(listener_conn, 335142ca628SMarc-André Lureau "swapped-signal::closed", listener_vanished_cb, listener, 336142ca628SMarc-André Lureau NULL); 337142ca628SMarc-André Lureau 338142ca628SMarc-André Lureau trace_dbus_registered_listener(sender); 339142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 340142ca628SMarc-André Lureau } 341142ca628SMarc-André Lureau 342142ca628SMarc-André Lureau static gboolean 343142ca628SMarc-André Lureau dbus_kbd_press(DBusDisplayConsole *ddc, 344142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 345142ca628SMarc-André Lureau guint arg_keycode) 346142ca628SMarc-André Lureau { 347142ca628SMarc-André Lureau QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode); 348142ca628SMarc-André Lureau 349142ca628SMarc-André Lureau trace_dbus_kbd_press(arg_keycode); 350142ca628SMarc-André Lureau 351142ca628SMarc-André Lureau qkbd_state_key_event(ddc->kbd, qcode, true); 352142ca628SMarc-André Lureau 353142ca628SMarc-André Lureau qemu_dbus_display1_keyboard_complete_press(ddc->iface_kbd, invocation); 354142ca628SMarc-André Lureau 355142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 356142ca628SMarc-André Lureau } 357142ca628SMarc-André Lureau 358142ca628SMarc-André Lureau static gboolean 359142ca628SMarc-André Lureau dbus_kbd_release(DBusDisplayConsole *ddc, 360142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 361142ca628SMarc-André Lureau guint arg_keycode) 362142ca628SMarc-André Lureau { 363142ca628SMarc-André Lureau QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode); 364142ca628SMarc-André Lureau 365142ca628SMarc-André Lureau trace_dbus_kbd_release(arg_keycode); 366142ca628SMarc-André Lureau 367142ca628SMarc-André Lureau qkbd_state_key_event(ddc->kbd, qcode, false); 368142ca628SMarc-André Lureau 369142ca628SMarc-André Lureau qemu_dbus_display1_keyboard_complete_release(ddc->iface_kbd, invocation); 370142ca628SMarc-André Lureau 371142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 372142ca628SMarc-André Lureau } 373142ca628SMarc-André Lureau 374142ca628SMarc-André Lureau static void 375142ca628SMarc-André Lureau dbus_kbd_qemu_leds_updated(void *data, int ledstate) 376142ca628SMarc-André Lureau { 377142ca628SMarc-André Lureau DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(data); 378142ca628SMarc-André Lureau 379142ca628SMarc-André Lureau qemu_dbus_display1_keyboard_set_modifiers(ddc->iface_kbd, ledstate); 380142ca628SMarc-André Lureau } 381142ca628SMarc-André Lureau 382142ca628SMarc-André Lureau static gboolean 383142ca628SMarc-André Lureau dbus_mouse_rel_motion(DBusDisplayConsole *ddc, 384142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 385142ca628SMarc-André Lureau int dx, int dy) 386142ca628SMarc-André Lureau { 387142ca628SMarc-André Lureau trace_dbus_mouse_rel_motion(dx, dy); 388142ca628SMarc-André Lureau 389142ca628SMarc-André Lureau if (qemu_input_is_absolute()) { 390142ca628SMarc-André Lureau g_dbus_method_invocation_return_error( 391142ca628SMarc-André Lureau invocation, DBUS_DISPLAY_ERROR, 392142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_INVALID, 393142ca628SMarc-André Lureau "Mouse is not relative"); 394142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 395142ca628SMarc-André Lureau } 396142ca628SMarc-André Lureau 397417a2319SMarc-André Lureau qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_X, dx); 398417a2319SMarc-André Lureau qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_Y, dy); 399142ca628SMarc-André Lureau qemu_input_event_sync(); 400142ca628SMarc-André Lureau 401142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_rel_motion(ddc->iface_mouse, 402142ca628SMarc-André Lureau invocation); 403142ca628SMarc-André Lureau 404142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 405142ca628SMarc-André Lureau } 406142ca628SMarc-André Lureau 407142ca628SMarc-André Lureau static gboolean 408de9f844cSBilal Elmoussaoui dbus_touch_send_event(DBusDisplayConsole *ddc, 409de9f844cSBilal Elmoussaoui GDBusMethodInvocation *invocation, 410de9f844cSBilal Elmoussaoui guint kind, uint64_t num_slot, 411de9f844cSBilal Elmoussaoui double x, double y) 412de9f844cSBilal Elmoussaoui { 413de9f844cSBilal Elmoussaoui Error *error = NULL; 414de9f844cSBilal Elmoussaoui int width, height; 415de9f844cSBilal Elmoussaoui trace_dbus_touch_send_event(kind, num_slot, x, y); 416de9f844cSBilal Elmoussaoui 417de9f844cSBilal Elmoussaoui if (kind != INPUT_MULTI_TOUCH_TYPE_BEGIN && 418de9f844cSBilal Elmoussaoui kind != INPUT_MULTI_TOUCH_TYPE_UPDATE && 419de9f844cSBilal Elmoussaoui kind != INPUT_MULTI_TOUCH_TYPE_CANCEL && 420de9f844cSBilal Elmoussaoui kind != INPUT_MULTI_TOUCH_TYPE_END) 421de9f844cSBilal Elmoussaoui { 422de9f844cSBilal Elmoussaoui g_dbus_method_invocation_return_error( 423de9f844cSBilal Elmoussaoui invocation, DBUS_DISPLAY_ERROR, 424de9f844cSBilal Elmoussaoui DBUS_DISPLAY_ERROR_INVALID, 425de9f844cSBilal Elmoussaoui "Invalid touch event kind"); 426de9f844cSBilal Elmoussaoui return DBUS_METHOD_INVOCATION_HANDLED; 427de9f844cSBilal Elmoussaoui } 428de9f844cSBilal Elmoussaoui width = qemu_console_get_width(ddc->dcl.con, 0); 429de9f844cSBilal Elmoussaoui height = qemu_console_get_height(ddc->dcl.con, 0); 430de9f844cSBilal Elmoussaoui 431de9f844cSBilal Elmoussaoui console_handle_touch_event(ddc->dcl.con, touch_slots, 432de9f844cSBilal Elmoussaoui num_slot, width, height, 433de9f844cSBilal Elmoussaoui x, y, kind, &error); 434de9f844cSBilal Elmoussaoui if (error != NULL) { 435de9f844cSBilal Elmoussaoui g_dbus_method_invocation_return_error( 436de9f844cSBilal Elmoussaoui invocation, DBUS_DISPLAY_ERROR, 437de9f844cSBilal Elmoussaoui DBUS_DISPLAY_ERROR_INVALID, 438de9f844cSBilal Elmoussaoui error_get_pretty(error), NULL); 439de9f844cSBilal Elmoussaoui error_free(error); 440de9f844cSBilal Elmoussaoui } else { 441de9f844cSBilal Elmoussaoui qemu_dbus_display1_multi_touch_complete_send_event(ddc->iface_touch, 442de9f844cSBilal Elmoussaoui invocation); 443de9f844cSBilal Elmoussaoui } 444de9f844cSBilal Elmoussaoui return DBUS_METHOD_INVOCATION_HANDLED; 445de9f844cSBilal Elmoussaoui } 446de9f844cSBilal Elmoussaoui 447de9f844cSBilal Elmoussaoui static gboolean 448142ca628SMarc-André Lureau dbus_mouse_set_pos(DBusDisplayConsole *ddc, 449142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 450142ca628SMarc-André Lureau guint x, guint y) 451142ca628SMarc-André Lureau { 452142ca628SMarc-André Lureau int width, height; 453142ca628SMarc-André Lureau 454142ca628SMarc-André Lureau trace_dbus_mouse_set_pos(x, y); 455142ca628SMarc-André Lureau 456142ca628SMarc-André Lureau if (!qemu_input_is_absolute()) { 457142ca628SMarc-André Lureau g_dbus_method_invocation_return_error( 458142ca628SMarc-André Lureau invocation, DBUS_DISPLAY_ERROR, 459142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_INVALID, 460142ca628SMarc-André Lureau "Mouse is not absolute"); 461142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 462142ca628SMarc-André Lureau } 463142ca628SMarc-André Lureau 464417a2319SMarc-André Lureau width = qemu_console_get_width(ddc->dcl.con, 0); 465417a2319SMarc-André Lureau height = qemu_console_get_height(ddc->dcl.con, 0); 466142ca628SMarc-André Lureau if (x >= width || y >= height) { 467142ca628SMarc-André Lureau g_dbus_method_invocation_return_error( 468142ca628SMarc-André Lureau invocation, DBUS_DISPLAY_ERROR, 469142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_INVALID, 470142ca628SMarc-André Lureau "Invalid mouse position"); 471142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 472142ca628SMarc-André Lureau } 473417a2319SMarc-André Lureau qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_X, x, 0, width); 474417a2319SMarc-André Lureau qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_Y, y, 0, height); 475142ca628SMarc-André Lureau qemu_input_event_sync(); 476142ca628SMarc-André Lureau 477142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_set_abs_position(ddc->iface_mouse, 478142ca628SMarc-André Lureau invocation); 479142ca628SMarc-André Lureau 480142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 481142ca628SMarc-André Lureau } 482142ca628SMarc-André Lureau 483142ca628SMarc-André Lureau static gboolean 484142ca628SMarc-André Lureau dbus_mouse_press(DBusDisplayConsole *ddc, 485142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 486142ca628SMarc-André Lureau guint button) 487142ca628SMarc-André Lureau { 488142ca628SMarc-André Lureau trace_dbus_mouse_press(button); 489142ca628SMarc-André Lureau 490417a2319SMarc-André Lureau qemu_input_queue_btn(ddc->dcl.con, button, true); 491142ca628SMarc-André Lureau qemu_input_event_sync(); 492142ca628SMarc-André Lureau 493142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation); 494142ca628SMarc-André Lureau 495142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 496142ca628SMarc-André Lureau } 497142ca628SMarc-André Lureau 498142ca628SMarc-André Lureau static gboolean 499142ca628SMarc-André Lureau dbus_mouse_release(DBusDisplayConsole *ddc, 500142ca628SMarc-André Lureau GDBusMethodInvocation *invocation, 501142ca628SMarc-André Lureau guint button) 502142ca628SMarc-André Lureau { 503142ca628SMarc-André Lureau trace_dbus_mouse_release(button); 504142ca628SMarc-André Lureau 505417a2319SMarc-André Lureau qemu_input_queue_btn(ddc->dcl.con, button, false); 506142ca628SMarc-André Lureau qemu_input_event_sync(); 507142ca628SMarc-André Lureau 508142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_release(ddc->iface_mouse, invocation); 509142ca628SMarc-André Lureau 510142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED; 511142ca628SMarc-André Lureau } 512142ca628SMarc-André Lureau 513142ca628SMarc-André Lureau static void 514eb9062d4SMarc-André Lureau dbus_mouse_update_is_absolute(DBusDisplayConsole *ddc) 515eb9062d4SMarc-André Lureau { 516eb9062d4SMarc-André Lureau g_object_set(ddc->iface_mouse, 517eb9062d4SMarc-André Lureau "is-absolute", qemu_input_is_absolute(), 518eb9062d4SMarc-André Lureau NULL); 519eb9062d4SMarc-André Lureau } 520eb9062d4SMarc-André Lureau 521eb9062d4SMarc-André Lureau static void 522142ca628SMarc-André Lureau dbus_mouse_mode_change(Notifier *notify, void *data) 523142ca628SMarc-André Lureau { 524142ca628SMarc-André Lureau DBusDisplayConsole *ddc = 525142ca628SMarc-André Lureau container_of(notify, DBusDisplayConsole, mouse_mode_notifier); 526142ca628SMarc-André Lureau 527eb9062d4SMarc-André Lureau dbus_mouse_update_is_absolute(ddc); 528142ca628SMarc-André Lureau } 529142ca628SMarc-André Lureau 530142ca628SMarc-André Lureau int dbus_display_console_get_index(DBusDisplayConsole *ddc) 531142ca628SMarc-André Lureau { 532417a2319SMarc-André Lureau return qemu_console_get_index(ddc->dcl.con); 533142ca628SMarc-André Lureau } 534142ca628SMarc-André Lureau 535142ca628SMarc-André Lureau DBusDisplayConsole * 536142ca628SMarc-André Lureau dbus_display_console_new(DBusDisplay *display, QemuConsole *con) 537142ca628SMarc-André Lureau { 538142ca628SMarc-André Lureau g_autofree char *path = NULL; 539142ca628SMarc-André Lureau g_autofree char *label = NULL; 540142ca628SMarc-André Lureau char device_addr[256] = ""; 541142ca628SMarc-André Lureau DBusDisplayConsole *ddc; 542de9f844cSBilal Elmoussaoui int idx, i; 543439e0164SMarc-André Lureau const char *interfaces[] = { 544439e0164SMarc-André Lureau "org.qemu.Display1.Keyboard", 545439e0164SMarc-André Lureau "org.qemu.Display1.Mouse", 546439e0164SMarc-André Lureau "org.qemu.Display1.MultiTouch", 547439e0164SMarc-André Lureau NULL 548439e0164SMarc-André Lureau }; 549142ca628SMarc-André Lureau 550142ca628SMarc-André Lureau assert(display); 551142ca628SMarc-André Lureau assert(con); 552142ca628SMarc-André Lureau 553142ca628SMarc-André Lureau label = qemu_console_get_label(con); 554142ca628SMarc-André Lureau idx = qemu_console_get_index(con); 555142ca628SMarc-André Lureau path = g_strdup_printf(DBUS_DISPLAY1_ROOT "/Console_%d", idx); 556142ca628SMarc-André Lureau ddc = g_object_new(DBUS_DISPLAY_TYPE_CONSOLE, 557142ca628SMarc-André Lureau "g-object-path", path, 558142ca628SMarc-André Lureau NULL); 559142ca628SMarc-André Lureau ddc->display = display; 560417a2319SMarc-André Lureau ddc->dcl.con = con; 561142ca628SMarc-André Lureau /* handle errors, and skip non graphics? */ 562142ca628SMarc-André Lureau qemu_console_fill_device_address( 563142ca628SMarc-André Lureau con, device_addr, sizeof(device_addr), NULL); 564142ca628SMarc-André Lureau 565142ca628SMarc-André Lureau ddc->iface = qemu_dbus_display1_console_skeleton_new(); 566142ca628SMarc-André Lureau g_object_set(ddc->iface, 567142ca628SMarc-André Lureau "label", label, 568142ca628SMarc-André Lureau "type", qemu_console_is_graphic(con) ? "Graphic" : "Text", 569142ca628SMarc-André Lureau "head", qemu_console_get_head(con), 570142ca628SMarc-André Lureau "width", qemu_console_get_width(con, 0), 571142ca628SMarc-André Lureau "height", qemu_console_get_height(con, 0), 572142ca628SMarc-André Lureau "device-address", device_addr, 573439e0164SMarc-André Lureau "interfaces", interfaces, 574142ca628SMarc-André Lureau NULL); 575142ca628SMarc-André Lureau g_object_connect(ddc->iface, 576142ca628SMarc-André Lureau "swapped-signal::handle-register-listener", 577142ca628SMarc-André Lureau dbus_console_register_listener, ddc, 578142ca628SMarc-André Lureau "swapped-signal::handle-set-uiinfo", 579142ca628SMarc-André Lureau dbus_console_set_ui_info, ddc, 580142ca628SMarc-André Lureau NULL); 581142ca628SMarc-André Lureau g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc), 582142ca628SMarc-André Lureau G_DBUS_INTERFACE_SKELETON(ddc->iface)); 583142ca628SMarc-André Lureau 584142ca628SMarc-André Lureau ddc->kbd = qkbd_state_init(con); 585142ca628SMarc-André Lureau ddc->iface_kbd = qemu_dbus_display1_keyboard_skeleton_new(); 586142ca628SMarc-André Lureau qemu_add_led_event_handler(dbus_kbd_qemu_leds_updated, ddc); 587142ca628SMarc-André Lureau g_object_connect(ddc->iface_kbd, 588142ca628SMarc-André Lureau "swapped-signal::handle-press", dbus_kbd_press, ddc, 589142ca628SMarc-André Lureau "swapped-signal::handle-release", dbus_kbd_release, ddc, 590142ca628SMarc-André Lureau NULL); 591142ca628SMarc-André Lureau g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc), 592142ca628SMarc-André Lureau G_DBUS_INTERFACE_SKELETON(ddc->iface_kbd)); 593142ca628SMarc-André Lureau 594142ca628SMarc-André Lureau ddc->iface_mouse = qemu_dbus_display1_mouse_skeleton_new(); 595142ca628SMarc-André Lureau g_object_connect(ddc->iface_mouse, 596142ca628SMarc-André Lureau "swapped-signal::handle-set-abs-position", dbus_mouse_set_pos, ddc, 597142ca628SMarc-André Lureau "swapped-signal::handle-rel-motion", dbus_mouse_rel_motion, ddc, 598142ca628SMarc-André Lureau "swapped-signal::handle-press", dbus_mouse_press, ddc, 599142ca628SMarc-André Lureau "swapped-signal::handle-release", dbus_mouse_release, ddc, 600142ca628SMarc-André Lureau NULL); 601142ca628SMarc-André Lureau g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc), 602142ca628SMarc-André Lureau G_DBUS_INTERFACE_SKELETON(ddc->iface_mouse)); 603142ca628SMarc-André Lureau 604de9f844cSBilal Elmoussaoui ddc->iface_touch = qemu_dbus_display1_multi_touch_skeleton_new(); 605de9f844cSBilal Elmoussaoui g_object_connect(ddc->iface_touch, 606de9f844cSBilal Elmoussaoui "swapped-signal::handle-send-event", dbus_touch_send_event, ddc, 607de9f844cSBilal Elmoussaoui NULL); 608de9f844cSBilal Elmoussaoui qemu_dbus_display1_multi_touch_set_max_slots(ddc->iface_touch, 609de9f844cSBilal Elmoussaoui INPUT_EVENT_SLOTS_MAX); 610de9f844cSBilal Elmoussaoui g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc), 611de9f844cSBilal Elmoussaoui G_DBUS_INTERFACE_SKELETON(ddc->iface_touch)); 612de9f844cSBilal Elmoussaoui 613de9f844cSBilal Elmoussaoui for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) { 614de9f844cSBilal Elmoussaoui struct touch_slot *slot = &touch_slots[i]; 615de9f844cSBilal Elmoussaoui slot->tracking_id = -1; 616de9f844cSBilal Elmoussaoui } 617de9f844cSBilal Elmoussaoui 618142ca628SMarc-André Lureau register_displaychangelistener(&ddc->dcl); 619142ca628SMarc-André Lureau ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change; 620142ca628SMarc-André Lureau qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier); 621eb9062d4SMarc-André Lureau dbus_mouse_update_is_absolute(ddc); 622142ca628SMarc-André Lureau 623142ca628SMarc-André Lureau return ddc; 624142ca628SMarc-André Lureau } 625