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;
44*2448ff39SMarc-André Lureau GPtrArray *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 {
1136779a307SDongwon Kim uint32_t width, height;
1146779a307SDongwon Kim
115142ca628SMarc-André Lureau DBusDisplayConsole *ddc = container_of(dcl, DBusDisplayConsole, dcl);
116142ca628SMarc-André Lureau
1176779a307SDongwon Kim width = qemu_dmabuf_get_width(dmabuf);
1186779a307SDongwon Kim height = qemu_dmabuf_get_height(dmabuf);
1196779a307SDongwon Kim
1206779a307SDongwon Kim dbus_display_console_set_size(ddc, width, height);
121142ca628SMarc-André Lureau }
122142ca628SMarc-André Lureau
123142ca628SMarc-André Lureau static void
dbus_gl_scanout_update(DisplayChangeListener * dcl,uint32_t x,uint32_t y,uint32_t w,uint32_t h)124142ca628SMarc-André Lureau dbus_gl_scanout_update(DisplayChangeListener *dcl,
125142ca628SMarc-André Lureau uint32_t x, uint32_t y,
126142ca628SMarc-André Lureau uint32_t w, uint32_t h)
127142ca628SMarc-André Lureau {
128142ca628SMarc-André Lureau }
129142ca628SMarc-André Lureau
130417a2319SMarc-André Lureau const DisplayChangeListenerOps dbus_console_dcl_ops = {
131142ca628SMarc-André Lureau .dpy_name = "dbus-console",
132142ca628SMarc-André Lureau .dpy_gfx_switch = dbus_gfx_switch,
133142ca628SMarc-André Lureau .dpy_gfx_update = dbus_gfx_update,
134142ca628SMarc-André Lureau .dpy_gl_scanout_disable = dbus_gl_scanout_disable,
135142ca628SMarc-André Lureau .dpy_gl_scanout_texture = dbus_gl_scanout_texture,
136142ca628SMarc-André Lureau .dpy_gl_scanout_dmabuf = dbus_gl_scanout_dmabuf,
137142ca628SMarc-André Lureau .dpy_gl_update = dbus_gl_scanout_update,
138142ca628SMarc-André Lureau };
139142ca628SMarc-André Lureau
140142ca628SMarc-André Lureau static void
dbus_display_console_init(DBusDisplayConsole * object)141142ca628SMarc-André Lureau dbus_display_console_init(DBusDisplayConsole *object)
142142ca628SMarc-André Lureau {
143142ca628SMarc-André Lureau DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
144142ca628SMarc-André Lureau
145*2448ff39SMarc-André Lureau ddc->listeners = g_ptr_array_new_with_free_func(g_object_unref);
146142ca628SMarc-André Lureau ddc->dcl.ops = &dbus_console_dcl_ops;
147142ca628SMarc-André Lureau }
148142ca628SMarc-André Lureau
149142ca628SMarc-André Lureau static void
dbus_display_console_dispose(GObject * object)150142ca628SMarc-André Lureau dbus_display_console_dispose(GObject *object)
151142ca628SMarc-André Lureau {
152142ca628SMarc-André Lureau DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(object);
153142ca628SMarc-André Lureau
154142ca628SMarc-André Lureau unregister_displaychangelistener(&ddc->dcl);
155cb6ccdc9SBilal Elmoussaoui g_clear_object(&ddc->iface_touch);
156cb6ccdc9SBilal Elmoussaoui g_clear_object(&ddc->iface_mouse);
157142ca628SMarc-André Lureau g_clear_object(&ddc->iface_kbd);
158142ca628SMarc-André Lureau g_clear_object(&ddc->iface);
159*2448ff39SMarc-André Lureau g_clear_pointer(&ddc->listeners, g_ptr_array_unref);
160142ca628SMarc-André Lureau g_clear_pointer(&ddc->kbd, qkbd_state_free);
161142ca628SMarc-André Lureau
162142ca628SMarc-André Lureau G_OBJECT_CLASS(dbus_display_console_parent_class)->dispose(object);
163142ca628SMarc-André Lureau }
164142ca628SMarc-André Lureau
165142ca628SMarc-André Lureau static void
dbus_display_console_class_init(DBusDisplayConsoleClass * klass)166142ca628SMarc-André Lureau dbus_display_console_class_init(DBusDisplayConsoleClass *klass)
167142ca628SMarc-André Lureau {
168142ca628SMarc-André Lureau GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
169142ca628SMarc-André Lureau
170142ca628SMarc-André Lureau gobject_class->dispose = dbus_display_console_dispose;
171142ca628SMarc-André Lureau }
172142ca628SMarc-André Lureau
173142ca628SMarc-André Lureau static void
listener_vanished_cb(DBusDisplayListener * listener)174142ca628SMarc-André Lureau listener_vanished_cb(DBusDisplayListener *listener)
175142ca628SMarc-André Lureau {
176142ca628SMarc-André Lureau DBusDisplayConsole *ddc = dbus_display_listener_get_console(listener);
177142ca628SMarc-André Lureau const char *name = dbus_display_listener_get_bus_name(listener);
178142ca628SMarc-André Lureau
179142ca628SMarc-André Lureau trace_dbus_listener_vanished(name);
180142ca628SMarc-André Lureau
181*2448ff39SMarc-André Lureau g_ptr_array_remove_fast(ddc->listeners, listener);
182142ca628SMarc-André Lureau qkbd_state_lift_all_keys(ddc->kbd);
183142ca628SMarc-André Lureau }
184142ca628SMarc-André Lureau
185142ca628SMarc-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)186142ca628SMarc-André Lureau dbus_console_set_ui_info(DBusDisplayConsole *ddc,
187142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
188142ca628SMarc-André Lureau guint16 arg_width_mm,
189142ca628SMarc-André Lureau guint16 arg_height_mm,
190142ca628SMarc-André Lureau gint arg_xoff,
191142ca628SMarc-André Lureau gint arg_yoff,
192142ca628SMarc-André Lureau guint arg_width,
193142ca628SMarc-André Lureau guint arg_height)
194142ca628SMarc-André Lureau {
195142ca628SMarc-André Lureau QemuUIInfo info = {
196142ca628SMarc-André Lureau .width_mm = arg_width_mm,
197142ca628SMarc-André Lureau .height_mm = arg_height_mm,
198142ca628SMarc-André Lureau .xoff = arg_xoff,
199142ca628SMarc-André Lureau .yoff = arg_yoff,
200142ca628SMarc-André Lureau .width = arg_width,
201142ca628SMarc-André Lureau .height = arg_height,
202142ca628SMarc-André Lureau };
203142ca628SMarc-André Lureau
204417a2319SMarc-André Lureau if (!dpy_ui_info_supported(ddc->dcl.con)) {
205142ca628SMarc-André Lureau g_dbus_method_invocation_return_error(invocation,
206142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR,
207142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_UNSUPPORTED,
208142ca628SMarc-André Lureau "SetUIInfo is not supported");
209142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
210142ca628SMarc-André Lureau }
211142ca628SMarc-André Lureau
212417a2319SMarc-André Lureau dpy_set_ui_info(ddc->dcl.con, &info, false);
213142ca628SMarc-André Lureau qemu_dbus_display1_console_complete_set_uiinfo(ddc->iface, invocation);
214142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
215142ca628SMarc-André Lureau }
216142ca628SMarc-André Lureau
2176cc5a615SMarc-André Lureau #ifdef G_OS_WIN32
2186cc5a615SMarc-André Lureau bool
dbus_win32_import_socket(GDBusMethodInvocation * invocation,GVariant * arg_listener,int * socket)2196cc5a615SMarc-André Lureau dbus_win32_import_socket(GDBusMethodInvocation *invocation,
2206cc5a615SMarc-André Lureau GVariant *arg_listener, int *socket)
2216cc5a615SMarc-André Lureau {
2226cc5a615SMarc-André Lureau gsize n;
2236cc5a615SMarc-André Lureau WSAPROTOCOL_INFOW *info = (void *)g_variant_get_fixed_array(arg_listener, &n, 1);
2246cc5a615SMarc-André Lureau
2256cc5a615SMarc-André Lureau if (!info || n != sizeof(*info)) {
2266cc5a615SMarc-André Lureau g_dbus_method_invocation_return_error(
2276cc5a615SMarc-André Lureau invocation,
2286cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR,
2296cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED,
2306cc5a615SMarc-André Lureau "Failed to get socket infos");
2316cc5a615SMarc-André Lureau return false;
2326cc5a615SMarc-André Lureau }
2336cc5a615SMarc-André Lureau
2346cc5a615SMarc-André Lureau *socket = WSASocketW(FROM_PROTOCOL_INFO,
2356cc5a615SMarc-André Lureau FROM_PROTOCOL_INFO,
2366cc5a615SMarc-André Lureau FROM_PROTOCOL_INFO,
2376cc5a615SMarc-André Lureau info, 0, 0);
2386cc5a615SMarc-André Lureau if (*socket == INVALID_SOCKET) {
2396cc5a615SMarc-André Lureau g_autofree gchar *emsg = g_win32_error_message(WSAGetLastError());
2406cc5a615SMarc-André Lureau g_dbus_method_invocation_return_error(
2416cc5a615SMarc-André Lureau invocation,
2426cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR,
2436cc5a615SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED,
2446cc5a615SMarc-André Lureau "Couldn't create socket: %s", emsg);
2456cc5a615SMarc-André Lureau return false;
2466cc5a615SMarc-André Lureau }
2476cc5a615SMarc-André Lureau
2486cc5a615SMarc-André Lureau return true;
2496cc5a615SMarc-André Lureau }
2506cc5a615SMarc-André Lureau #endif
2516cc5a615SMarc-André Lureau
252142ca628SMarc-André Lureau static gboolean
dbus_console_register_listener(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,GUnixFDList * fd_list,GVariant * arg_listener)253142ca628SMarc-André Lureau dbus_console_register_listener(DBusDisplayConsole *ddc,
254142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
2556cc5a615SMarc-André Lureau #ifdef G_OS_UNIX
256142ca628SMarc-André Lureau GUnixFDList *fd_list,
2576cc5a615SMarc-André Lureau #endif
258142ca628SMarc-André Lureau GVariant *arg_listener)
259142ca628SMarc-André Lureau {
260142ca628SMarc-André Lureau const char *sender = g_dbus_method_invocation_get_sender(invocation);
261142ca628SMarc-André Lureau GDBusConnection *listener_conn;
262142ca628SMarc-André Lureau g_autoptr(GError) err = NULL;
263142ca628SMarc-André Lureau g_autoptr(GSocket) socket = NULL;
264142ca628SMarc-André Lureau g_autoptr(GSocketConnection) socket_conn = NULL;
265142ca628SMarc-André Lureau g_autofree char *guid = g_dbus_generate_guid();
266142ca628SMarc-André Lureau DBusDisplayListener *listener;
267142ca628SMarc-André Lureau int fd;
268142ca628SMarc-André Lureau
2696cc5a615SMarc-André Lureau #ifdef G_OS_WIN32
2706cc5a615SMarc-André Lureau if (!dbus_win32_import_socket(invocation, arg_listener, &fd)) {
2716cc5a615SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
2726cc5a615SMarc-André Lureau }
2736cc5a615SMarc-André Lureau #else
274142ca628SMarc-André Lureau fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(arg_listener), &err);
275142ca628SMarc-André Lureau if (err) {
276142ca628SMarc-André Lureau g_dbus_method_invocation_return_error(
277142ca628SMarc-André Lureau invocation,
278142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR,
279142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED,
280142ca628SMarc-André Lureau "Couldn't get peer fd: %s", err->message);
281142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
282142ca628SMarc-André Lureau }
2836cc5a615SMarc-André Lureau #endif
284142ca628SMarc-André Lureau
285142ca628SMarc-André Lureau socket = g_socket_new_from_fd(fd, &err);
286142ca628SMarc-André Lureau if (err) {
287142ca628SMarc-André Lureau g_dbus_method_invocation_return_error(
288142ca628SMarc-André Lureau invocation,
289142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR,
290142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_FAILED,
291142ca628SMarc-André Lureau "Couldn't make a socket: %s", err->message);
2926cc5a615SMarc-André Lureau #ifdef G_OS_WIN32
2936cc5a615SMarc-André Lureau closesocket(fd);
2946cc5a615SMarc-André Lureau #else
295142ca628SMarc-André Lureau close(fd);
2966cc5a615SMarc-André Lureau #endif
297142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
298142ca628SMarc-André Lureau }
299142ca628SMarc-André Lureau socket_conn = g_socket_connection_factory_create_connection(socket);
300142ca628SMarc-André Lureau
301142ca628SMarc-André Lureau qemu_dbus_display1_console_complete_register_listener(
3026cc5a615SMarc-André Lureau ddc->iface, invocation
3036cc5a615SMarc-André Lureau #ifdef G_OS_UNIX
3046cc5a615SMarc-André Lureau , NULL
3056cc5a615SMarc-André Lureau #endif
3066cc5a615SMarc-André Lureau );
307142ca628SMarc-André Lureau
308142ca628SMarc-André Lureau listener_conn = g_dbus_connection_new_sync(
309142ca628SMarc-André Lureau G_IO_STREAM(socket_conn),
310142ca628SMarc-André Lureau guid,
311142ca628SMarc-André Lureau G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
312142ca628SMarc-André Lureau NULL, NULL, &err);
313142ca628SMarc-André Lureau if (err) {
314142ca628SMarc-André Lureau error_report("Failed to setup peer connection: %s", err->message);
315142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
316142ca628SMarc-André Lureau }
317142ca628SMarc-André Lureau
318142ca628SMarc-André Lureau listener = dbus_display_listener_new(sender, listener_conn, ddc);
319142ca628SMarc-André Lureau if (!listener) {
320142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
321142ca628SMarc-André Lureau }
322142ca628SMarc-André Lureau
323*2448ff39SMarc-André Lureau g_ptr_array_add(ddc->listeners, listener);
324142ca628SMarc-André Lureau g_object_connect(listener_conn,
325142ca628SMarc-André Lureau "swapped-signal::closed", listener_vanished_cb, listener,
326142ca628SMarc-André Lureau NULL);
327142ca628SMarc-André Lureau
328142ca628SMarc-André Lureau trace_dbus_registered_listener(sender);
329142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
330142ca628SMarc-André Lureau }
331142ca628SMarc-André Lureau
332142ca628SMarc-André Lureau static gboolean
dbus_kbd_press(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint arg_keycode)333142ca628SMarc-André Lureau dbus_kbd_press(DBusDisplayConsole *ddc,
334142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
335142ca628SMarc-André Lureau guint arg_keycode)
336142ca628SMarc-André Lureau {
337142ca628SMarc-André Lureau QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
338142ca628SMarc-André Lureau
339142ca628SMarc-André Lureau trace_dbus_kbd_press(arg_keycode);
340142ca628SMarc-André Lureau
341142ca628SMarc-André Lureau qkbd_state_key_event(ddc->kbd, qcode, true);
342142ca628SMarc-André Lureau
343142ca628SMarc-André Lureau qemu_dbus_display1_keyboard_complete_press(ddc->iface_kbd, invocation);
344142ca628SMarc-André Lureau
345142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
346142ca628SMarc-André Lureau }
347142ca628SMarc-André Lureau
348142ca628SMarc-André Lureau static gboolean
dbus_kbd_release(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint arg_keycode)349142ca628SMarc-André Lureau dbus_kbd_release(DBusDisplayConsole *ddc,
350142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
351142ca628SMarc-André Lureau guint arg_keycode)
352142ca628SMarc-André Lureau {
353142ca628SMarc-André Lureau QKeyCode qcode = qemu_input_key_number_to_qcode(arg_keycode);
354142ca628SMarc-André Lureau
355142ca628SMarc-André Lureau trace_dbus_kbd_release(arg_keycode);
356142ca628SMarc-André Lureau
357142ca628SMarc-André Lureau qkbd_state_key_event(ddc->kbd, qcode, false);
358142ca628SMarc-André Lureau
359142ca628SMarc-André Lureau qemu_dbus_display1_keyboard_complete_release(ddc->iface_kbd, invocation);
360142ca628SMarc-André Lureau
361142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
362142ca628SMarc-André Lureau }
363142ca628SMarc-André Lureau
364142ca628SMarc-André Lureau static void
dbus_kbd_qemu_leds_updated(void * data,int ledstate)365142ca628SMarc-André Lureau dbus_kbd_qemu_leds_updated(void *data, int ledstate)
366142ca628SMarc-André Lureau {
367142ca628SMarc-André Lureau DBusDisplayConsole *ddc = DBUS_DISPLAY_CONSOLE(data);
368142ca628SMarc-André Lureau
369142ca628SMarc-André Lureau qemu_dbus_display1_keyboard_set_modifiers(ddc->iface_kbd, ledstate);
370142ca628SMarc-André Lureau }
371142ca628SMarc-André Lureau
372142ca628SMarc-André Lureau static gboolean
dbus_mouse_rel_motion(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,int dx,int dy)373142ca628SMarc-André Lureau dbus_mouse_rel_motion(DBusDisplayConsole *ddc,
374142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
375142ca628SMarc-André Lureau int dx, int dy)
376142ca628SMarc-André Lureau {
377142ca628SMarc-André Lureau trace_dbus_mouse_rel_motion(dx, dy);
378142ca628SMarc-André Lureau
3790337e412SAkihiko Odaki if (qemu_input_is_absolute(ddc->dcl.con)) {
380142ca628SMarc-André Lureau g_dbus_method_invocation_return_error(
381142ca628SMarc-André Lureau invocation, DBUS_DISPLAY_ERROR,
382142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_INVALID,
383142ca628SMarc-André Lureau "Mouse is not relative");
384142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
385142ca628SMarc-André Lureau }
386142ca628SMarc-André Lureau
387417a2319SMarc-André Lureau qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_X, dx);
388417a2319SMarc-André Lureau qemu_input_queue_rel(ddc->dcl.con, INPUT_AXIS_Y, dy);
389142ca628SMarc-André Lureau qemu_input_event_sync();
390142ca628SMarc-André Lureau
391142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_rel_motion(ddc->iface_mouse,
392142ca628SMarc-André Lureau invocation);
393142ca628SMarc-André Lureau
394142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
395142ca628SMarc-André Lureau }
396142ca628SMarc-André Lureau
397142ca628SMarc-André Lureau static gboolean
dbus_touch_send_event(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint kind,uint64_t num_slot,double x,double y)398de9f844cSBilal Elmoussaoui dbus_touch_send_event(DBusDisplayConsole *ddc,
399de9f844cSBilal Elmoussaoui GDBusMethodInvocation *invocation,
400de9f844cSBilal Elmoussaoui guint kind, uint64_t num_slot,
401de9f844cSBilal Elmoussaoui double x, double y)
402de9f844cSBilal Elmoussaoui {
403de9f844cSBilal Elmoussaoui Error *error = NULL;
404de9f844cSBilal Elmoussaoui int width, height;
405de9f844cSBilal Elmoussaoui trace_dbus_touch_send_event(kind, num_slot, x, y);
406de9f844cSBilal Elmoussaoui
407de9f844cSBilal Elmoussaoui if (kind != INPUT_MULTI_TOUCH_TYPE_BEGIN &&
408de9f844cSBilal Elmoussaoui kind != INPUT_MULTI_TOUCH_TYPE_UPDATE &&
409de9f844cSBilal Elmoussaoui kind != INPUT_MULTI_TOUCH_TYPE_CANCEL &&
410de9f844cSBilal Elmoussaoui kind != INPUT_MULTI_TOUCH_TYPE_END)
411de9f844cSBilal Elmoussaoui {
412de9f844cSBilal Elmoussaoui g_dbus_method_invocation_return_error(
413de9f844cSBilal Elmoussaoui invocation, DBUS_DISPLAY_ERROR,
414de9f844cSBilal Elmoussaoui DBUS_DISPLAY_ERROR_INVALID,
415de9f844cSBilal Elmoussaoui "Invalid touch event kind");
416de9f844cSBilal Elmoussaoui return DBUS_METHOD_INVOCATION_HANDLED;
417de9f844cSBilal Elmoussaoui }
418de9f844cSBilal Elmoussaoui width = qemu_console_get_width(ddc->dcl.con, 0);
419de9f844cSBilal Elmoussaoui height = qemu_console_get_height(ddc->dcl.con, 0);
420de9f844cSBilal Elmoussaoui
421de9f844cSBilal Elmoussaoui console_handle_touch_event(ddc->dcl.con, touch_slots,
422de9f844cSBilal Elmoussaoui num_slot, width, height,
423de9f844cSBilal Elmoussaoui x, y, kind, &error);
424de9f844cSBilal Elmoussaoui if (error != NULL) {
425de9f844cSBilal Elmoussaoui g_dbus_method_invocation_return_error(
426de9f844cSBilal Elmoussaoui invocation, DBUS_DISPLAY_ERROR,
427de9f844cSBilal Elmoussaoui DBUS_DISPLAY_ERROR_INVALID,
428de9f844cSBilal Elmoussaoui error_get_pretty(error), NULL);
429de9f844cSBilal Elmoussaoui error_free(error);
430de9f844cSBilal Elmoussaoui } else {
431de9f844cSBilal Elmoussaoui qemu_dbus_display1_multi_touch_complete_send_event(ddc->iface_touch,
432de9f844cSBilal Elmoussaoui invocation);
433de9f844cSBilal Elmoussaoui }
434de9f844cSBilal Elmoussaoui return DBUS_METHOD_INVOCATION_HANDLED;
435de9f844cSBilal Elmoussaoui }
436de9f844cSBilal Elmoussaoui
437de9f844cSBilal Elmoussaoui static gboolean
dbus_mouse_set_pos(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint x,guint y)438142ca628SMarc-André Lureau dbus_mouse_set_pos(DBusDisplayConsole *ddc,
439142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
440142ca628SMarc-André Lureau guint x, guint y)
441142ca628SMarc-André Lureau {
442142ca628SMarc-André Lureau int width, height;
443142ca628SMarc-André Lureau
444142ca628SMarc-André Lureau trace_dbus_mouse_set_pos(x, y);
445142ca628SMarc-André Lureau
4460337e412SAkihiko Odaki if (!qemu_input_is_absolute(ddc->dcl.con)) {
447142ca628SMarc-André Lureau g_dbus_method_invocation_return_error(
448142ca628SMarc-André Lureau invocation, DBUS_DISPLAY_ERROR,
449142ca628SMarc-André Lureau DBUS_DISPLAY_ERROR_INVALID,
450142ca628SMarc-André Lureau "Mouse is not absolute");
451142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
452142ca628SMarc-André Lureau }
453142ca628SMarc-André Lureau
454417a2319SMarc-André Lureau width = qemu_console_get_width(ddc->dcl.con, 0);
455417a2319SMarc-André Lureau height = qemu_console_get_height(ddc->dcl.con, 0);
456142ca628SMarc-André Lureau if (x >= width || y >= height) {
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 "Invalid mouse position");
461142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
462142ca628SMarc-André Lureau }
463417a2319SMarc-André Lureau qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_X, x, 0, width);
464417a2319SMarc-André Lureau qemu_input_queue_abs(ddc->dcl.con, INPUT_AXIS_Y, y, 0, height);
465142ca628SMarc-André Lureau qemu_input_event_sync();
466142ca628SMarc-André Lureau
467142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_set_abs_position(ddc->iface_mouse,
468142ca628SMarc-André Lureau invocation);
469142ca628SMarc-André Lureau
470142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
471142ca628SMarc-André Lureau }
472142ca628SMarc-André Lureau
473142ca628SMarc-André Lureau static gboolean
dbus_mouse_press(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint button)474142ca628SMarc-André Lureau dbus_mouse_press(DBusDisplayConsole *ddc,
475142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
476142ca628SMarc-André Lureau guint button)
477142ca628SMarc-André Lureau {
478142ca628SMarc-André Lureau trace_dbus_mouse_press(button);
479142ca628SMarc-André Lureau
480417a2319SMarc-André Lureau qemu_input_queue_btn(ddc->dcl.con, button, true);
481142ca628SMarc-André Lureau qemu_input_event_sync();
482142ca628SMarc-André Lureau
483142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_press(ddc->iface_mouse, invocation);
484142ca628SMarc-André Lureau
485142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
486142ca628SMarc-André Lureau }
487142ca628SMarc-André Lureau
488142ca628SMarc-André Lureau static gboolean
dbus_mouse_release(DBusDisplayConsole * ddc,GDBusMethodInvocation * invocation,guint button)489142ca628SMarc-André Lureau dbus_mouse_release(DBusDisplayConsole *ddc,
490142ca628SMarc-André Lureau GDBusMethodInvocation *invocation,
491142ca628SMarc-André Lureau guint button)
492142ca628SMarc-André Lureau {
493142ca628SMarc-André Lureau trace_dbus_mouse_release(button);
494142ca628SMarc-André Lureau
495417a2319SMarc-André Lureau qemu_input_queue_btn(ddc->dcl.con, button, false);
496142ca628SMarc-André Lureau qemu_input_event_sync();
497142ca628SMarc-André Lureau
498142ca628SMarc-André Lureau qemu_dbus_display1_mouse_complete_release(ddc->iface_mouse, invocation);
499142ca628SMarc-André Lureau
500142ca628SMarc-André Lureau return DBUS_METHOD_INVOCATION_HANDLED;
501142ca628SMarc-André Lureau }
502142ca628SMarc-André Lureau
503142ca628SMarc-André Lureau static void
dbus_mouse_update_is_absolute(DBusDisplayConsole * ddc)504eb9062d4SMarc-André Lureau dbus_mouse_update_is_absolute(DBusDisplayConsole *ddc)
505eb9062d4SMarc-André Lureau {
506eb9062d4SMarc-André Lureau g_object_set(ddc->iface_mouse,
5070337e412SAkihiko Odaki "is-absolute", qemu_input_is_absolute(ddc->dcl.con),
508eb9062d4SMarc-André Lureau NULL);
509eb9062d4SMarc-André Lureau }
510eb9062d4SMarc-André Lureau
511eb9062d4SMarc-André Lureau static void
dbus_mouse_mode_change(Notifier * notify,void * data)512142ca628SMarc-André Lureau dbus_mouse_mode_change(Notifier *notify, void *data)
513142ca628SMarc-André Lureau {
514142ca628SMarc-André Lureau DBusDisplayConsole *ddc =
515142ca628SMarc-André Lureau container_of(notify, DBusDisplayConsole, mouse_mode_notifier);
516142ca628SMarc-André Lureau
517eb9062d4SMarc-André Lureau dbus_mouse_update_is_absolute(ddc);
518142ca628SMarc-André Lureau }
519142ca628SMarc-André Lureau
dbus_display_console_get_index(DBusDisplayConsole * ddc)520142ca628SMarc-André Lureau int dbus_display_console_get_index(DBusDisplayConsole *ddc)
521142ca628SMarc-André Lureau {
522417a2319SMarc-André Lureau return qemu_console_get_index(ddc->dcl.con);
523142ca628SMarc-André Lureau }
524142ca628SMarc-André Lureau
525142ca628SMarc-André Lureau DBusDisplayConsole *
dbus_display_console_new(DBusDisplay * display,QemuConsole * con)526142ca628SMarc-André Lureau dbus_display_console_new(DBusDisplay *display, QemuConsole *con)
527142ca628SMarc-André Lureau {
528142ca628SMarc-André Lureau g_autofree char *path = NULL;
529142ca628SMarc-André Lureau g_autofree char *label = NULL;
530142ca628SMarc-André Lureau char device_addr[256] = "";
531142ca628SMarc-André Lureau DBusDisplayConsole *ddc;
532de9f844cSBilal Elmoussaoui int idx, i;
533439e0164SMarc-André Lureau const char *interfaces[] = {
534439e0164SMarc-André Lureau "org.qemu.Display1.Keyboard",
535439e0164SMarc-André Lureau "org.qemu.Display1.Mouse",
536439e0164SMarc-André Lureau "org.qemu.Display1.MultiTouch",
537439e0164SMarc-André Lureau NULL
538439e0164SMarc-André Lureau };
539142ca628SMarc-André Lureau
540142ca628SMarc-André Lureau assert(display);
541142ca628SMarc-André Lureau assert(con);
542142ca628SMarc-André Lureau
543142ca628SMarc-André Lureau label = qemu_console_get_label(con);
544142ca628SMarc-André Lureau idx = qemu_console_get_index(con);
545142ca628SMarc-André Lureau path = g_strdup_printf(DBUS_DISPLAY1_ROOT "/Console_%d", idx);
546142ca628SMarc-André Lureau ddc = g_object_new(DBUS_DISPLAY_TYPE_CONSOLE,
547142ca628SMarc-André Lureau "g-object-path", path,
548142ca628SMarc-André Lureau NULL);
549142ca628SMarc-André Lureau ddc->display = display;
550417a2319SMarc-André Lureau ddc->dcl.con = con;
551142ca628SMarc-André Lureau /* handle errors, and skip non graphics? */
552142ca628SMarc-André Lureau qemu_console_fill_device_address(
553142ca628SMarc-André Lureau con, device_addr, sizeof(device_addr), NULL);
554142ca628SMarc-André Lureau
555142ca628SMarc-André Lureau ddc->iface = qemu_dbus_display1_console_skeleton_new();
556142ca628SMarc-André Lureau g_object_set(ddc->iface,
557142ca628SMarc-André Lureau "label", label,
558142ca628SMarc-André Lureau "type", qemu_console_is_graphic(con) ? "Graphic" : "Text",
559142ca628SMarc-André Lureau "head", qemu_console_get_head(con),
560142ca628SMarc-André Lureau "width", qemu_console_get_width(con, 0),
561142ca628SMarc-André Lureau "height", qemu_console_get_height(con, 0),
562142ca628SMarc-André Lureau "device-address", device_addr,
563439e0164SMarc-André Lureau "interfaces", interfaces,
564142ca628SMarc-André Lureau NULL);
565142ca628SMarc-André Lureau g_object_connect(ddc->iface,
566142ca628SMarc-André Lureau "swapped-signal::handle-register-listener",
567142ca628SMarc-André Lureau dbus_console_register_listener, ddc,
568142ca628SMarc-André Lureau "swapped-signal::handle-set-uiinfo",
569142ca628SMarc-André Lureau dbus_console_set_ui_info, ddc,
570142ca628SMarc-André Lureau NULL);
571142ca628SMarc-André Lureau g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
572142ca628SMarc-André Lureau G_DBUS_INTERFACE_SKELETON(ddc->iface));
573142ca628SMarc-André Lureau
574142ca628SMarc-André Lureau ddc->kbd = qkbd_state_init(con);
575142ca628SMarc-André Lureau ddc->iface_kbd = qemu_dbus_display1_keyboard_skeleton_new();
576142ca628SMarc-André Lureau qemu_add_led_event_handler(dbus_kbd_qemu_leds_updated, ddc);
577142ca628SMarc-André Lureau g_object_connect(ddc->iface_kbd,
578142ca628SMarc-André Lureau "swapped-signal::handle-press", dbus_kbd_press, ddc,
579142ca628SMarc-André Lureau "swapped-signal::handle-release", dbus_kbd_release, 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_kbd));
583142ca628SMarc-André Lureau
584142ca628SMarc-André Lureau ddc->iface_mouse = qemu_dbus_display1_mouse_skeleton_new();
585142ca628SMarc-André Lureau g_object_connect(ddc->iface_mouse,
586142ca628SMarc-André Lureau "swapped-signal::handle-set-abs-position", dbus_mouse_set_pos, ddc,
587142ca628SMarc-André Lureau "swapped-signal::handle-rel-motion", dbus_mouse_rel_motion, ddc,
588142ca628SMarc-André Lureau "swapped-signal::handle-press", dbus_mouse_press, ddc,
589142ca628SMarc-André Lureau "swapped-signal::handle-release", dbus_mouse_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_mouse));
593142ca628SMarc-André Lureau
594de9f844cSBilal Elmoussaoui ddc->iface_touch = qemu_dbus_display1_multi_touch_skeleton_new();
595de9f844cSBilal Elmoussaoui g_object_connect(ddc->iface_touch,
596de9f844cSBilal Elmoussaoui "swapped-signal::handle-send-event", dbus_touch_send_event, ddc,
597de9f844cSBilal Elmoussaoui NULL);
598de9f844cSBilal Elmoussaoui qemu_dbus_display1_multi_touch_set_max_slots(ddc->iface_touch,
599de9f844cSBilal Elmoussaoui INPUT_EVENT_SLOTS_MAX);
600de9f844cSBilal Elmoussaoui g_dbus_object_skeleton_add_interface(G_DBUS_OBJECT_SKELETON(ddc),
601de9f844cSBilal Elmoussaoui G_DBUS_INTERFACE_SKELETON(ddc->iface_touch));
602de9f844cSBilal Elmoussaoui
603de9f844cSBilal Elmoussaoui for (i = 0; i < INPUT_EVENT_SLOTS_MAX; i++) {
604de9f844cSBilal Elmoussaoui struct touch_slot *slot = &touch_slots[i];
605de9f844cSBilal Elmoussaoui slot->tracking_id = -1;
606de9f844cSBilal Elmoussaoui }
607de9f844cSBilal Elmoussaoui
608142ca628SMarc-André Lureau register_displaychangelistener(&ddc->dcl);
609142ca628SMarc-André Lureau ddc->mouse_mode_notifier.notify = dbus_mouse_mode_change;
610142ca628SMarc-André Lureau qemu_add_mouse_mode_change_notifier(&ddc->mouse_mode_notifier);
611eb9062d4SMarc-André Lureau dbus_mouse_update_is_absolute(ddc);
612142ca628SMarc-André Lureau
613142ca628SMarc-André Lureau return ddc;
614142ca628SMarc-André Lureau }
615