forked from AuroraMiddleware/gtk
30210c7087
We are doing too much work during the construction phase of the AT-SPI backend for GtkATContext. Instead of having the AtSpiContext register itself at construction time, let's add explicit realize and unrealize operations, and connect the ATContext realization to the rooting operation of a GtkWidget.
690 lines
22 KiB
C
690 lines
22 KiB
C
/* gtkatspiroot.c: AT-SPI root object
|
|
*
|
|
* Copyright 2020 GNOME Foundation
|
|
*
|
|
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gtkatspirootprivate.h"
|
|
|
|
#include "gtkatspicontextprivate.h"
|
|
#include "gtkaccessibleprivate.h"
|
|
#include "gtkatspiprivate.h"
|
|
#include "gtkatspiutilsprivate.h"
|
|
|
|
#include "gtkdebug.h"
|
|
#include "gtkwindow.h"
|
|
|
|
#include "a11y/atspi/atspi-accessible.h"
|
|
#include "a11y/atspi/atspi-application.h"
|
|
|
|
#include <locale.h>
|
|
|
|
#include <glib/gi18n-lib.h>
|
|
#include <gio/gio.h>
|
|
|
|
#define ATSPI_VERSION "2.1"
|
|
|
|
#define ATSPI_PATH_PREFIX "/org/a11y/atspi"
|
|
#define ATSPI_ROOT_PATH ATSPI_PATH_PREFIX "/accessible/root"
|
|
#define ATSPI_CACHE_PATH ATSPI_PATH_PREFIX "/cache"
|
|
|
|
struct _GtkAtSpiRoot
|
|
{
|
|
GObject parent_instance;
|
|
|
|
char *bus_address;
|
|
GDBusConnection *connection;
|
|
|
|
const char *root_path;
|
|
|
|
const char *toolkit_name;
|
|
const char *version;
|
|
const char *atspi_version;
|
|
|
|
char *desktop_name;
|
|
char *desktop_path;
|
|
|
|
gint32 application_id;
|
|
guint register_id;
|
|
|
|
GtkAtSpiCache *cache;
|
|
|
|
GListModel *toplevels;
|
|
};
|
|
|
|
enum
|
|
{
|
|
PROP_BUS_ADDRESS = 1,
|
|
|
|
N_PROPS
|
|
};
|
|
|
|
static GParamSpec *obj_props[N_PROPS];
|
|
|
|
G_DEFINE_TYPE (GtkAtSpiRoot, gtk_at_spi_root, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
gtk_at_spi_root_finalize (GObject *gobject)
|
|
{
|
|
GtkAtSpiRoot *self = GTK_AT_SPI_ROOT (gobject);
|
|
|
|
g_clear_handle_id (&self->register_id, g_source_remove);
|
|
|
|
g_free (self->bus_address);
|
|
g_free (self->desktop_name);
|
|
g_free (self->desktop_path);
|
|
|
|
G_OBJECT_CLASS (gtk_at_spi_root_parent_class)->dispose (gobject);
|
|
}
|
|
|
|
static void
|
|
gtk_at_spi_root_dispose (GObject *gobject)
|
|
{
|
|
GtkAtSpiRoot *self = GTK_AT_SPI_ROOT (gobject);
|
|
|
|
g_clear_object (&self->cache);
|
|
g_clear_object (&self->connection);
|
|
|
|
G_OBJECT_CLASS (gtk_at_spi_root_parent_class)->dispose (gobject);
|
|
}
|
|
|
|
static void
|
|
gtk_at_spi_root_set_property (GObject *gobject,
|
|
guint prop_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkAtSpiRoot *self = GTK_AT_SPI_ROOT (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_BUS_ADDRESS:
|
|
self->bus_address = g_value_dup_string (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_at_spi_root_get_property (GObject *gobject,
|
|
guint prop_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GtkAtSpiRoot *self = GTK_AT_SPI_ROOT (gobject);
|
|
|
|
switch (prop_id)
|
|
{
|
|
case PROP_BUS_ADDRESS:
|
|
g_value_set_string (value, self->bus_address);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void
|
|
handle_application_method (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *object_path,
|
|
const gchar *interface_name,
|
|
const gchar *method_name,
|
|
GVariant *parameters,
|
|
GDBusMethodInvocation *invocation,
|
|
gpointer user_data)
|
|
{
|
|
if (g_strcmp0 (method_name, "GetLocale") == 0)
|
|
{
|
|
guint lctype;
|
|
const char *locale;
|
|
|
|
int types[] = {
|
|
LC_MESSAGES, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME
|
|
};
|
|
|
|
g_variant_get (parameters, "(u)", &lctype);
|
|
if (lctype >= G_N_ELEMENTS (types))
|
|
{
|
|
g_dbus_method_invocation_return_error (invocation,
|
|
G_IO_ERROR,
|
|
G_IO_ERROR_INVALID_ARGUMENT,
|
|
"Not a known locale facet: %u", lctype);
|
|
return;
|
|
}
|
|
|
|
locale = setlocale (types[lctype], NULL);
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", locale));
|
|
}
|
|
}
|
|
|
|
static GVariant *
|
|
handle_application_get_property (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *object_path,
|
|
const gchar *interface_name,
|
|
const gchar *property_name,
|
|
GError **error,
|
|
gpointer user_data)
|
|
{
|
|
GtkAtSpiRoot *self = user_data;
|
|
GVariant *res = NULL;
|
|
|
|
if (g_strcmp0 (property_name, "Id") == 0)
|
|
res = g_variant_new_int32 (self->application_id);
|
|
else if (g_strcmp0 (property_name, "ToolkitName") == 0)
|
|
res = g_variant_new_string (self->toolkit_name);
|
|
else if (g_strcmp0 (property_name, "Version") == 0)
|
|
res = g_variant_new_string (self->version);
|
|
else if (g_strcmp0 (property_name, "AtspiVersion") == 0)
|
|
res = g_variant_new_string (self->atspi_version);
|
|
else
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
"Unknown property '%s'", property_name);
|
|
|
|
return res;
|
|
}
|
|
|
|
static gboolean
|
|
handle_application_set_property (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *object_path,
|
|
const gchar *interface_name,
|
|
const gchar *property_name,
|
|
GVariant *value,
|
|
GError **error,
|
|
gpointer user_data)
|
|
{
|
|
GtkAtSpiRoot *self = user_data;
|
|
|
|
if (g_strcmp0 (property_name, "Id") == 0)
|
|
{
|
|
g_variant_get (value, "i", &(self->application_id));
|
|
}
|
|
else
|
|
{
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
"Invalid property '%s'", property_name);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
handle_accessible_method (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *object_path,
|
|
const gchar *interface_name,
|
|
const gchar *method_name,
|
|
GVariant *parameters,
|
|
GDBusMethodInvocation *invocation,
|
|
gpointer user_data)
|
|
{
|
|
GtkAtSpiRoot *self = user_data;
|
|
|
|
if (g_strcmp0 (method_name, "GetRole") == 0)
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", ATSPI_ROLE_APPLICATION));
|
|
else if (g_strcmp0 (method_name, "GetRoleName") == 0)
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", "application"));
|
|
else if (g_strcmp0 (method_name, "GetLocalizedRoleName") == 0)
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", C_("accessibility", "application")));
|
|
else if (g_strcmp0 (method_name, "GetState") == 0)
|
|
{
|
|
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(au)"));
|
|
|
|
g_variant_builder_open (&builder, G_VARIANT_TYPE ("au"));
|
|
g_variant_builder_add (&builder, "u", 0);
|
|
g_variant_builder_add (&builder, "u", 0);
|
|
g_variant_builder_close (&builder);
|
|
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_builder_end (&builder));
|
|
}
|
|
else if (g_strcmp0 (method_name, "GetAttributes") == 0)
|
|
{
|
|
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("(a{ss})"));
|
|
|
|
g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{ss}"));
|
|
g_variant_builder_add (&builder, "{ss}", "toolkit", "GTK");
|
|
g_variant_builder_close (&builder);
|
|
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_builder_end (&builder));
|
|
}
|
|
else if (g_strcmp0 (method_name, "GetApplication") == 0)
|
|
{
|
|
g_dbus_method_invocation_return_value (invocation,
|
|
g_variant_new ("((so))",
|
|
self->desktop_name,
|
|
self->desktop_path));
|
|
}
|
|
else if (g_strcmp0 (method_name, "GetChildAtIndex") == 0)
|
|
{
|
|
int idx, real_idx = 0;
|
|
|
|
g_variant_get (parameters, "(i)", &idx);
|
|
|
|
GtkWidget *window = NULL;
|
|
guint n_toplevels = g_list_model_get_n_items (self->toplevels);
|
|
for (guint i = 0; i < n_toplevels; i++)
|
|
{
|
|
window = g_list_model_get_item (self->toplevels, i);
|
|
|
|
g_object_unref (window);
|
|
|
|
if (!gtk_widget_get_visible (window))
|
|
continue;
|
|
|
|
if (real_idx == idx)
|
|
break;
|
|
|
|
real_idx += 1;
|
|
}
|
|
|
|
if (window == NULL)
|
|
return;
|
|
|
|
GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (window));
|
|
|
|
const char *name = g_dbus_connection_get_unique_name (self->connection);
|
|
const char *path = gtk_at_spi_context_get_context_path (GTK_AT_SPI_CONTEXT (context));
|
|
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("((so))", name, path));
|
|
}
|
|
else if (g_strcmp0 (method_name, "GetChildren") == 0)
|
|
{
|
|
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(so)"));
|
|
|
|
guint n_toplevels = g_list_model_get_n_items (self->toplevels);
|
|
for (guint i = 0; i < n_toplevels; i++)
|
|
{
|
|
GtkWidget *window = g_list_model_get_item (self->toplevels, i);
|
|
|
|
g_object_unref (window);
|
|
|
|
if (!gtk_widget_get_visible (window))
|
|
continue;
|
|
|
|
GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (window));
|
|
const char *name = g_dbus_connection_get_unique_name (self->connection);
|
|
const char *path = gtk_at_spi_context_get_context_path (GTK_AT_SPI_CONTEXT (context));
|
|
|
|
g_variant_builder_add (&builder, "(so)", name, path);
|
|
}
|
|
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(so))", &builder));
|
|
}
|
|
else if (g_strcmp0 (method_name, "GetIndexInParent") == 0)
|
|
{
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(i)", -1));
|
|
}
|
|
else if (g_strcmp0 (method_name, "GetRelationSet") == 0)
|
|
{
|
|
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(ua(so))"));
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(ua(so)))", &builder));
|
|
}
|
|
else if (g_strcmp0 (method_name, "GetInterfaces") == 0)
|
|
{
|
|
GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("as"));
|
|
|
|
g_variant_builder_add (&builder, "s", "org.a11y.atspi.Accessible");
|
|
g_variant_builder_add (&builder, "s", "org.a11y.atspi.Application");
|
|
g_dbus_method_invocation_return_value (invocation, g_variant_new ("(as)", &builder));
|
|
}
|
|
}
|
|
|
|
static GVariant *
|
|
handle_accessible_get_property (GDBusConnection *connection,
|
|
const gchar *sender,
|
|
const gchar *object_path,
|
|
const gchar *interface_name,
|
|
const gchar *property_name,
|
|
GError **error,
|
|
gpointer user_data)
|
|
{
|
|
GtkAtSpiRoot *self = user_data;
|
|
GVariant *res = NULL;
|
|
|
|
if (g_strcmp0 (property_name, "Name") == 0)
|
|
res = g_variant_new_string (g_get_prgname () ? g_get_prgname () : "Unnamed");
|
|
else if (g_strcmp0 (property_name, "Description") == 0)
|
|
res = g_variant_new_string (g_get_application_name () ? g_get_application_name () : "No description");
|
|
else if (g_strcmp0 (property_name, "Locale") == 0)
|
|
res = g_variant_new_string (setlocale (LC_MESSAGES, NULL));
|
|
else if (g_strcmp0 (property_name, "AccessibleId") == 0)
|
|
res = g_variant_new_string ("");
|
|
else if (g_strcmp0 (property_name, "Parent") == 0)
|
|
res = g_variant_new ("(so)", self->desktop_name, self->desktop_path);
|
|
else if (g_strcmp0 (property_name, "ChildCount") == 0)
|
|
{
|
|
guint n_toplevels = g_list_model_get_n_items (self->toplevels);
|
|
int n_children = 0;
|
|
|
|
for (guint i = 0; i < n_toplevels; i++)
|
|
{
|
|
GtkWidget *window = g_list_model_get_item (self->toplevels, i);
|
|
|
|
if (gtk_widget_get_visible (window))
|
|
n_children += 1;
|
|
|
|
g_object_unref (window);
|
|
}
|
|
|
|
res = g_variant_new_int32 (n_children);
|
|
}
|
|
else
|
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
"Unknown property '%s'", property_name);
|
|
|
|
return res;
|
|
}
|
|
|
|
static const GDBusInterfaceVTable root_application_vtable = {
|
|
handle_application_method,
|
|
handle_application_get_property,
|
|
handle_application_set_property,
|
|
};
|
|
|
|
static const GDBusInterfaceVTable root_accessible_vtable = {
|
|
handle_accessible_method,
|
|
handle_accessible_get_property,
|
|
NULL,
|
|
};
|
|
|
|
void
|
|
gtk_at_spi_root_child_changed (GtkAtSpiRoot *self,
|
|
GtkAccessibleChildChange change,
|
|
GtkAccessible *child)
|
|
{
|
|
guint n, i;
|
|
int idx = 0;
|
|
GVariant *window_ref;
|
|
GtkAccessibleChildState state;
|
|
|
|
if (!self->toplevels)
|
|
return;
|
|
|
|
for (i = 0, n = g_list_model_get_n_items (self->toplevels); i < n; i++)
|
|
{
|
|
GtkAccessible *item = g_list_model_get_item (self->toplevels, i);
|
|
|
|
g_object_unref (item);
|
|
|
|
if (item == child)
|
|
break;
|
|
|
|
if (!gtk_accessible_should_present (item))
|
|
continue;
|
|
|
|
idx++;
|
|
}
|
|
|
|
if (child == NULL)
|
|
{
|
|
window_ref = gtk_at_spi_null_ref ();
|
|
}
|
|
else
|
|
{
|
|
GtkATContext *context = gtk_accessible_get_at_context (child);
|
|
|
|
window_ref = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (context));
|
|
}
|
|
|
|
switch (change)
|
|
{
|
|
case GTK_ACCESSIBLE_CHILD_CHANGE_ADDED:
|
|
state = GTK_ACCESSIBLE_CHILD_STATE_ADDED;
|
|
break;
|
|
case GTK_ACCESSIBLE_CHILD_CHANGE_REMOVED:
|
|
state = GTK_ACCESSIBLE_CHILD_STATE_REMOVED;
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
gtk_at_spi_emit_children_changed (self->connection,
|
|
self->root_path,
|
|
state,
|
|
idx,
|
|
gtk_at_spi_root_to_ref (self),
|
|
window_ref);
|
|
}
|
|
|
|
static void
|
|
on_registration_reply (GObject *gobject,
|
|
GAsyncResult *result,
|
|
gpointer user_data)
|
|
{
|
|
GtkAtSpiRoot *self = user_data;
|
|
|
|
GError *error = NULL;
|
|
GVariant *reply = g_dbus_connection_call_finish (G_DBUS_CONNECTION (gobject), result, &error);
|
|
|
|
if (error != NULL)
|
|
{
|
|
g_critical ("Unable to register the application: %s", error->message);
|
|
g_error_free (error);
|
|
return;
|
|
}
|
|
|
|
if (reply != NULL)
|
|
{
|
|
g_variant_get (reply, "((so))",
|
|
&self->desktop_name,
|
|
&self->desktop_path);
|
|
g_variant_unref (reply);
|
|
|
|
GTK_NOTE (A11Y, g_message ("Connected to the a11y registry at (%s, %s)",
|
|
self->desktop_name,
|
|
self->desktop_path));
|
|
}
|
|
|
|
/* Register the cache object */
|
|
self->cache = gtk_at_spi_cache_new (self->connection, ATSPI_CACHE_PATH);
|
|
|
|
self->toplevels = gtk_window_get_toplevels ();
|
|
}
|
|
|
|
static gboolean
|
|
root_register (gpointer data)
|
|
{
|
|
GtkAtSpiRoot *self = data;
|
|
const char *unique_name;
|
|
|
|
/* Register the root element; every application has a single root, so we only
|
|
* need to do this once.
|
|
*
|
|
* The root element is used to advertise our existence on the accessibility
|
|
* bus, and it's the entry point to the accessible objects tree.
|
|
*
|
|
* The announcement is split into two phases:
|
|
*
|
|
* 1. we register the org.a11y.atspi.Application and org.a11y.atspi.Accessible
|
|
* interfaces at the well-known object path
|
|
* 2. we invoke the org.a11y.atspi.Socket.Embed method with the connection's
|
|
* unique name and the object path
|
|
* 3. the ATSPI registry daemon will set the org.a11y.atspi.Application.Id
|
|
* property on the given object path
|
|
* 4. the registration concludes when the Embed method returns us the desktop
|
|
* name and object path
|
|
*/
|
|
self->toolkit_name = "GTK";
|
|
self->version = PACKAGE_VERSION;
|
|
self->atspi_version = ATSPI_VERSION;
|
|
self->root_path = ATSPI_ROOT_PATH;
|
|
|
|
unique_name = g_dbus_connection_get_unique_name (self->connection);
|
|
|
|
g_dbus_connection_register_object (self->connection,
|
|
self->root_path,
|
|
(GDBusInterfaceInfo *) &atspi_application_interface,
|
|
&root_application_vtable,
|
|
self,
|
|
NULL,
|
|
NULL);
|
|
g_dbus_connection_register_object (self->connection,
|
|
self->root_path,
|
|
(GDBusInterfaceInfo *) &atspi_accessible_interface,
|
|
&root_accessible_vtable,
|
|
self,
|
|
NULL,
|
|
NULL);
|
|
|
|
GTK_NOTE (A11Y, g_message ("Registering (%s, %s) on the a11y bus",
|
|
unique_name,
|
|
self->root_path));
|
|
|
|
g_dbus_connection_call (self->connection,
|
|
"org.a11y.atspi.Registry",
|
|
ATSPI_ROOT_PATH,
|
|
"org.a11y.atspi.Socket",
|
|
"Embed",
|
|
g_variant_new ("((so))", unique_name, self->root_path),
|
|
G_VARIANT_TYPE ("((so))"),
|
|
G_DBUS_CALL_FLAGS_NONE, -1,
|
|
NULL,
|
|
on_registration_reply,
|
|
self);
|
|
|
|
self->register_id = 0;
|
|
|
|
return G_SOURCE_REMOVE;
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_spi_root_queue_register:
|
|
* @self: a #GtkAtSpiRoot
|
|
*
|
|
* Queues the registration of the root object on the AT-SPI bus.
|
|
*/
|
|
void
|
|
gtk_at_spi_root_queue_register (GtkAtSpiRoot *self)
|
|
{
|
|
/* Ignore multiple registration requests while one is already in flight */
|
|
if (self->register_id != 0)
|
|
return;
|
|
|
|
/* The cache is only available once the registration succeeds */
|
|
if (self->cache != NULL)
|
|
return;
|
|
|
|
self->register_id = g_idle_add (root_register, self);
|
|
g_source_set_name_by_id (self->register_id, "[gtk] ATSPI root registration");
|
|
}
|
|
|
|
static void
|
|
gtk_at_spi_root_constructed (GObject *gobject)
|
|
{
|
|
GtkAtSpiRoot *self = GTK_AT_SPI_ROOT (gobject);
|
|
|
|
GError *error = NULL;
|
|
|
|
/* The accessibility bus is a fully managed bus */
|
|
self->connection =
|
|
g_dbus_connection_new_for_address_sync (self->bus_address,
|
|
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
|
|
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
|
|
NULL, NULL,
|
|
&error);
|
|
|
|
if (error != NULL)
|
|
{
|
|
g_critical ("Unable to connect to the accessibility bus at '%s': %s",
|
|
self->bus_address,
|
|
error->message);
|
|
g_error_free (error);
|
|
goto out;
|
|
}
|
|
|
|
out:
|
|
G_OBJECT_CLASS (gtk_at_spi_root_parent_class)->constructed (gobject);
|
|
}
|
|
|
|
static void
|
|
gtk_at_spi_root_class_init (GtkAtSpiRootClass *klass)
|
|
{
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
gobject_class->constructed = gtk_at_spi_root_constructed;
|
|
gobject_class->set_property = gtk_at_spi_root_set_property;
|
|
gobject_class->get_property = gtk_at_spi_root_get_property;
|
|
gobject_class->dispose = gtk_at_spi_root_dispose;
|
|
gobject_class->finalize = gtk_at_spi_root_finalize;
|
|
|
|
obj_props[PROP_BUS_ADDRESS] =
|
|
g_param_spec_string ("bus-address", NULL, NULL,
|
|
NULL,
|
|
G_PARAM_CONSTRUCT_ONLY |
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS);
|
|
|
|
g_object_class_install_properties (gobject_class, N_PROPS, obj_props);
|
|
}
|
|
|
|
static void
|
|
gtk_at_spi_root_init (GtkAtSpiRoot *self)
|
|
{
|
|
}
|
|
|
|
GtkAtSpiRoot *
|
|
gtk_at_spi_root_new (const char *bus_address)
|
|
{
|
|
g_return_val_if_fail (bus_address != NULL, NULL);
|
|
|
|
return g_object_new (GTK_TYPE_AT_SPI_ROOT,
|
|
"bus-address", bus_address,
|
|
NULL);
|
|
}
|
|
|
|
GDBusConnection *
|
|
gtk_at_spi_root_get_connection (GtkAtSpiRoot *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_SPI_ROOT (self), NULL);
|
|
|
|
return self->connection;
|
|
}
|
|
|
|
GtkAtSpiCache *
|
|
gtk_at_spi_root_get_cache (GtkAtSpiRoot *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_SPI_ROOT (self), NULL);
|
|
|
|
return self->cache;
|
|
}
|
|
|
|
/*< private >
|
|
* gtk_at_spi_root_to_ref:
|
|
* @self: a #GtkAtSpiRoot
|
|
*
|
|
* Returns an ATSPI object reference for the #GtkAtSpiRoot node.
|
|
*
|
|
* Returns: (transfer floating): a #GVariant with the root reference
|
|
*/
|
|
GVariant *
|
|
gtk_at_spi_root_to_ref (GtkAtSpiRoot *self)
|
|
{
|
|
g_return_val_if_fail (GTK_IS_AT_SPI_ROOT (self), NULL);
|
|
|
|
if (self->desktop_path == NULL)
|
|
return gtk_at_spi_null_ref ();
|
|
|
|
return g_variant_new ("(so)", self->desktop_name, self->desktop_path);
|
|
}
|