Samuel Thibault, le jeu. 22 août 2019 13:16:44 +0200, a ecrit: > Now, thinking more about this, maybe there is a way to make all of this > transparent to applications using GtkSocket/GtkPlug: > > - introduce the at-spi objects I mentioned in my Aug 14th mail > - make GtkPlug expose the at-spi path as a _NET_WM property. > - make gtk_socket_add_window try to read it, and if it exists, call > atk_socket_embed on it > > That should be working both for the mate-panel implementation mentioned > above, and for tray icons. And for anything that uses GtkPlug/Socket.
Here is what is looks like, it looks quite fine in the end, what do people think? Arguably, the AtkPlugExt part could be stuffed into AtkPlug: currently it does not actually implement the ref_child/get_n_children interfaces so subclasses have to implement it anyway. So we could as well have a default implementation which returns 0 children by default, and 1 child if it was built by using a new dedicated atk_plug_new_child(child) allocator which takes the child to be used as parameter. AIUI doing this can't break existing usage, and allows to have it shared by all toolkits needing it instead of putting it in gtk only. Samuel
Index: gtk3/gtk/a11y/Makefile.inc =================================================================== --- gtk3.orig/gtk/a11y/Makefile.inc +++ gtk3/gtk/a11y/Makefile.inc @@ -30,6 +30,7 @@ a11y_h_sources = \ a11y/gtknotebookaccessible.h \ a11y/gtknotebookpageaccessible.h \ a11y/gtkpanedaccessible.h \ + a11y/gtkplugaccessible.h \ a11y/gtkpopoveraccessible.h \ a11y/gtkprogressbaraccessible.h \ a11y/gtkradiobuttonaccessible.h \ @@ -39,6 +40,7 @@ a11y_h_sources = \ a11y/gtkscaleaccessible.h \ a11y/gtkscalebuttonaccessible.h \ a11y/gtkscrolledwindowaccessible.h \ + a11y/gtksocketaccessible.h \ a11y/gtkspinbuttonaccessible.h \ a11y/gtkspinneraccessible.h \ a11y/gtkstatusbaraccessible.h \ @@ -104,6 +106,7 @@ a11y_c_sources = \ a11y/gtknotebookaccessible.c \ a11y/gtknotebookpageaccessible.c \ a11y/gtkpanedaccessible.c \ + a11y/gtkplugaccessible.c \ a11y/gtkpopoveraccessible.c \ a11y/gtkprogressbaraccessible.c \ a11y/gtkradiobuttonaccessible.c \ @@ -113,6 +116,7 @@ a11y_c_sources = \ a11y/gtkscaleaccessible.c \ a11y/gtkscalebuttonaccessible.c \ a11y/gtkscrolledwindowaccessible.c \ + a11y/gtksocketaccessible.c \ a11y/gtkspinbuttonaccessible.c \ a11y/gtkspinneraccessible.c \ a11y/gtkstatusbaraccessible.c \ Index: gtk3/gtk/gtk-a11y.h =================================================================== --- gtk3.orig/gtk/gtk-a11y.h +++ gtk3/gtk/gtk-a11y.h @@ -57,6 +57,7 @@ #include <gtk/a11y/gtkmenushellaccessible.h> #include <gtk/a11y/gtknotebookaccessible.h> #include <gtk/a11y/gtknotebookpageaccessible.h> +#include <gtk/a11y/gtkplugaccessible.h> #include <gtk/a11y/gtkpopoveraccessible.h> #include <gtk/a11y/gtkpanedaccessible.h> #include <gtk/a11y/gtkprogressbaraccessible.h> @@ -67,6 +68,7 @@ #include <gtk/a11y/gtkscaleaccessible.h> #include <gtk/a11y/gtkscalebuttonaccessible.h> #include <gtk/a11y/gtkscrolledwindowaccessible.h> +#include <gtk/a11y/gtksocketaccessible.h> #include <gtk/a11y/gtkspinbuttonaccessible.h> #include <gtk/a11y/gtkspinneraccessible.h> #include <gtk/a11y/gtkstatusbaraccessible.h> Index: gtk3/gtk/a11y/gtkplugaccessible.c =================================================================== --- /dev/null +++ gtk3/gtk/a11y/gtkplugaccessible.c @@ -0,0 +1,172 @@ +/* GTK+ - accessibility implementations + * Copyright 2019 Samuel Thibault <sthiba...@hypra.fr> + * + * 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 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 <gtk/gtk.h> +#include "gtkplugaccessible.h" + +/* We can not make GtkPlugAccessible inherit both from GtkContainerAccessible + * and GtkPlug, so we make it the atk child of an AtkPlug */ + +#ifndef HAVE_ATK_PLUG_NEW_CHILD + +// This could be stuffed into AtkPlug? + +#define ATK_TYPE_PLUG_EXT atk_plug_ext_get_type () +#define ATK_PLUG_EXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ATK_TYPE_PLUG_EXT_PLUG, AtkPlugExt)) + +GType atk_plug_ext_get_type (void); + +typedef struct _AtkPlugExt AtkPlugExt; +typedef struct _AtkPlugExtClass AtkPlugExtClass; + +AtkObject *atk_plug_ext_new (AtkObject *child); + + + + +struct _AtkPlugExt +{ + AtkPlug parent; + + // Private actually + AtkObject *child; +}; + +struct _AtkPlugExtClass +{ + AtkPlugClass parent_class; +}; + +G_DEFINE_TYPE (AtkPlugExt, atk_plug_ext, ATK_TYPE_PLUG) + +static AtkObject* +atk_plug_ext_ref_child (AtkObject *obj, int i) +{ + AtkObject *child; + + if (i != 0) + return NULL; + + child = ATK_PLUG_EXT (obj)->child; + + if (child == NULL) + return NULL; + + return g_object_ref (child); +} + +static int +atk_plug_ext_get_n_children (AtkObject *obj) +{ + if (ATK_PLUG_EXT (obj)->child == NULL) + return 0; + + return 1; +} + +static AtkStateSet* +atk_plug_ext_ref_state_set (AtkObject *object) +{ + AtkObject *child = ATK_PLUG_EXT (object)->child; + + if (child == NULL) + return NULL; + + return atk_object_ref_state_set (child); +} + + +static void +atk_plug_ext_class_init (AtkPlugExtClass *klass) +{ + AtkObjectClass *class = ATK_OBJECT_CLASS (klass); + + class->get_n_children = atk_plug_ext_get_n_children; + class->ref_child = atk_plug_ext_ref_child; + class->ref_state_set = atk_plug_ext_ref_state_set; +} + +static void +atk_plug_ext_init (AtkPlugExt *plug) { +} + +AtkObject *atk_plug_ext_new_child (AtkObject *child) +{ + AtkPlugExt *accessible; + + accessible = g_object_new (ATK_TYPE_PLUG_EXT, NULL); + + accessible->child = child; + atk_object_set_parent (child, ATK_OBJECT (accessible)); + + return ATK_OBJECT (accessible); +} +#define atk_plug_new_child(child) atk_plug_ext_new_child(child) +#endif + + + +struct _GtkPlugAccessiblePrivate +{ + AtkObject *accessible_plug; +}; + +G_DEFINE_TYPE_WITH_CODE (GtkPlugAccessible, gtk_plug_accessible, GTK_TYPE_WINDOW_ACCESSIBLE, + G_ADD_PRIVATE (GtkPlugAccessible)) + + +static void +gtk_plug_accessible_finalize (GObject *object) +{ + GtkPlugAccessible *plug = GTK_PLUG_ACCESSIBLE (object); + GtkPlugAccessiblePrivate *priv = plug->priv; + + g_clear_object (&priv->accessible_plug); + + G_OBJECT_CLASS (gtk_plug_accessible_parent_class)->finalize (object); +} + +static void +gtk_plug_accessible_initialize (AtkObject *plug, gpointer data) +{ + ATK_OBJECT_CLASS (gtk_plug_accessible_parent_class)->initialize (plug, data); + + GTK_PLUG_ACCESSIBLE (plug)->priv->accessible_plug = atk_plug_ext_new_child (plug); +} + +static void +gtk_plug_accessible_class_init (GtkPlugAccessibleClass *klass) { + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + atk_class->initialize = gtk_plug_accessible_initialize; + gobject_class->finalize = gtk_plug_accessible_finalize; +} + +static void +gtk_plug_accessible_init (GtkPlugAccessible *plug) +{ + plug->priv = gtk_plug_accessible_get_instance_private (plug); +} + +gchar * +gtk_plug_accessible_get_id (GtkPlugAccessible *plug) +{ + return atk_plug_get_id (ATK_PLUG (plug->priv->accessible_plug)); +} Index: gtk3/gtk/a11y/gtkplugaccessible.h =================================================================== --- /dev/null +++ gtk3/gtk/a11y/gtkplugaccessible.h @@ -0,0 +1,60 @@ +/* GTK+ - accessibility implementations + * Copyright 2019 Samuel Thibault <sthiba...@hypra.fr> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GTK_PLUG_ACCESSIBLE_H__ +#define __GTK_PLUG_ACCESSIBLE_H__ + +#if !defined (__GTK_A11Y_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk-a11y.h> can be included directly." +#endif + +#include <gtk/a11y/gtkwindowaccessible.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_PLUG_ACCESSIBLE (gtk_plug_accessible_get_type ()) +#define GTK_PLUG_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PLUG_ACCESSIBLE, GtkPlugAccessible)) +#define GTK_PLUG_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PLUG_ACCESSIBLE, GtkPlugAccessibleClass)) +#define GTK_IS_PLUG_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PLUG_ACCESSIBLE)) +#define GTK_IS_PLUG_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PLUG_ACCESSIBLE)) +#define GTK_PLUG_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PLUG_ACCESSIBLE, GtkPlugAccessibleClass)) + +typedef struct _GtkPlugAccessible GtkPlugAccessible; +typedef struct _GtkPlugAccessibleClass GtkPlugAccessibleClass; +typedef struct _GtkPlugAccessiblePrivate GtkPlugAccessiblePrivate; + +struct _GtkPlugAccessible +{ + GtkWindowAccessible parent; + + GtkPlugAccessiblePrivate *priv; +}; + +struct _GtkPlugAccessibleClass +{ + GtkWindowAccessibleClass parent_class; +}; + +GDK_AVAILABLE_IN_ALL +GType gtk_plug_accessible_get_type (void); + +GDK_AVAILABLE_IN_ALL +gchar *gtk_plug_accessible_get_id (GtkPlugAccessible *plug); + +G_END_DECLS + +#endif /* __GTK_PLUG_ACCESSIBLE_H__ */ Index: gtk3/gtk/a11y/gtksocketaccessible.c =================================================================== --- /dev/null +++ gtk3/gtk/a11y/gtksocketaccessible.c @@ -0,0 +1,102 @@ +/* GTK+ - accessibility implementations + * Copyright 2019 Samuel Thibault <sthiba...@hypra.fr> + * + * 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 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 <gtk/gtk.h> +#include "gtksocketaccessible.h" + +/* We can not make GtkSocketAccessible inherit both from GtkContainerAccessible + * and GtkSocket, so we make it the atk parent of an AtkSocket */ + +struct _GtkSocketAccessiblePrivate +{ + AtkObject *accessible_socket; +}; + +G_DEFINE_TYPE_WITH_CODE (GtkSocketAccessible, gtk_socket_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE, + G_ADD_PRIVATE (GtkSocketAccessible)) + +static AtkObject* +gtk_socket_accessible_ref_child (AtkObject *obj, int i) +{ + GtkSocketAccessible *socket = GTK_SOCKET_ACCESSIBLE (obj); + + if (i != 0) + return NULL; + + return g_object_ref (socket->priv->accessible_socket); +} + +static int +gtk_socket_accessible_get_n_children (AtkObject *obj) +{ + return 1; +} + +static void +gtk_socket_accessible_finalize (GObject *object) +{ + GtkSocketAccessible *socket = GTK_SOCKET_ACCESSIBLE (object); + GtkSocketAccessiblePrivate *priv = socket->priv; + + g_clear_object (&priv->accessible_socket); + + G_OBJECT_CLASS (gtk_socket_accessible_parent_class)->finalize (object); +} + +static void +gtk_socket_accessible_initialize (AtkObject *socket, gpointer data) +{ + AtkObject *atk_socket; + + ATK_OBJECT_CLASS (gtk_socket_accessible_parent_class)->initialize (socket, data); + + atk_socket = atk_socket_new (); + + GTK_SOCKET_ACCESSIBLE(socket)->priv->accessible_socket = atk_socket; + atk_object_set_parent (atk_socket, socket); +} + +static void +gtk_socket_accessible_class_init (GtkSocketAccessibleClass *klass) +{ + GtkContainerAccessibleClass *container_class = (GtkContainerAccessibleClass*)klass; + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + container_class->add_gtk = NULL; + container_class->remove_gtk = NULL; + + atk_class->initialize = gtk_socket_accessible_initialize; + atk_class->get_n_children = gtk_socket_accessible_get_n_children; + atk_class->ref_child = gtk_socket_accessible_ref_child; + + gobject_class->finalize = gtk_socket_accessible_finalize; +} + +static void +gtk_socket_accessible_init (GtkSocketAccessible *socket) +{ + socket->priv = gtk_socket_accessible_get_instance_private (socket); +} + +void +gtk_socket_accessible_embed (GtkSocketAccessible *socket, gchar *path) +{ + atk_socket_embed (ATK_SOCKET (socket->priv->accessible_socket), path); +} Index: gtk3/gtk/a11y/gtksocketaccessible.h =================================================================== --- /dev/null +++ gtk3/gtk/a11y/gtksocketaccessible.h @@ -0,0 +1,60 @@ +/* GTK+ - accessibility implementations + * Copyright 2019 Samuel Thibault <sthiba...@hypra.fr> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GTK_SOCKET_ACCESSIBLE_H__ +#define __GTK_SOCKET_ACCESSIBLE_H__ + +#if !defined (__GTK_A11Y_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only <gtk/gtk-a11y.h> can be included directly." +#endif + +#include <gtk/a11y/gtkcontaineraccessible.h> + +G_BEGIN_DECLS + +#define GTK_TYPE_SOCKET_ACCESSIBLE (gtk_socket_accessible_get_type ()) +#define GTK_SOCKET_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SOCKET_ACCESSIBLE, GtkSocketAccessible)) +#define GTK_SOCKET_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_SOCKET_ACCESSIBLE, GtkSocketAccessibleClass)) +#define GTK_IS_SOCKET_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SOCKET_ACCESSIBLE)) +#define GTK_IS_SOCKET_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_SOCKET_ACCESSIBLE)) +#define GTK_SOCKET_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_SOCKET_ACCESSIBLE, GtkSocketAccessibleClass)) + +typedef struct _GtkSocketAccessible GtkSocketAccessible; +typedef struct _GtkSocketAccessibleClass GtkSocketAccessibleClass; +typedef struct _GtkSocketAccessiblePrivate GtkSocketAccessiblePrivate; + +struct _GtkSocketAccessible +{ + GtkContainerAccessible parent; + + GtkSocketAccessiblePrivate *priv; +}; + +struct _GtkSocketAccessibleClass +{ + GtkContainerAccessibleClass parent_class; +}; + +GDK_AVAILABLE_IN_ALL +GType gtk_socket_accessible_get_type (void); + +GDK_AVAILABLE_IN_ALL +void gtk_socket_accessible_embed (GtkSocketAccessible *socket, gchar *path); + +G_END_DECLS + +#endif /* __GTK_SOCKET_ACCESSIBLE_H__ */ Index: gtk3/gtk/gtkplug.c =================================================================== --- gtk3.orig/gtk/gtkplug.c +++ gtk3/gtk/gtkplug.c @@ -39,6 +39,8 @@ #include "gtkwindowprivate.h" #include "gtkxembed.h" +#include "a11y/gtkplugaccessible.h" + #include <gdk/gdkx.h> /** @@ -227,6 +229,8 @@ gtk_plug_class_init (GtkPlugClass *class NULL, NULL, NULL, G_TYPE_NONE, 0); + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_PLUG_ACCESSIBLE); } static void @@ -710,6 +714,24 @@ xembed_set_info (GdkWindow *window, (unsigned char *)buffer, 2); } +static void +_gtk_plug_accessible_embed_set_info (GtkWidget *widget, GdkWindow *window) +{ + GdkDisplay *display = gdk_window_get_display (window); + gchar *buffer = gtk_plug_accessible_get_id (GTK_PLUG_ACCESSIBLE (gtk_widget_get_accessible (widget))); + Atom net_at_spi_path_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_AT_SPI_PATH"); + + if (!buffer) + return; + + XChangeProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + net_at_spi_path_atom, net_at_spi_path_atom, 8, + PropModeReplace, + (unsigned char *)buffer, strlen(buffer)); + g_free (buffer); +} + /** * gtk_plug_focus_first_last: * @plug: a #GtkPlug @@ -1097,6 +1119,8 @@ gtk_plug_realize (GtkWidget *widget) } gtk_widget_register_window (widget, gdk_window); + + _gtk_plug_accessible_embed_set_info (widget, gdk_window); } static void Index: gtk3/gtk/gtksocket.c =================================================================== --- gtk3.orig/gtk/gtksocket.c +++ gtk3/gtk/gtksocket.c @@ -51,6 +51,8 @@ #include "gtkxembed.h" +#include "a11y/gtksocketaccessible.h" + /** * SECTION:gtksocket @@ -152,6 +154,9 @@ static gboolean xembed_get_info unsigned long *version, unsigned long *flags); +static void _gtk_socket_accessible_embed (GtkWidget *socket, + GdkWindow *window); + /* From Tk */ #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20 @@ -264,6 +269,9 @@ gtk_socket_class_init (GtkSocketClass *c _gtk_boolean_handled_accumulator, NULL, _gtk_marshal_BOOLEAN__VOID, G_TYPE_BOOLEAN, 0); + + + gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SOCKET_ACCESSIBLE); } static void @@ -1145,6 +1153,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS socket_update_focus_in (socket); gtk_widget_queue_resize (GTK_WIDGET (socket)); + + _gtk_socket_accessible_embed (GTK_WIDGET (socket), private->plug_window); } if (private->plug_window) @@ -1368,6 +1378,58 @@ handle_xembed_message (GtkSocket } } +static void +_gtk_socket_accessible_embed (GtkWidget *socket, GdkWindow *window) +{ + GdkDisplay *display = gdk_window_get_display (window); + Atom net_at_spi_path_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_AT_SPI_PATH"); + Atom type; + int format; + unsigned long nitems, bytes_after; + unsigned char *data; + int status; + + gdk_error_trap_push (); + status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), + GDK_WINDOW_XID (window), + net_at_spi_path_atom, + 0, INT_MAX / 4, False, + net_at_spi_path_atom, &type, &format, + &nitems, &bytes_after, &data); + gdk_error_trap_pop_ignored (); + + if (status != Success) + return; /* Window vanished? */ + + if (type == None) /* No info property */ + return; + + if (type != net_at_spi_path_atom) + { + g_warning ("_XEMBED_AT_SPI_PATH property has wrong type"); + return; + } + + if (nitems == 0) + { + g_warning ("_XEMBED_AT_SPI_PATH too short"); + XFree (data); + return; + } + + if (nitems > INT_MAX) + { + g_warning ("_XEMBED_AT_SPI_PATH too long"); + XFree (data); + return; + } + + gtk_socket_accessible_embed (GTK_SOCKET_ACCESSIBLE (gtk_widget_get_accessible (socket)), (gchar*) data); + XFree (data); + + return; +} + static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event,
_______________________________________________ gnome-accessibility-list mailing list gnome-accessibility-list@gnome.org https://mail.gnome.org/mailman/listinfo/gnome-accessibility-list