[at-spi2-core] Support mutter remote desktop interface for key/mouse events
- From: Mike Gorse <mgorse src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [at-spi2-core] Support mutter remote desktop interface for key/mouse events
- Date: Mon, 5 Aug 2019 20:22:31 +0000 (UTC)
commit 673340d60a0bf7b97863985f02854b943ee009bb
Author: Mike Gorse <mgorse alum wpi edu>
Date: Mon Aug 5 14:31:58 2019 -0500
Support mutter remote desktop interface for key/mouse events
Mutter now has a remote desktop interface with methods to synthesize keyboard
and mouse events. This functionality has not been available through AT-SPI on
wayland since it uses X-specific functions.
Also add atspi_set_reference_window.
Probably a work in progress; doesn't appear to be behaving as intended.
Also requires that introspection be enabled on gnome-shell. Ie,
gsettings set org.gnome.shell introspect true
https://bugzilla.gnome.org/show_bug.cgi?id=709999
https://gitlab.gnome.org/GNOME/at-spi2-core/issues/14
atspi/atspi-mutter-private.h | 36 ++++
atspi/atspi-mutter.c | 407 +++++++++++++++++++++++++++++++++++++
atspi/atspi-private.h | 1 +
atspi/atspi-registry.c | 41 ++++
atspi/atspi-registry.h | 2 +
atspi/meson.build | 1 +
doc/libatspi/libatspi-sections.txt | 1 +
7 files changed, 489 insertions(+)
---
diff --git a/atspi/atspi-mutter-private.h b/atspi/atspi-mutter-private.h
new file mode 100644
index 0000000..7d09c57
--- /dev/null
+++ b/atspi/atspi-mutter-private.h
@@ -0,0 +1,36 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2019 SUSE LLC.
+ *
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _ATSPI_MUTTER_H_
+#define _ATSPI_MUTTER_H_
+
+G_BEGIN_DECLS
+
+gboolean _atspi_mutter_generate_keyboard_event (glong keyval, const gchar *keystring, AtspiKeySynthType
synth_type, GError **error);
+
+gboolean _atspi_mutter_generate_mouse_event (glong x, glong y, const gchar *name, GError **error);
+
+void _atspi_mutter_set_reference_window (AtspiAccessible *accessible);
+G_END_DECLS
+
+#endif /* _ATSPI_MUTTER_H_ */
diff --git a/atspi/atspi-mutter.c b/atspi/atspi-mutter.c
new file mode 100644
index 0000000..8010680
--- /dev/null
+++ b/atspi/atspi-mutter.c
@@ -0,0 +1,407 @@
+/*
+ * AT-SPI - Assistive Technology Service Provider Interface
+ * (Gnome Accessibility Project; http://developer.gnome.org/projects/gap)
+ *
+ * Copyright 2019 SUSE LLC.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* atspi-mutter.c: support for keyboard/mouse handling using the
+ * mutter/gnome-shell remote desktop interfaces
+ *
+ * This functionality is analogous to the X11-based code in
+ * device-event-controller-x11.c. Placing the code here, rather than in the
+ * registry daemon, allows the relevant dbus calls to come directly from the
+ * AT-SPI client, rather than at-spi2-registryd being an intermediary,
+ * which may be useful if a distribution wishes to lock down access to the
+ * remote desktop interfaces.
+ */
+
+#include "atspi-private.h"
+
+typedef struct
+{
+ DBusConnection *bus;
+ const char *rd_session_id;
+ const char *rd_session_path;
+ const char *sc_session_id;
+ const char *sc_session_path;
+ const char *sc_stream_path;
+ dbus_uint64_t window_id;
+ gboolean window_id_is_explicit;
+} ATSPI_MUTTER_DATA;
+
+static ATSPI_MUTTER_DATA data;
+
+#define MUTTER_REMOTE_DESKTOP_BUS_NAME "org.gnome.Mutter.RemoteDesktop"
+#define MUTTER_REMOTE_DESKTOP_OBJECT_PATH "/org/gnome/Mutter/RemoteDesktop"
+#define MUTTER_REMOTE_DESKTOP_INTERFACE "org.gnome.Mutter.RemoteDesktop"
+#define MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE "org.gnome.Mutter.RemoteDesktop.Session"
+#define MUTTER_SCREEN_CAST_BUS_NAME "org.gnome.Mutter.ScreenCast"
+#define MUTTER_SCREEN_CAST_OBJECT_PATH "/org/gnome/Mutter/ScreenCast"
+#define MUTTER_SCREEN_CAST_INTERFACE "org.gnome.Mutter.ScreenCast"
+#define MUTTER_SCREEN_CAST_SESSION_INTERFACE "org.gnome.Mutter.ScreenCast.Session"
+
+/* TODO: consider porting this to gdbus */
+
+static void
+ensure_bus ()
+{
+ if (data.bus)
+ return;
+ data.bus = dbus_bus_get (DBUS_BUS_SESSION, NULL);
+}
+
+static gboolean
+ensure_rd_session_path (GError **error)
+{
+ char *session_path;
+ DBusError d_error;
+
+ if (data.rd_session_path)
+ return (data.rd_session_path[0] != '\0');
+ ensure_bus ();
+
+ dbus_error_init (&d_error);
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, MUTTER_REMOTE_DESKTOP_OBJECT_PATH,
MUTTER_REMOTE_DESKTOP_INTERFACE, "CreateSession", &d_error, "=>o", &session_path);
+
+ data.rd_session_path = g_strdup (session_path);
+ if (!data.rd_session_path[0])
+ return FALSE;
+
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "Start", &d_error, "");
+ return TRUE;
+}
+
+static dbus_uint64_t
+get_window_id (const char *name)
+{
+ DBusMessage *message, *reply;
+ DBusError d_error;
+ dbus_uint64_t window_id;
+ DBusMessageIter iter, iter_array, iter_dict, iter_sub_array, iter_sub_dict;
+ const char *prop_name;
+ const char *cur_name;
+ dbus_bool_t cur_focus;
+ gboolean have_focus;
+
+ dbus_error_init (&d_error);
+ message = dbus_message_new_method_call (MUTTER_REMOTE_DESKTOP_BUS_NAME, "/org/gnome/Shell/Introspect",
"org.gnome.Shell.Introspect", "GetWindows");
+ reply = dbus_connection_send_with_reply_and_block (data.bus, message, -1, &d_error);
+ dbus_message_unref (message);
+
+ if (!reply)
+ return FALSE;
+ if (strcmp (dbus_message_get_signature (reply), "a{ta{sv}}") != 0)
+ {
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_array);
+ while (dbus_message_iter_get_arg_type (&iter_array) != DBUS_TYPE_INVALID)
+ {
+ dbus_message_iter_recurse (&iter_array, &iter_dict);
+ dbus_message_iter_get_basic (&iter_dict, &window_id);
+ dbus_message_iter_next (&iter_dict);
+ dbus_message_iter_recurse (&iter_dict, &iter_sub_array);
+ cur_name = NULL;
+ have_focus = FALSE;
+ while (dbus_message_iter_get_arg_type (&iter_sub_array) != DBUS_TYPE_INVALID)
+ {
+ dbus_message_iter_recurse (&iter_sub_array, &iter_sub_dict);
+ dbus_message_iter_get_basic (&iter_sub_dict, &prop_name);
+ if (!strcmp (prop_name, "wm-class"))
+ {
+ DBusMessageIter iter_variant;
+ dbus_message_iter_next (&iter_sub_dict);
+ dbus_message_iter_recurse (&iter_sub_dict, &iter_variant);
+ dbus_message_iter_get_basic (&iter_variant, &cur_name);
+ }
+ if (!strcmp (prop_name, "has-focus"))
+ {
+ DBusMessageIter iter_variant;
+ dbus_message_iter_next (&iter_sub_dict);
+ dbus_message_iter_recurse (&iter_sub_dict, &iter_variant);
+ dbus_message_iter_get_basic (&iter_variant, &cur_focus);
+ have_focus = TRUE;
+ }
+ if (cur_name && have_focus)
+ {
+ if ((name && !strcmp (name, cur_name)) || cur_focus)
+ {
+ dbus_message_unref (reply);
+ return window_id;
+ }
+ break;
+ }
+ dbus_message_iter_next (&iter_sub_array);
+ }
+ dbus_message_iter_next (&iter_array);
+ }
+
+ dbus_message_unref (reply);
+ return 0;
+}
+
+static gboolean
+ensure_rd_session_id (GError **error)
+{
+ DBusMessage *message, *reply;
+ DBusError d_error;
+ const char *interface = "org.gnome.Mutter.RemoteDesktop.Session";
+ const char *prop_name = "SessionId";
+ DBusMessageIter iter, iter_variant;
+ const char *session_id;
+
+ if (data.rd_session_id)
+ return (data.rd_session_id[0] != '\0');
+
+ if (!ensure_rd_session_path (error))
+ return FALSE;
+
+ message = dbus_message_new_method_call (MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
"org.freedesktop.DBus.Properties", "Get");
+ dbus_message_append_args (message, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &prop_name,
DBUS_TYPE_INVALID);
+
+ dbus_error_init (&d_error);
+ reply = dbus_connection_send_with_reply_and_block (data.bus, message, -1, &d_error);
+ dbus_message_unref (message);
+ if (!reply)
+ return FALSE;
+ if (strcmp (dbus_message_get_signature (reply), "v") != 0)
+ {
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+ dbus_message_iter_init (reply, &iter);
+ dbus_message_iter_recurse (&iter, &iter_variant);
+ dbus_message_iter_get_basic (&iter_variant, &session_id);
+ data.rd_session_id = g_strdup (session_id);
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+static gboolean
+ensure_sc_session (GError **error)
+{
+ DBusMessage *message, *reply;
+ DBusError d_error;
+ DBusMessageIter iter, iter_array, iter_dict_entry, iter_variant;
+ const char *prop_name = "remote-desktop-session-id";
+ const char *sc_session_path;
+
+ if (!ensure_rd_session_id (error))
+ return FALSE;
+
+ if (data.sc_session_path)
+ return (data.sc_session_path[0] != '\0');
+
+ message = dbus_message_new_method_call (MUTTER_SCREEN_CAST_BUS_NAME, MUTTER_SCREEN_CAST_OBJECT_PATH,
MUTTER_SCREEN_CAST_INTERFACE, "CreateSession");
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_array);
+ dbus_message_iter_open_container (&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry);
+ dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop_name);
+ dbus_message_iter_open_container (&iter_dict_entry, DBUS_TYPE_VARIANT, "s", &iter_variant);
+ dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_STRING, &data.rd_session_id);
+ dbus_message_iter_close_container (&iter_dict_entry, &iter_variant);
+ dbus_message_iter_close_container (&iter_array, &iter_dict_entry);
+ dbus_message_iter_close_container (&iter, &iter_array);
+ dbus_error_init (&d_error);
+ reply = dbus_connection_send_with_reply_and_block (data.bus, message, -1, &d_error);
+ dbus_message_unref (message);
+ if (!reply)
+ return FALSE;
+ if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &sc_session_path, DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ data.sc_session_path = g_strdup (sc_session_path);
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+static gboolean
+init_mutter (gboolean need_window, GError **error)
+{
+ dbus_uint64_t window_id;
+ const char *prop_name = "window-id";
+ DBusError d_error;
+ DBusMessageIter iter, iter_array, iter_dict_entry, iter_variant;
+ DBusMessage *message, *reply;
+ const char *sc_stream_path;
+
+ if (!ensure_rd_session_path (error))
+ return FALSE;
+
+ if (!need_window)
+ return TRUE;
+
+ window_id = (data.window_id_is_explicit) ? data.window_id
+ : get_window_id (NULL);
+ if (!window_id)
+ return FALSE;
+
+ if (!ensure_sc_session (error))
+ return FALSE;
+
+ if (window_id == data.window_id)
+ return TRUE;
+
+ message = dbus_message_new_method_call (MUTTER_SCREEN_CAST_BUS_NAME, data.sc_session_path,
MUTTER_SCREEN_CAST_SESSION_INTERFACE, "RecordWindow");
+ dbus_message_iter_init_append (message, &iter);
+ dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "{sv}", &iter_array);
+ dbus_message_iter_open_container (&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict_entry);
+ dbus_message_iter_append_basic (&iter_dict_entry, DBUS_TYPE_STRING, &prop_name);
+ dbus_message_iter_open_container (&iter_dict_entry, DBUS_TYPE_VARIANT, "t", &iter_variant);
+ dbus_message_iter_append_basic (&iter_variant, DBUS_TYPE_UINT64, &window_id);
+ dbus_message_iter_close_container (&iter_dict_entry, &iter_variant);
+ dbus_message_iter_close_container (&iter_array, &iter_dict_entry);
+ dbus_message_iter_close_container (&iter, &iter_array);
+ dbus_error_init (&d_error);
+ reply = dbus_connection_send_with_reply_and_block (data.bus, message, -1, &d_error);
+ dbus_message_unref (message);
+ if (!reply)
+ return FALSE;
+ if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &sc_stream_path, DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ data.sc_stream_path = g_strdup (sc_stream_path);
+ dbus_message_unref (reply);
+ data.window_id = window_id;
+ return TRUE;
+}
+
+gboolean
+_atspi_mutter_generate_keyboard_event (glong keyval,
+ const gchar *keystring,
+ AtspiKeySynthType synth_type, GError **error)
+{
+ DBusError d_error;
+ dbus_uint32_t d_keyval = keyval;
+
+ if (!init_mutter (FALSE, error))
+ return FALSE;
+
+ dbus_error_init (&d_error);
+ switch (synth_type)
+ {
+ case ATSPI_KEY_PRESS:
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyKeyboardKeycode", &d_error, "ub", d_keyval, TRUE);
+ break;
+ case ATSPI_KEY_RELEASE:
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyKeyboardKeycode", &d_error, "ub", d_keyval, FALSE);
+ break;
+ case ATSPI_KEY_PRESSRELEASE:
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyKeyboardKeycode", &d_error, "ub", d_keyval, TRUE);
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyKeyboardKeycode", &d_error, "ub", d_keyval, FALSE);
+ break;
+ case ATSPI_KEY_SYM:
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyKeyboardKeysyme", &d_error, "ub", d_keyval, TRUE);
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyKeyboardKeysyme", &d_error, "ub", d_keyval, FALSE);
+ break;
+ default:
+ /* TODO: set error */
+ g_warning ("%s: unsupported type", __func__);
+ return FALSE;
+ }
+ if (dbus_error_is_set (&d_error))
+ {
+ g_warning ("GenerateKeyboardEvent failed: %s", d_error.message);
+ dbus_error_free (&d_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean
+_atspi_mutter_generate_mouse_event (glong x, glong y, const gchar *name, GError **error)
+{
+ gint button = 0;
+ double d_x = x, d_y = y;
+ DBusError d_error;
+
+ if (!init_mutter (TRUE, error))
+ return FALSE;
+
+ dbus_error_init (&d_error);
+ switch (name[0])
+ {
+ case 'b':
+ button = name[1] - '1';
+ if (button < 0 || button > 4)
+ return FALSE;
+ if (x != -1 && y != -1)
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerMotionAbsolute", &d_error, "sdd", data.sc_stream_path,
d_x, d_y);
+ switch (name[2])
+ {
+ case 'p':
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, TRUE);
+ break;
+ case 'r':
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, FALSE);
+ break;
+ case 'c':
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, TRUE);
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, FALSE);
+ break;
+ case 'd':
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, TRUE);
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, FALSE);
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, TRUE);
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerButton", &d_error, "ib", button, FALSE);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+ case 'a': /* absolute motion */
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerMotionAbsolute", &d_error, "sdd", data.sc_stream_path,
d_x, d_y);
+ break;
+ case 'r': /* relative */
+ dbind_method_call_reentrant (data.bus, MUTTER_REMOTE_DESKTOP_BUS_NAME, data.rd_session_path,
MUTTER_REMOTE_DESKTOP_SESSION_INTERFACE, "NotifyPointerMotionRelative", &d_error, "dd", d_x, d_y);
+ break;
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+_atspi_mutter_set_reference_window (AtspiAccessible *accessible)
+{
+ if (accessible)
+ {
+ AtspiRole role = atspi_accessible_get_role (accessible, NULL);
+ gchar *name;
+ g_return_if_fail (role != ATSPI_ROLE_APPLICATION);
+ name = atspi_accessible_get_name (accessible, NULL);
+ data.window_id = get_window_id (name);
+ data.window_id_is_explicit = TRUE;
+ }
+
+ else
+ {
+ data.window_id_is_explicit = FALSE;
+ }
+}
diff --git a/atspi/atspi-private.h b/atspi/atspi-private.h
index 2cf5693..fc7727c 100644
--- a/atspi/atspi-private.h
+++ b/atspi/atspi-private.h
@@ -30,6 +30,7 @@
#include "atspi-event-listener-private.h"
#include "atspi-matchrule-private.h"
#include "atspi-misc-private.h"
+#include "atspi-mutter-private.h"
#include "glib/gi18n.h"
diff --git a/atspi/atspi-registry.c b/atspi/atspi-registry.c
index 76b1926..50cce98 100644
--- a/atspi/atspi-registry.c
+++ b/atspi/atspi-registry.c
@@ -424,6 +424,12 @@ atspi_deregister_device_event_listener (AtspiDeviceListener *listener,
return TRUE;
}
+static gboolean
+using_mutter ()
+{
+ return (g_getenv ("WAYLAND_DISPLAY") != NULL);
+}
+
/**
* atspi_generate_keyboard_event:
* @keyval: a #gint indicating the keycode or keysym or modifier mask of the
@@ -456,6 +462,12 @@ atspi_generate_keyboard_event (glong keyval,
dbus_int32_t d_keyval = keyval;
DBusError d_error;
+ if (using_mutter ())
+ {
+ if (_atspi_mutter_generate_keyboard_event (keyval, keystring, synth_type, error))
+ return TRUE;
+ }
+
dbus_error_init (&d_error);
if (!keystring)
keystring = "";
@@ -492,6 +504,14 @@ atspi_generate_mouse_event (glong x, glong y, const gchar *name, GError **error)
dbus_int32_t d_x = x, d_y = y;
DBusError d_error;
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ if (using_mutter ())
+ {
+ if (_atspi_mutter_generate_mouse_event (x, y, name, error))
+ return TRUE;
+ }
+
dbus_error_init (&d_error);
dbind_method_call_reentrant (_atspi_bus(), atspi_bus_registry,
atspi_path_dec, atspi_interface_dec,
@@ -506,6 +526,27 @@ atspi_generate_mouse_event (glong x, glong y, const gchar *name, GError **error)
return TRUE;
}
+/**
+ * atspi_set_reference_window:
+ *
+ * @accessible: the #AtspiAccessible corresponding to the window to select.
+ * should be a top-level window with a role of
+ * ATSPI_ROLE_APPLICATION.
+ *
+ * Sets the reference window that will be used when atspi_generate_mouse_event
+ * is called. Coordinates will be assumed to be relative to this window. This
+ * is needed because, due to Wayland's security model, it is not currently
+ * possible to retrieve global coordinates.
+ * If NULL is passed, then AT-SPI will use the window that has focus at the
+ * time that atspi_generate_mouse_event is called.
+ */
+void
+atspi_set_reference_window (AtspiAccessible *accessible)
+{
+ if (using_mutter ())
+ _atspi_mutter_set_reference_window (accessible);
+}
+
AtspiKeyDefinition *
atspi_key_definition_copy (AtspiKeyDefinition *src)
{
diff --git a/atspi/atspi-registry.h b/atspi/atspi-registry.h
index 18e32a6..dd787d4 100644
--- a/atspi/atspi-registry.h
+++ b/atspi/atspi-registry.h
@@ -71,6 +71,8 @@ atspi_generate_keyboard_event (glong keyval,
gboolean
atspi_generate_mouse_event (glong x, glong y, const gchar *name, GError **error);
+void
+atspi_set_reference_window (AtspiAccessible *accessible);
G_END_DECLS
#endif /* _ATSPI_REGISTRY_H_ */
diff --git a/atspi/meson.build b/atspi/meson.build
index 14c771b..8a2ca27 100644
--- a/atspi/meson.build
+++ b/atspi/meson.build
@@ -13,6 +13,7 @@ atspi_sources = [
'atspi-hypertext.c',
'atspi-image.c',
'atspi-matchrule.c',
+ 'atspi-mutter.c',
'atspi-misc.c',
'atspi-object.c',
'atspi-registry.c',
diff --git a/doc/libatspi/libatspi-sections.txt b/doc/libatspi/libatspi-sections.txt
index f4a0eec..d7bfc10 100644
--- a/doc/libatspi/libatspi-sections.txt
+++ b/doc/libatspi/libatspi-sections.txt
@@ -504,6 +504,7 @@ atspi_register_device_event_listener
atspi_deregister_device_event_listener
atspi_generate_keyboard_event
atspi_generate_mouse_event
+atspi_set_reference_window
</SECTION>
<SECTION>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]