xref: /qemu/ui/dbus-console.c (revision 0337e412)
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 
G_DEFINE_TYPE(DBusDisplayConsole,dbus_display_console,G_TYPE_DBUS_OBJECT_SKELETON)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
dbus_gfx_switch(DisplayChangeListener * dcl,struct DisplaySurface * new_surface)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
dbus_gfx_update(DisplayChangeListener * dcl,int x,int y,int w,int h)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
dbus_gl_scanout_disable(DisplayChangeListener * dcl)90142ca628SMarc-André Lureau dbus_gl_scanout_disable(DisplayChangeListener *dcl)
91142ca628SMarc-André Lureau {
92142ca628SMarc-André Lureau }
93142ca628SMarc-André Lureau 
94142ca628SMarc-André Lureau 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)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
dbus_gl_scanout_dmabuf(DisplayChangeListener * dcl,QemuDmaBuf * dmabuf)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
dbus_gl_scanout_update(DisplayChangeListener * dcl,uint32_t x,uint32_t y,uint32_t w,uint32_t h)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
dbus_display_console_init(DBusDisplayConsole * object)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
dbus_display_console_dispose(GObject * object)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
dbus_display_console_class_init(DBusDisplayConsoleClass * klass)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
listener_vanished_cb(DBusDisplayListener * listener)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
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)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
dbus_win32_import_socket(GDBusMethodInvocation * invocation,GVariant * arg_listener,int * socket)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
dbus_console_register_listener(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,GUnixFDList * fd_list,GVariant * arg_listener)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
dbus_kbd_press(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint arg_keycode)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
dbus_kbd_release(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint arg_keycode)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
dbus_kbd_qemu_leds_updated(void * data,int ledstate)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
dbus_mouse_rel_motion(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,int dx,int dy)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 
3890337e412SAkihiko Odaki     if (qemu_input_is_absolute(ddc->dcl.con)) {
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
dbus_touch_send_event(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint kind,uint64_t num_slot,double x,double y)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
dbus_mouse_set_pos(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint x,guint y)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 
4560337e412SAkihiko Odaki     if (!qemu_input_is_absolute(ddc->dcl.con)) {
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
dbus_mouse_press(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint button)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
dbus_mouse_release(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint button)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
dbus_mouse_update_is_absolute(DBusDisplayConsole * ddc)514eb9062d4SMarc-André Lureau dbus_mouse_update_is_absolute(DBusDisplayConsole *ddc)
515eb9062d4SMarc-André Lureau {
516eb9062d4SMarc-André Lureau     g_object_set(ddc->iface_mouse,
5170337e412SAkihiko Odaki                  "is-absolute", qemu_input_is_absolute(ddc->dcl.con),
518eb9062d4SMarc-André Lureau                  NULL);
519eb9062d4SMarc-André Lureau }
520eb9062d4SMarc-André Lureau 
521eb9062d4SMarc-André Lureau static void
dbus_mouse_mode_change(Notifier * notify,void * data)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 
dbus_display_console_get_index(DBusDisplayConsole * ddc)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 *
dbus_display_console_new(DBusDisplay * display,QemuConsole * con)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