diff --git a/gtk/a11y/gtkatspicontext.c b/gtk/a11y/gtkatspicontext.c index 8380d156b4..5501721d12 100644 --- a/gtk/a11y/gtkatspicontext.c +++ b/gtk/a11y/gtkatspicontext.c @@ -82,6 +82,10 @@ * hold the TAB_PANEL role and be the target of the CONTROLS * relation with their corresponding tabs (in the stack * switcher or notebook). + * + * These are the exceptions implemented by GTK itself, but note that application + * developers can customize the accessibility tree by implementing the + * [iface@Gtk.Accessible] interface in any way they choose. */ struct _GtkAtSpiContext @@ -329,32 +333,43 @@ collect_relations (GtkAtSpiContext *self, /* }}} */ /* {{{ Accessible implementation */ static int -get_index_in_parent (GtkWidget *widget) +get_index_in (GtkAccessible *parent, + GtkAccessible *child) { - GtkWidget *parent = gtk_widget_get_parent (widget); - GtkWidget *child; - int idx; + GtkAccessible *candidate; + guint res; if (parent == NULL) return -1; - idx = 0; - for (child = gtk_widget_get_first_child (parent); - child; - child = gtk_widget_get_next_sibling (child)) + res = 0; + for (candidate = gtk_accessible_get_first_accessible_child (parent); + candidate != NULL; + candidate = gtk_accessible_get_next_accessible_sibling (candidate)) { - if (child == widget) - return idx; + if (candidate == child) + return res; - if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child))) + if (!gtk_accessible_should_present (candidate)) continue; - idx++; + res++; } return -1; } +static int +get_index_in_parent (GtkAccessible *accessible) +{ + GtkAccessible *parent = gtk_accessible_get_accessible_parent (accessible); + + if (parent != NULL) + return get_index_in (parent, accessible); + + return -1; +} + static int get_index_in_toplevels (GtkWidget *widget) { @@ -387,61 +402,21 @@ get_parent_context_ref (GtkAccessible *accessible) { GVariant *res = NULL; - if (GTK_IS_WIDGET (accessible)) + GtkAccessible *parent = gtk_accessible_get_accessible_parent (accessible); + + if (parent == NULL) { - GtkWidget *widget = GTK_WIDGET (accessible); - GtkWidget *parent = gtk_widget_get_parent (widget); + GtkATContext *context = gtk_accessible_get_at_context (accessible); + GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context); - if (parent == NULL) - { - GtkATContext *context = gtk_accessible_get_at_context (accessible); - GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (context); - - res = gtk_at_spi_root_to_ref (self->root); - } - else if (GTK_IS_STACK (parent)) - { - GtkStackPage *page = - gtk_stack_get_page (GTK_STACK (parent), widget); - GtkATContext *parent_context = - gtk_accessible_get_at_context (GTK_ACCESSIBLE (page)); - - if (parent_context != NULL) - { - gtk_at_context_realize (parent_context); - - res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context)); - } - } - else - { - GtkATContext *parent_context = - gtk_accessible_get_at_context (GTK_ACCESSIBLE (parent)); - - if (parent_context != NULL) - { - /* XXX: This realize() is needed otherwise opening a GtkPopover will - * emit a warning when getting the context's reference - */ - gtk_at_context_realize (parent_context); - - res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context)); - } - } + res = gtk_at_spi_root_to_ref (self->root); } - else if (GTK_IS_STACK_PAGE (accessible)) + else { - GtkWidget *parent = - gtk_widget_get_parent (gtk_stack_page_get_child (GTK_STACK_PAGE (accessible))); - GtkATContext *parent_context = - gtk_accessible_get_at_context (GTK_ACCESSIBLE (parent)); + GtkATContext *parent_context = gtk_accessible_get_at_context (parent); + gtk_at_context_realize (parent_context); - if (parent_context != NULL) - { - gtk_at_context_realize (parent_context); - - res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context)); - } + res = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (parent_context)); } if (res == NULL) @@ -522,49 +497,30 @@ handle_accessible_method (GDBusConnection *connection, { GtkATContext *context = NULL; GtkAccessible *accessible; - int idx, real_idx = 0; + int idx, presentable_idx; g_variant_get (parameters, "(i)", &idx); accessible = gtk_at_context_get_accessible (GTK_AT_CONTEXT (self)); - if (GTK_IS_STACK_PAGE (accessible)) - { - if (idx == 0) - { - GtkWidget *child; + GtkAccessible *child; + + presentable_idx = 0; + for (child = gtk_accessible_get_first_accessible_child (accessible); + child != NULL; + child = gtk_accessible_get_next_accessible_sibling (child)) + { + if (!gtk_accessible_should_present (child)) + continue; + + if (presentable_idx == idx) + break; + presentable_idx++; - child = gtk_stack_page_get_child (GTK_STACK_PAGE (accessible)); - if (gtk_accessible_should_present (GTK_ACCESSIBLE (child))) - context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child)); - } } - else if (GTK_IS_WIDGET (accessible)) + if (child) { - GtkWidget *widget = GTK_WIDGET (accessible); - GtkWidget *child; - - real_idx = 0; - for (child = gtk_widget_get_first_child (widget); - child; - child = gtk_widget_get_next_sibling (child)) - { - if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child))) - continue; - - if (real_idx == idx) - break; - - real_idx += 1; - } - - if (child) - { - if (GTK_IS_STACK (accessible)) - context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (gtk_stack_get_page (GTK_STACK (accessible), child))); - else - context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child)); - } + context = gtk_accessible_get_at_context (child); } if (context == NULL) @@ -588,45 +544,24 @@ handle_accessible_method (GDBusConnection *connection, GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(so)")); GtkAccessible *accessible = gtk_at_context_get_accessible (GTK_AT_CONTEXT (self)); - if (GTK_IS_WIDGET (accessible)) - { - GtkWidget *widget = GTK_WIDGET (accessible); - GtkWidget *child; - for (child = gtk_widget_get_first_child (widget); - child; - child = gtk_widget_get_next_sibling (child)) - { - if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child))) - continue; + GtkAccessible *child; + for (child = gtk_accessible_get_first_accessible_child (accessible); + child != NULL; + child = gtk_accessible_get_next_accessible_sibling (child)) + { + if (!gtk_accessible_should_present (child)) + continue; - GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child)); + GtkATContext *context = gtk_accessible_get_at_context (child); - /* Realize the child ATContext in order to get its ref */ - gtk_at_context_realize (context); + /* Realize the child ATContext in order to get its ref */ + gtk_at_context_realize (context); - GVariant *ref = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (context)); + GVariant *ref = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (context)); - if (ref != NULL) - g_variant_builder_add (&builder, "@(so)", ref); - } - } - else if (GTK_IS_STACK_PAGE (accessible)) - { - GtkWidget *child = gtk_stack_page_get_child (GTK_STACK_PAGE (accessible)); - - if (gtk_accessible_should_present (GTK_ACCESSIBLE (child))) - { - GtkATContext *context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (child)); - - /* Realize the child ATContext in order to get its ref */ - gtk_at_context_realize (context); - - GVariant *ref = gtk_at_spi_context_to_ref (GTK_AT_SPI_CONTEXT (context)); - - if (ref != NULL) - g_variant_builder_add (&builder, "@(so)", ref); - } + if (ref != NULL) + g_variant_builder_add (&builder, "@(so)", ref); } g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a(so))", &builder)); @@ -915,7 +850,7 @@ gtk_at_spi_context_state_change (GtkATContext *ctx, if (changed_states & GTK_ACCESSIBLE_STATE_CHANGE_HIDDEN) { - GtkWidget *parent; + GtkAccessible *parent; GtkATContext *context; GtkAccessibleChildChange change; @@ -932,14 +867,9 @@ gtk_at_spi_context_state_change (GtkATContext *ctx, } else { - if (GTK_IS_WIDGET (accessible)) - parent = gtk_widget_get_parent (GTK_WIDGET (accessible)); - else if (GTK_IS_STACK_PAGE (accessible)) - parent = gtk_widget_get_parent (gtk_stack_page_get_child (GTK_STACK_PAGE (accessible))); - else - g_assert_not_reached (); + parent = gtk_accessible_get_accessible_parent (accessible); - context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (parent)); + context = gtk_accessible_get_at_context (parent); gtk_at_context_child_changed (context, change, accessible); } } @@ -1168,29 +1098,9 @@ gtk_at_spi_context_bounds_change (GtkATContext *ctx) { GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (ctx); GtkAccessible *accessible = gtk_at_context_get_accessible (ctx); - GtkWidget *widget; - GtkWidget *parent; - double x, y; - int width, height; - - if (!GTK_IS_WIDGET (accessible)) - return; - - widget = GTK_WIDGET (accessible); - if (!gtk_widget_get_realized (widget)) - return; - - parent = gtk_widget_get_parent (widget); - - if (parent) - gtk_widget_translate_coordinates (widget, parent, 0., 0., &x, &y); - else - x = y = 0.; - - width = gtk_widget_get_width (widget); - height = gtk_widget_get_height (widget); - - emit_bounds_changed (self, (int)x, (int)y, width, height); + int x, y, width, height; + if (gtk_accessible_get_bounds (accessible, &x, &y, &width, &height)) + emit_bounds_changed (self, x, y, width, height); } static void @@ -1201,99 +1111,17 @@ gtk_at_spi_context_child_change (GtkATContext *ctx, GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (ctx); GtkAccessible *accessible = gtk_at_context_get_accessible (ctx); GtkATContext *child_context = gtk_accessible_get_at_context (child); - GtkWidget *parent_widget; - GtkWidget *child_widget; - int idx = 0; - - if (!GTK_IS_WIDGET (accessible)) - return; if (child_context == NULL) return; - /* handle the stack page special case */ - if (GTK_IS_WIDGET (child) && - GTK_IS_STACK (gtk_widget_get_parent (GTK_WIDGET (child)))) - { - GtkWidget *stack; - GtkStackPage *page; - GListModel *pages; + GtkAccessible *parent = gtk_accessible_get_accessible_parent (child); + int idx = 0; - stack = gtk_widget_get_parent (GTK_WIDGET (child)); - page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (child)); - pages = G_LIST_MODEL (gtk_stack_get_pages (GTK_STACK (stack))); - idx = 0; - for (guint i = 0; i < g_list_model_get_n_items (pages); i++) - { - GtkStackPage *item = g_list_model_get_item (pages, i); - - g_object_unref (item); - - if (!gtk_accessible_should_present (GTK_ACCESSIBLE (item))) - continue; - - if (item == page) - break; - - idx++; - } - g_object_unref (pages); - - if (change & GTK_ACCESSIBLE_CHILD_CHANGE_ADDED) - { - emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (stack))), - GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))), - idx, - GTK_ACCESSIBLE_CHILD_STATE_ADDED); - - emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))), - GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (child)), - 0, - GTK_ACCESSIBLE_CHILD_STATE_ADDED); - } - - if (change & GTK_ACCESSIBLE_CHILD_CHANGE_REMOVED) - { - emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))), - GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (child)), - 0, - GTK_ACCESSIBLE_CHILD_STATE_REMOVED); - emit_children_changed (GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (stack))), - GTK_AT_SPI_CONTEXT (gtk_accessible_get_at_context (GTK_ACCESSIBLE (page))), - idx, - GTK_ACCESSIBLE_CHILD_STATE_REMOVED); - - } - - return; - } - - parent_widget = GTK_WIDGET (accessible); - - if (GTK_IS_STACK_PAGE (child)) - child_widget = gtk_stack_page_get_child (GTK_STACK_PAGE (child)); - else - child_widget = GTK_WIDGET (child); - - if (gtk_widget_get_parent (child_widget) != parent_widget) - { - idx = 0; - } - else - { - for (GtkWidget *iter = gtk_widget_get_first_child (parent_widget); - iter != NULL; - iter = gtk_widget_get_next_sibling (iter)) - { - if (!gtk_accessible_should_present (GTK_ACCESSIBLE (iter))) - continue; - - if (iter == child_widget) - break; - - idx += 1; - } - } + if (parent == NULL) + idx = -1; + else if (parent == accessible) + idx = get_index_in (accessible, child); if (change & GTK_ACCESSIBLE_CHILD_CHANGE_ADDED) emit_children_changed (self, @@ -1858,12 +1686,8 @@ gtk_at_spi_context_get_index_in_parent (GtkAtSpiContext *self) if (GTK_IS_ROOT (accessible)) idx = get_index_in_toplevels (GTK_WIDGET (accessible)); - else if (GTK_IS_STACK_PAGE (accessible)) - idx = get_index_in_parent (gtk_stack_page_get_child (GTK_STACK_PAGE (accessible))); - else if (GTK_IS_STACK (gtk_widget_get_parent (GTK_WIDGET (accessible)))) - idx = 1; else - idx = get_index_in_parent (GTK_WIDGET (accessible)); + idx = get_index_in_parent (accessible); return idx; } @@ -1874,26 +1698,18 @@ gtk_at_spi_context_get_child_count (GtkAtSpiContext *self) g_return_val_if_fail (GTK_IS_AT_SPI_CONTEXT (self), -1); GtkAccessible *accessible = gtk_at_context_get_accessible (GTK_AT_CONTEXT (self)); - int n_children = -1; + int n_children = 0; - if (GTK_IS_WIDGET (accessible)) + GtkAccessible *child = NULL; + + for (child = gtk_accessible_get_first_accessible_child (accessible); + child != NULL; + child = gtk_accessible_get_next_accessible_sibling (child)) { - GtkWidget *child; + if (!gtk_accessible_should_present (child)) + continue; - n_children = 0; - for (child = gtk_widget_get_first_child (GTK_WIDGET (accessible)); - child; - child = gtk_widget_get_next_sibling (child)) - { - if (!gtk_accessible_should_present (GTK_ACCESSIBLE (child))) - continue; - - n_children++; - } - } - else if (GTK_IS_STACK_PAGE (accessible)) - { - n_children = 1; + n_children++; } return n_children; diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c index 05f804e25d..7143c14006 100644 --- a/gtk/gtkaccessible.c +++ b/gtk/gtkaccessible.c @@ -37,6 +37,14 @@ * a way that should be reflected by assistive technologies. For instance, * if a `GtkWidget` visibility changes, the %GTK_ACCESSIBLE_STATE_HIDDEN * state will also change to reflect the [property@Gtk.Widget:visible] property. + * + * Every accessible implementation is part of a tree of accessible objects. + * Normally, this tree corresponds to the widget tree, but can be customized + * by reimplementing the [vfunc@Gtk.Accessible.get_accessible_parent], + * [vfunc@Gtk.Accessible.get_first_accessible_child] and + * [vfunc@Gtk.Accessible.get_next_accessible_sibling] virtual functions. + * Note that you can not create a top-level accessible object as of now, + * which means that you must always have a parent accessible object. */ #include "config.h" @@ -74,7 +82,7 @@ gtk_accessible_default_init (GtkAccessibleInterface *iface) g_object_interface_install_property (iface, pspec); } -/*< private > +/** * gtk_accessible_get_at_context: * @self: a `GtkAccessible` * @@ -91,12 +99,68 @@ gtk_accessible_get_at_context (GtkAccessible *self) } /** - * gtk_accessible_get_accessible_role: (attributes org.gtk.Method.get_property=accessible-role) + * gtk_accessible_get_accessible_parent: * @self: a `GtkAccessible` * - * Retrieves the `GtkAccessibleRole` for the given `GtkAccessible`. + * Retrieves the accessible accessible for an accessible object * - * Returns: a `GtkAccessibleRole` + * This function returns `NULL` for top level widgets + * + * Returns: (transfer none) (nullable): the accessible parent + * + * Since: 4.10 + */ +GtkAccessible * +gtk_accessible_get_accessible_parent (GtkAccessible *self) +{ + g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), NULL); + + return GTK_ACCESSIBLE_GET_IFACE (self)->get_accessible_parent (self); +} + +/** + * gtk_accessible_get_first_accessible_child: + * @self: an accessible object + * + * Retrieves the first accessible child of an accessible object. + * + * Returns: (transfer none) (nullable): the first accessible child + * + * since: 4.10 + */ +GtkAccessible * +gtk_accessible_get_first_accessible_child (GtkAccessible *self) +{ + g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), NULL); + + return GTK_ACCESSIBLE_GET_IFACE (self)->get_first_accessible_child (self); +} + +/** + * gtk_accessible_get_next_accessible_sibling: + * @self: an accessible object + * + * Retrieves the next accessible sibling of an accessible object + * + * Returns: (transfer none) (nullable): the next accessible sibling + * + * since: 4.10 + */ +GtkAccessible * +gtk_accessible_get_next_accessible_sibling (GtkAccessible *self) +{ + g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), NULL); + + return GTK_ACCESSIBLE_GET_IFACE (self)->get_next_accessible_sibling (self); +} + +/** + * gtk_accessible_get_accessible_role: + * @self: an accessible object + * + * Retrieves the accessible role of an accessible object. + * + * Returns: the accessible role */ GtkAccessibleRole gtk_accessible_get_accessible_role (GtkAccessible *self) @@ -127,6 +191,7 @@ gtk_accessible_get_accessible_role (GtkAccessible *self) * state change must be communicated to assistive technologies. * * Example: + * * ```c * value = GTK_ACCESSIBLE_TRISTATE_MIXED; * gtk_accessible_update_state (GTK_ACCESSIBLE (check_button), @@ -659,10 +724,10 @@ gtk_accessible_role_to_name (GtkAccessibleRole role, /*< private > * gtk_accessible_role_is_range_subclass: * @role: a `GtkAccessibleRole` - * + * * Checks if @role is considered to be a subclass of %GTK_ACCESSIBLE_ROLE_RANGE * according to the WAI-ARIA specification. - * + * * Returns: whether the @role is range-like */ gboolean @@ -683,7 +748,7 @@ gtk_accessible_role_is_range_subclass (GtkAccessibleRole role) return FALSE; } -/* +/*< private > * gtk_accessible_platform_changed: * @self: a `GtkAccessible` * @change: the platform state change to report @@ -712,7 +777,7 @@ gtk_accessible_platform_changed (GtkAccessible *self, /* propagate changes up from ignored widgets */ if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE) - context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (gtk_widget_get_parent (GTK_WIDGET (self)))); + context = gtk_accessible_get_at_context (gtk_accessible_get_accessible_parent (self)); if (context == NULL) return; @@ -721,7 +786,7 @@ gtk_accessible_platform_changed (GtkAccessible *self, gtk_at_context_update (context); } -/* +/** * gtk_accessible_get_platform_state: * @self: a `GtkAccessible` * @state: platform state to query @@ -735,15 +800,19 @@ gtk_accessible_platform_changed (GtkAccessible *self, * child widget, as is the case for `GtkText` wrappers. * * Returns: the value of @state for the accessible + * + * Since: 4.10 */ gboolean gtk_accessible_get_platform_state (GtkAccessible *self, GtkAccessiblePlatformState state) { + g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), FALSE); + return GTK_ACCESSIBLE_GET_IFACE (self)->get_platform_state (self, state); } -/* +/*< private > * gtk_accessible_bounds_changed: * @self: a `GtkAccessible` * @@ -752,7 +821,7 @@ gtk_accessible_get_platform_state (GtkAccessible *self, * changed. * * Note that the bounds are not included in this API. - * AT backends should use widget API to obtain them. + * AT backends should use [method@Gtk.Accessible.get_bounds] to get them. */ void gtk_accessible_bounds_changed (GtkAccessible *self) @@ -770,7 +839,39 @@ gtk_accessible_bounds_changed (GtkAccessible *self) gtk_at_context_bounds_changed (context); } -/* +/** + * gtk_accessible_get_bounds: + * @self: a `GtkAccessible` + * @x: (out): the x coordinate of the top left corner of the accessible + * @y: (out): the y coordinate of the top left corner of the widget + * @width: (out): the width of the accessible object + * @height: (out): the height of the accessible object + * + * Queries the coordinates and dimensions of this accessible + * + * This functionality can be overridden by `GtkAccessible` + * implementations, e.g. to get the bounds from an ignored + * child widget. + * + * Returns: true if the bounds are valid, and false otherwise + * + * Since: 4.10 + */ +gboolean +gtk_accessible_get_bounds (GtkAccessible *self, + int *x, + int *y, + int *width, + int *height) +{ + g_return_val_if_fail (GTK_IS_ACCESSIBLE (self), FALSE); + g_return_val_if_fail (x != NULL && y != NULL, FALSE); + g_return_val_if_fail (width != NULL && height != NULL, FALSE); + + return GTK_ACCESSIBLE_GET_IFACE (self)->get_bounds (self, x, y, width, height); +} + +/*< private > * gtk_accessible_should_present: * @self: a `GtkAccessible` * @@ -829,7 +930,7 @@ gtk_accessible_update_children (GtkAccessible *self, /* propagate changes up from ignored widgets */ if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE) - context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (gtk_widget_get_parent (GTK_WIDGET (self)))); + context = gtk_accessible_get_at_context (gtk_accessible_get_accessible_parent (self)); if (context == NULL) return; diff --git a/gtk/gtkaccessible.h b/gtk/gtkaccessible.h index 17a31ba4a4..713a9b5ccf 100644 --- a/gtk/gtkaccessible.h +++ b/gtk/gtkaccessible.h @@ -32,58 +32,199 @@ G_BEGIN_DECLS #define GTK_TYPE_ACCESSIBLE (gtk_accessible_get_type()) -GDK_AVAILABLE_IN_ALL +GDK_AVAILABLE_IN_4_10 G_DECLARE_INTERFACE (GtkAccessible, gtk_accessible, GTK, ACCESSIBLE, GObject) -GDK_AVAILABLE_IN_ALL -GtkAccessibleRole gtk_accessible_get_accessible_role (GtkAccessible *self); +/** + * GtkAccessiblePlatformState: + * @GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE: whether the accessible can be focused + * @GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED: whether the accessible has focus + * @GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE: whether the accessible is active + * + * The various platform states which can be queried + * using [method@Gtk.Accessible.get_platform_state]. + * + * Since: 4.10 + */ +typedef enum { + GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE, + GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED, + GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE +} GtkAccessiblePlatformState; + +/** + * GtkAccessibleInterface: + * @get_at_context: retrieve the platform-specific accessibility context + * for the accessible implementation + * @get_platform_state: retrieve the accessible state + * + * The common interface for accessible objects. + * + * Since: 4.10 + */ +struct _GtkAccessibleInterface +{ + GTypeInterface g_iface; + + /** + * GtkAccessibleInterface::get_at_context: + * @self: an accessible object + * + * Retrieves the platform-specific accessibility context for the + * accessible implementation. + * + * Returns: (transfer none) (nullable): the accessibility context + * + * Since: 4.10 + */ + GtkATContext * (* get_at_context) (GtkAccessible *self); + + /** + * GtkAccessibleInterface::get_platform_state: + * @self: an accessible object + * @state: the state to query + * + * Checks if the given @state applies to the accessible object. + * + * Returns: true if the @state is set, and false otherwise + * + * Since: 4.10 + */ + gboolean (* get_platform_state) (GtkAccessible *self, + GtkAccessiblePlatformState state); + + /** + * GtkAccessibleInterface::get_accessible_parent: + * @self: an accessible object + * + * Retrieves the accessible parent of an accessible object. + * + * This virtual function should return `NULL` for top level objects. + * + * Returns: (nullable) (transfer none): the accessible parent + * + * Since: 4.10 + */ + GtkAccessible * (* get_accessible_parent) (GtkAccessible *self); + + /** + * GtkaccessibleInterface::get_first_accessible_child: + * @self: an accessible object + * + * Retrieves the first accessible child of an accessible object. + * + * Returns: (transfer none) (nullable): an accessible object + * + * Since: 4.10 + */ + GtkAccessible * (* get_first_accessible_child) (GtkAccessible *self); + + /** + * GtkaccessibleInterface::get_next_accessible_sibling: + * @self: an accessible object + * + * Retrieves the next accessible sibling of an accessible object. + * + * Returns: (transfer none) (nullable): an accessible object + * + * Since: 4.10 + */ + GtkAccessible * (* get_next_accessible_sibling) (GtkAccessible *self); + + /** + * GtkAccessibleInterface::get_bounds: + * @self: an accessible object + * @x: (out): the horizontal coordinate of a rectangle + * @y: (out): the vertical coordinate of a rectangle + * @width: (out): the width of a rectangle + * @height: (out): the height of a rectangle + * + * Retrieves the dimensions and position of an accessible object in its + * parent's coordinate space, if those values can be determined. + * + * For top level accessible objects, the X and Y coordinates are always + * going to be set to zero. + * + * Returns: true if the values are value, and false otherwise + */ + gboolean (* get_bounds) (GtkAccessible *self, + int *x, + int *y, + int *width, + int *height); +}; GDK_AVAILABLE_IN_ALL -void gtk_accessible_update_state (GtkAccessible *self, - GtkAccessibleState first_state, - ...); -GDK_AVAILABLE_IN_ALL -void gtk_accessible_update_property (GtkAccessible *self, - GtkAccessibleProperty first_property, - ...); -GDK_AVAILABLE_IN_ALL -void gtk_accessible_update_relation (GtkAccessible *self, - GtkAccessibleRelation first_relation, - ...); -GDK_AVAILABLE_IN_ALL -void gtk_accessible_update_state_value (GtkAccessible *self, - int n_states, - GtkAccessibleState states[], - const GValue values[]); -GDK_AVAILABLE_IN_ALL -void gtk_accessible_update_property_value (GtkAccessible *self, - int n_properties, - GtkAccessibleProperty properties[], - const GValue values[]); -GDK_AVAILABLE_IN_ALL -void gtk_accessible_update_relation_value (GtkAccessible *self, - int n_relations, - GtkAccessibleRelation relations[], - const GValue values[]); +GtkATContext * gtk_accessible_get_at_context (GtkAccessible *self); + +GDK_AVAILABLE_IN_4_10 +gboolean gtk_accessible_get_platform_state (GtkAccessible *self, + GtkAccessiblePlatformState state); + +GDK_AVAILABLE_IN_4_10 +GtkAccessible * gtk_accessible_get_accessible_parent (GtkAccessible *self); + +GDK_AVAILABLE_IN_4_10 +GtkAccessible * gtk_accessible_get_first_accessible_child (GtkAccessible *self); + +GDK_AVAILABLE_IN_4_10 +GtkAccessible * gtk_accessible_get_next_accessible_sibling (GtkAccessible *self); + +GDK_AVAILABLE_IN_4_10 +gboolean gtk_accessible_get_bounds (GtkAccessible *self, + int *x, + int *y, + int *width, + int *height); GDK_AVAILABLE_IN_ALL -void gtk_accessible_reset_state (GtkAccessible *self, - GtkAccessibleState state); -GDK_AVAILABLE_IN_ALL -void gtk_accessible_reset_property (GtkAccessible *self, - GtkAccessibleProperty property); -GDK_AVAILABLE_IN_ALL -void gtk_accessible_reset_relation (GtkAccessible *self, - GtkAccessibleRelation relation); +GtkAccessibleRole gtk_accessible_get_accessible_role (GtkAccessible *self); GDK_AVAILABLE_IN_ALL -void gtk_accessible_state_init_value (GtkAccessibleState state, - GValue *value); +void gtk_accessible_update_state (GtkAccessible *self, + GtkAccessibleState first_state, + ...); GDK_AVAILABLE_IN_ALL -void gtk_accessible_property_init_value (GtkAccessibleProperty property, - GValue *value); +void gtk_accessible_update_property (GtkAccessible *self, + GtkAccessibleProperty first_property, + ...); GDK_AVAILABLE_IN_ALL -void gtk_accessible_relation_init_value (GtkAccessibleRelation relation, - GValue *value); +void gtk_accessible_update_relation (GtkAccessible *self, + GtkAccessibleRelation first_relation, + ...); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_update_state_value (GtkAccessible *self, + int n_states, + GtkAccessibleState states[], + const GValue values[]); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_update_property_value (GtkAccessible *self, + int n_properties, + GtkAccessibleProperty properties[], + const GValue values[]); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_update_relation_value (GtkAccessible *self, + int n_relations, + GtkAccessibleRelation relations[], + const GValue values[]); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_reset_state (GtkAccessible *self, + GtkAccessibleState state); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_reset_property (GtkAccessible *self, + GtkAccessibleProperty property); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_reset_relation (GtkAccessible *self, + GtkAccessibleRelation relation); + +GDK_AVAILABLE_IN_ALL +void gtk_accessible_state_init_value (GtkAccessibleState state, + GValue *value); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_property_init_value (GtkAccessibleProperty property, + GValue *value); +GDK_AVAILABLE_IN_ALL +void gtk_accessible_relation_init_value (GtkAccessibleRelation relation, + GValue *value); G_END_DECLS diff --git a/gtk/gtkaccessibleprivate.h b/gtk/gtkaccessibleprivate.h index eefd30a38b..6d2f2f2125 100644 --- a/gtk/gtkaccessibleprivate.h +++ b/gtk/gtkaccessibleprivate.h @@ -21,21 +21,36 @@ #pragma once #include "gtkaccessible.h" -#include "gtkatcontextprivate.h" G_BEGIN_DECLS -struct _GtkAccessibleInterface -{ - GTypeInterface g_iface; +/* < private > + * GtkAccessiblePlatformChange: + * @GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE: whether the accessible has changed + * its focusable state + * @GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED: whether the accessible has changed its + * focused state + * @GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE: whether the accessible has changed its + * active state + * + * Represents the various platform changes which can occur and are communicated + * using [method@Gtk.Accessible.platform_changed]. + */ +typedef enum { + GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE = 1 << GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE, + GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED = 1 << GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED, + GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE = 1 << GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE, +} GtkAccessiblePlatformChange; - GtkATContext * (* get_at_context) (GtkAccessible *self); +typedef enum { + GTK_ACCESSIBLE_CHILD_STATE_ADDED, + GTK_ACCESSIBLE_CHILD_STATE_REMOVED +} GtkAccessibleChildState; - gboolean (* get_platform_state) (GtkAccessible *self, - GtkAccessiblePlatformState state); -}; - -GtkATContext * gtk_accessible_get_at_context (GtkAccessible *self); +typedef enum { + GTK_ACCESSIBLE_CHILD_CHANGE_ADDED = 1 << GTK_ACCESSIBLE_CHILD_STATE_ADDED, + GTK_ACCESSIBLE_CHILD_CHANGE_REMOVED = 1 << GTK_ACCESSIBLE_CHILD_STATE_REMOVED +} GtkAccessibleChildChange; const char * gtk_accessible_role_to_name (GtkAccessibleRole role, const char *domain); @@ -44,15 +59,13 @@ gboolean gtk_accessible_role_is_range_subclass (GtkAccessibleRole role); gboolean gtk_accessible_should_present (GtkAccessible *self); -void gtk_accessible_platform_changed (GtkAccessible *self, - GtkAccessiblePlatformChange change); -gboolean gtk_accessible_get_platform_state (GtkAccessible *self, - GtkAccessiblePlatformState state); - -void gtk_accessible_bounds_changed (GtkAccessible *self); - void gtk_accessible_update_children (GtkAccessible *self, GtkAccessible *child, GtkAccessibleChildState state); +void gtk_accessible_bounds_changed (GtkAccessible *self); + +void gtk_accessible_platform_changed (GtkAccessible *self, + GtkAccessiblePlatformChange change); + G_END_DECLS diff --git a/gtk/gtkatcontextprivate.h b/gtk/gtkatcontextprivate.h index c05c04948f..c0acfc7793 100644 --- a/gtk/gtkatcontextprivate.h +++ b/gtk/gtkatcontextprivate.h @@ -22,6 +22,7 @@ #include "gtkatcontext.h" +#include "gtkaccessibleprivate.h" #include "gtkaccessibleattributesetprivate.h" G_BEGIN_DECLS @@ -80,28 +81,6 @@ typedef enum { GTK_ACCESSIBLE_STATE_CHANGE_SELECTED = 1 << GTK_ACCESSIBLE_STATE_SELECTED } GtkAccessibleStateChange; -typedef enum { - GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE, - GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED, - GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE -} GtkAccessiblePlatformState; - -typedef enum { - GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE = 1 << GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE, - GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED = 1 << GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED, - GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE = 1 << GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE, -} GtkAccessiblePlatformChange; - -typedef enum { - GTK_ACCESSIBLE_CHILD_STATE_ADDED, - GTK_ACCESSIBLE_CHILD_STATE_REMOVED -} GtkAccessibleChildState; - -typedef enum { - GTK_ACCESSIBLE_CHILD_CHANGE_ADDED = 1 << GTK_ACCESSIBLE_CHILD_STATE_ADDED, - GTK_ACCESSIBLE_CHILD_CHANGE_REMOVED = 1 << GTK_ACCESSIBLE_CHILD_STATE_REMOVED -} GtkAccessibleChildChange; - struct _GtkATContext { GObject parent_instance; diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c index 47e7f81324..4b9ccc1aa0 100644 --- a/gtk/gtkstack.c +++ b/gtk/gtkstack.c @@ -139,7 +139,7 @@ struct _GtkStackClass { }; typedef struct { - GList *children; + GPtrArray *children; GtkStackPage *visible_child; @@ -165,9 +165,12 @@ typedef struct { } GtkStackPrivate; static void gtk_stack_buildable_interface_init (GtkBuildableIface *iface); +static void gtk_stack_accessible_init (GtkAccessibleInterface *iface); G_DEFINE_TYPE_WITH_CODE (GtkStack, gtk_stack, GTK_TYPE_WIDGET, G_ADD_PRIVATE (GtkStack) + G_IMPLEMENT_INTERFACE (GTK_TYPE_ACCESSIBLE, + gtk_stack_accessible_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_stack_buildable_interface_init)) enum { @@ -209,6 +212,8 @@ struct _GtkStackPage char *icon_name; GtkWidget *last_focus; + GtkStackPage *next_page; + GtkATContext *at_context; guint needs_attention : 1; @@ -253,11 +258,59 @@ gtk_stack_page_accessible_get_platform_state (GtkAccessible *self, return FALSE; } +static GtkAccessible * +gtk_stack_page_accessible_get_accessible_parent (GtkAccessible *accessible) +{ + GtkStackPage *page = GTK_STACK_PAGE (accessible); + + if (page->widget == NULL) + return NULL; + else + return GTK_ACCESSIBLE (gtk_widget_get_parent (page->widget)); +} + +static GtkAccessible * +gtk_stack_page_accessible_get_first_accessible_child(GtkAccessible *accessible) +{ + GtkStackPage *page = GTK_STACK_PAGE (accessible); + + if (page->widget != NULL) + return GTK_ACCESSIBLE (page->widget); + else + return NULL; +} + +static GtkAccessible * +gtk_stack_page_accessible_get_next_accessible_sibling(GtkAccessible *accessible) +{ + GtkStackPage *page = GTK_STACK_PAGE (accessible); + + return GTK_ACCESSIBLE (page->next_page); +} + +static gboolean +gtk_stack_page_accessible_get_bounds (GtkAccessible *accessible, + int *x, + int *y, + int *width, + int *height) +{ + GtkStackPage *page = GTK_STACK_PAGE (accessible); + if (page->widget != NULL) + return gtk_accessible_get_bounds (GTK_ACCESSIBLE (page->widget), x, y, width, height); + else + return FALSE; +} + static void gtk_stack_page_accessible_init (GtkAccessibleInterface *iface) { iface->get_at_context = gtk_stack_page_accessible_get_at_context; iface->get_platform_state = gtk_stack_page_accessible_get_platform_state; + iface->get_accessible_parent = gtk_stack_page_accessible_get_accessible_parent; + iface->get_first_accessible_child = gtk_stack_page_accessible_get_first_accessible_child; + iface->get_next_accessible_sibling = gtk_stack_page_accessible_get_next_accessible_sibling; + iface->get_bounds = gtk_stack_page_accessible_get_bounds; } G_DEFINE_TYPE_WITH_CODE (GtkStackPage, gtk_stack_page, G_TYPE_OBJECT, @@ -534,7 +587,7 @@ gtk_stack_pages_get_n_items (GListModel *model) GtkStackPages *pages = GTK_STACK_PAGES (model); GtkStackPrivate *priv = gtk_stack_get_instance_private (pages->stack); - return g_list_length (priv->children); + return priv->children->len; } static gpointer @@ -545,11 +598,12 @@ gtk_stack_pages_get_item (GListModel *model, GtkStackPrivate *priv = gtk_stack_get_instance_private (pages->stack); GtkStackPage *page; - page = g_list_nth_data (priv->children, position); - if (!page) + if (position > priv->children->len - 1) return NULL; + page = g_ptr_array_index (priv->children, position); + return g_object_ref (page); } @@ -569,9 +623,12 @@ gtk_stack_pages_is_selected (GtkSelectionModel *model, GtkStackPrivate *priv = gtk_stack_get_instance_private (pages->stack); GtkStackPage *page; - page = g_list_nth_data (priv->children, position); + if (position > priv->children->len - 1) + return FALSE; - return page && page == priv->visible_child; + page = g_ptr_array_index (priv->children, position); + + return page == priv->visible_child; } static void set_visible_child (GtkStack *stack, @@ -588,7 +645,7 @@ gtk_stack_pages_select_item (GtkSelectionModel *model, GtkStackPrivate *priv = gtk_stack_get_instance_private (pages->stack); GtkStackPage *page; - page = g_list_nth_data (priv->children, position); + page = g_ptr_array_index (priv->children, position); set_visible_child (pages->stack, page, priv->transition_type, priv->transition_duration); @@ -728,6 +785,21 @@ gtk_stack_buildable_interface_init (GtkBuildableIface *iface) iface->add_child = gtk_stack_buildable_add_child; } +static GtkAccessible * +gtk_stack_accessible_get_first_accessible_child (GtkAccessible *accessible) +{ + GtkStack *stack = GTK_STACK (accessible); + GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); + GtkStackPage *page = g_ptr_array_index (priv->children, 0); + return GTK_ACCESSIBLE (page); +} + +static void +gtk_stack_accessible_init (GtkAccessibleInterface *iface) +{ + iface->get_first_accessible_child = gtk_stack_accessible_get_first_accessible_child; +} + static void stack_remove (GtkStack *stack, GtkWidget *child, gboolean in_dispose); @@ -738,7 +810,7 @@ gtk_stack_dispose (GObject *obj) GtkStack *stack = GTK_STACK (obj); GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); GtkWidget *child; - guint n_pages = g_list_length (priv->children); + guint n_pages = priv->children->len; while ((child = gtk_widget_get_first_child (GTK_WIDGET (stack)))) stack_remove (stack, child, TRUE); @@ -763,6 +835,8 @@ gtk_stack_finalize (GObject *obj) gtk_stack_unschedule_ticks (stack); + g_ptr_array_free (priv->children, TRUE); + G_OBJECT_CLASS (gtk_stack_parent_class)->finalize (obj); } @@ -978,11 +1052,11 @@ find_child_info_for_widget (GtkStack *stack, { GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); GtkStackPage *info; - GList *l; + guint idx; - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - info = l->data; + info = g_ptr_array_index (priv->children, idx); if (info->widget == child) return info; } @@ -1297,7 +1371,7 @@ set_visible_child (GtkStack *stack, GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); GtkStackPage *info; GtkWidget *widget = GTK_WIDGET (stack); - GList *l; + guint idx; GtkWidget *focus; gboolean contains_focus = FALSE; guint old_pos = GTK_INVALID_LIST_POSITION; @@ -1312,9 +1386,9 @@ set_visible_child (GtkStack *stack, /* If none, pick first visible */ if (child_info == NULL) { - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - info = l->data; + info = g_ptr_array_index (priv->children, idx); if (gtk_widget_get_visible (info->widget)) { child_info = info; @@ -1329,9 +1403,9 @@ set_visible_child (GtkStack *stack, if (priv->pages) { guint position; - for (l = priv->children, position = 0; l != NULL; l = l->next, position++) + for (idx = 0, position = 0; idx < priv->children->len; idx++, position++) { - info = l->data; + info = g_ptr_array_index (priv->children, idx); if (info == priv->visible_child) old_pos = position; else if (info == child_info) @@ -1399,14 +1473,14 @@ set_visible_child (GtkStack *stack, else if (is_direction_dependent_transition (transition_type)) { gboolean i_first = FALSE; - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - if (child_info == l->data) + if (child_info == g_ptr_array_index (priv->children, idx)) { i_first = TRUE; break; } - if (priv->last_visible_child == l->data) + if (priv->last_visible_child == g_ptr_array_index (priv->children, idx)) break; } @@ -1575,15 +1649,15 @@ gtk_stack_add_page (GtkStack *stack, GtkStackPage *child_info) { GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); - GList *l; + guint idx; g_return_if_fail (child_info->widget != NULL); if (child_info->name) { - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - GtkStackPage *info = l->data; + GtkStackPage *info = g_ptr_array_index (priv->children, idx); if (info->name && g_strcmp0 (info->name, child_info->name) == 0) { @@ -1593,14 +1667,26 @@ gtk_stack_add_page (GtkStack *stack, } } - priv->children = g_list_append (priv->children, g_object_ref (child_info)); + + if (priv->children->len > 0) + { + GtkStackPage *prev_last = g_ptr_array_index (priv->children, priv->children->len - 1); + + prev_last->next_page = child_info; + } + else + { + child_info->next_page = NULL; + } + + g_ptr_array_add (priv->children, g_object_ref (child_info)); gtk_widget_set_child_visible (child_info->widget, FALSE); gtk_widget_set_parent (child_info->widget, GTK_WIDGET (stack)); if (priv->pages) { - g_list_model_items_changed (G_LIST_MODEL (priv->pages), g_list_length (priv->children) - 1, 0, 1); + g_list_model_items_changed (G_LIST_MODEL (priv->pages), priv->children->len - 1, 0, 1); g_object_notify_by_pspec (G_OBJECT (priv->pages), pages_properties[PAGES_PROP_N_ITEMS]); } @@ -1644,7 +1730,17 @@ stack_remove (GtkStack *stack, g_clear_object (&child_info->widget); - priv->children = g_list_remove (priv->children, child_info); + g_ptr_array_remove (priv->children, child_info); + + for (guint prev_idx = 0; prev_idx < priv->children->len; prev_idx++) + { + GtkStackPage *prev_page = g_ptr_array_index (priv->children, prev_idx); + if (prev_page->next_page == child_info) + { + prev_page->next_page = child_info->next_page; + break; + } + } g_object_unref (child_info); @@ -1666,16 +1762,15 @@ gtk_stack_remove (GtkStack *stack, GtkWidget *child) { GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); - GList *l; guint position; g_return_if_fail (GTK_IS_STACK (stack)); g_return_if_fail (GTK_IS_WIDGET (child)); g_return_if_fail (gtk_widget_get_parent (child) == GTK_WIDGET (stack)); - for (l = priv->children, position = 0; l; l = l->next, position++) + for (position = 0; position < priv->children->len; position++) { - GtkStackPage *page = l->data; + GtkStackPage *page = g_ptr_array_index (priv->children, position); if (page->widget == child) break; } @@ -1723,14 +1818,14 @@ gtk_stack_get_child_by_name (GtkStack *stack, { GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); GtkStackPage *info; - GList *l; + guint idx; g_return_val_if_fail (GTK_IS_STACK (stack), NULL); g_return_val_if_fail (name != NULL, NULL); - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - info = l->data; + info = g_ptr_array_index (priv->children, idx); if (info->name && strcmp (info->name, name) == 0) return info->widget; } @@ -2141,7 +2236,7 @@ gtk_stack_set_visible_child_full (GtkStack *stack, { GtkStackPrivate *priv = gtk_stack_get_instance_private (stack); GtkStackPage *child_info, *info; - GList *l; + guint idx; g_return_if_fail (GTK_IS_STACK (stack)); @@ -2149,9 +2244,9 @@ gtk_stack_set_visible_child_full (GtkStack *stack, return; child_info = NULL; - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - info = l->data; + info = g_ptr_array_index (priv->children, idx); if (info->name != NULL && strcmp (info->name, name) == 0) { @@ -2180,13 +2275,13 @@ gtk_stack_compute_expand (GtkWidget *widget, gboolean hexpand, vexpand; GtkStackPage *child_info; GtkWidget *child; - GList *l; + guint idx; hexpand = FALSE; vexpand = FALSE; - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - child_info = l->data; + child_info = g_ptr_array_index (priv->children, idx); child = child_info->widget; if (!hexpand && @@ -2618,14 +2713,14 @@ gtk_stack_measure (GtkWidget *widget, GtkStackPage *child_info; GtkWidget *child; int child_min, child_nat; - GList *l; + guint idx; *minimum = 0; *natural = 0; - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - child_info = l->data; + child_info = g_ptr_array_index (priv->children, idx); child = child_info->widget; if (!priv->homogeneous[orientation] && @@ -2674,6 +2769,7 @@ gtk_stack_init (GtkStack *stack) priv->homogeneous[GTK_ORIENTATION_HORIZONTAL] = TRUE; priv->transition_duration = 200; priv->transition_type = GTK_STACK_TRANSITION_TYPE_NONE; + priv->children = g_ptr_array_new(); } /** @@ -2855,14 +2951,14 @@ gtk_stack_page_set_name (GtkStackPage *self, gtk_widget_get_parent (self->widget) && GTK_IS_STACK (gtk_widget_get_parent (self->widget))) { - GList *l; + guint idx; stack = GTK_STACK (gtk_widget_get_parent (self->widget)); priv = gtk_stack_get_instance_private (stack); - for (l = priv->children; l != NULL; l = l->next) + for (idx = 0; idx < priv->children->len; idx++) { - GtkStackPage *info2 = l->data; + GtkStackPage *info2 = g_ptr_array_index (priv->children, idx); if (self == info2) continue; diff --git a/gtk/gtktypes.h b/gtk/gtktypes.h index 71afde94b0..36084c036d 100644 --- a/gtk/gtktypes.h +++ b/gtk/gtktypes.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS typedef struct _GtkAdjustment GtkAdjustment; +typedef struct _GtkATContext GtkATContext; typedef struct _GtkBitset GtkBitset; typedef struct _GtkBuilder GtkBuilder; typedef struct _GtkBuilderScope GtkBuilderScope; diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 72582aeb6a..ab75402d8c 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -8465,11 +8465,78 @@ gtk_widget_accessible_get_platform_state (GtkAccessible *self, } } +static GtkAccessible * +gtk_widget_accessible_get_accessible_parent (GtkAccessible *self) +{ + return GTK_ACCESSIBLE (gtk_widget_get_parent (GTK_WIDGET (self))); +} + +static GtkAccessible * +gtk_widget_accessible_get_next_accessible_sibling (GtkAccessible *self) +{ + return GTK_ACCESSIBLE (gtk_widget_get_next_sibling (GTK_WIDGET (self))); +} + +static GtkAccessible * +gtk_widget_accessible_get_first_accessible_child (GtkAccessible *self) +{ + return GTK_ACCESSIBLE (gtk_widget_get_first_child (GTK_WIDGET (self))); +} + +static gboolean +gtk_widget_accessible_get_bounds (GtkAccessible *self, + int *x, + int *y, + int *width, + int *height) +{ + GtkWidget *widget; + GtkWidget *parent; + GtkWidget *bounds_relative_to; + double translated_x, translated_y; + graphene_rect_t bounds = GRAPHENE_RECT_INIT_ZERO; + + widget = GTK_WIDGET (self); + if (!gtk_widget_get_realized (widget)) + return FALSE; + + parent = gtk_widget_get_parent (widget); + if (parent != NULL) + { + gtk_widget_translate_coordinates (widget, parent, 0., 0., &translated_x, &translated_y); + *x = floorf (translated_x); + *y = floorf (translated_y); + bounds_relative_to = parent; + } + else + { + *x = *y = 0; + bounds_relative_to = widget; + } + + if (!gtk_widget_compute_bounds (widget, bounds_relative_to, &bounds)) + { + *width = 0; + *height = 0; + } + else + { + *width = ceilf (graphene_rect_get_width (&bounds)); + *height = ceilf (graphene_rect_get_height (&bounds)); + } + + return TRUE; +} + static void gtk_widget_accessible_interface_init (GtkAccessibleInterface *iface) { iface->get_at_context = gtk_widget_accessible_get_at_context; iface->get_platform_state = gtk_widget_accessible_get_platform_state; + iface->get_accessible_parent = gtk_widget_accessible_get_accessible_parent; + iface->get_first_accessible_child = gtk_widget_accessible_get_first_accessible_child; + iface->get_next_accessible_sibling = gtk_widget_accessible_get_next_accessible_sibling; + iface->get_bounds = gtk_widget_accessible_get_bounds; } static void diff --git a/gtk/inspector/a11y.c b/gtk/inspector/a11y.c index 5c506e24cc..f184489204 100644 --- a/gtk/inspector/a11y.c +++ b/gtk/inspector/a11y.c @@ -236,7 +236,14 @@ update_path (GtkInspectorA11y *sl) context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (sl->object)); if (GTK_IS_AT_SPI_CONTEXT (context)) - path = gtk_at_spi_context_get_context_path (GTK_AT_SPI_CONTEXT (context)); + { + if (gtk_at_context_is_realized (context)) + path = gtk_at_spi_context_get_context_path (GTK_AT_SPI_CONTEXT (context)); + else + path = "not realized"; + } + else + path = "not on bus"; #endif gtk_label_set_label (GTK_LABEL (sl->path), path); @@ -422,7 +429,7 @@ gtk_inspector_a11y_set_object (GtkInspectorA11y *sl, stack = gtk_widget_get_parent (GTK_WIDGET (sl)); page = gtk_stack_get_page (GTK_STACK (stack), GTK_WIDGET (sl)); - if (GTK_IS_ACCESSIBLE (object)) + if (GTK_IS_ACCESSIBLE (sl->object)) { context = gtk_accessible_get_at_context (GTK_ACCESSIBLE (sl->object)); if (context)