[at-spi2-core] Support mutter remote desktop interface for key/mouse events



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]