summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2020-10-22 02:52:46 +0000
committerMatthias Clasen <mclasen@redhat.com>2020-10-22 02:52:46 +0000
commitdaf3b3a3b4cc70c5db278fd7142a6b49af91ae1d (patch)
tree23d317eccfeec9fdd1188e19e779fc5919270c11
parentb5b8f42a0c6ac94722c62a27c0635b6484f5d72d (diff)
parent800eb76a2de85b4e1844b28b50d440602bf9c4f8 (diff)
downloadgtk+-daf3b3a3b4cc70c5db278fd7142a6b49af91ae1d.tar.gz
Merge branch 'matthiasc/for-master' into 'master'
Matthiasc/for master See merge request GNOME/gtk!2734
-rw-r--r--docs/reference/gtk/migrating-3to4.md8
-rw-r--r--docs/reference/gtk/section-accessibility.md19
-rw-r--r--gtk/a11y/gtkatspiaction.c4
-rw-r--r--gtk/gtkaccessible.c3
-rw-r--r--gtk/gtkenums.h35
-rw-r--r--gtk/gtklevelbar.c17
-rw-r--r--gtk/gtklinkbutton.c4
-rw-r--r--gtk/gtkmenubutton.c38
-rw-r--r--gtk/gtkmodelbutton.c98
-rw-r--r--gtk/gtkpopovermenu.c19
-rw-r--r--gtk/gtkpopovermenubar.c43
-rw-r--r--gtk/gtkprogressbar.c18
-rw-r--r--gtk/gtkscale.c26
-rw-r--r--gtk/gtkseparator.c3
-rw-r--r--gtk/gtkswitch.c14
-rw-r--r--testsuite/a11y/button.c2
16 files changed, 281 insertions, 70 deletions
diff --git a/docs/reference/gtk/migrating-3to4.md b/docs/reference/gtk/migrating-3to4.md
index 44f7d785b9..7a70e21bc0 100644
--- a/docs/reference/gtk/migrating-3to4.md
+++ b/docs/reference/gtk/migrating-3to4.md
@@ -264,6 +264,14 @@ therefore can no longer be used to break reference cycles. A typical sign
of a reference cycle involving a toplevel window is when closing the window
does not make the application quit.
+A good rule to follow is: If you set a widget pointer with
+gtk_widget_class_bind_template_child() in class_init(), you need to
+unparent it in dispose(). The slight complication here is that you need
+to respect the widget hierarchy while doing so. Ie if you set both `field1`
+and `field2`, but `field1` is an ancestor of `field2`, then you only need
+to unparent `field1` — doing so will remove the the entire subtree below
+`field1`, including `field2`.
+
### Stop using GdkScreen
The GdkScreen object has been removed in GTK 4. Most of its APIs already
diff --git a/docs/reference/gtk/section-accessibility.md b/docs/reference/gtk/section-accessibility.md
index 3afb747026..c86eb3c3c1 100644
--- a/docs/reference/gtk/section-accessibility.md
+++ b/docs/reference/gtk/section-accessibility.md
@@ -54,9 +54,16 @@ Each role name is part of the #GtkAccessibleRole enumeration.
| `GRID_CELL` | An item in a grid | #GtkFlowBoxChild, #GtkGridView, #GtkColumnView |
| `IMG` | An image | #GtkImage, #GtkPicture |
| `LABEL` | A visible name or caption for a user interface component | #GtkLabel |
+| `LINK` | A clickable hyperlink | #GtkLinkButton |
| `LIST` | A list of items | #GtkListBox |
| `LIST_ITEM` | An item in a list | #GtkListBoxRow |
+| `MENU` | A menu | #GtkPopoverMenu |
+| `MENU_BAR` | A menubar | #GtkPopoverMenuBar |
+| `MENU_ITEM` | A menu item | Items in #GtkPopoverMenu |
+| `MENU_ITEM_CHECKBOX` | Check menu item | Items in #GtkPopoverMenu |
+| `MENU_ITEM_RADIO` | Radio menu item | Items in #GtkPopoverMenu |
| `METER` | Represents a value within a known range | #GtkLevelBar |
+| `NONE` | Not represented in the accessibility tree | the slider of a #GtkScale |
| `PROGRESS_BAR` | An element that display progress | #GtkProgressBar |
| `RADIO` | A checkable input in a group of radio roles | #GtkCheckButton |
| `ROW` | A row in a columned list | #GtkColumnView |
@@ -106,9 +113,9 @@ for instance:
See the [WAI-ARIA](https://www.w3.org/WAI/PF/aria/appendices#quickref) list
of attributes for additional information.
-#### List of accessible properties
+#### List of accessible states
-Each state name is part of the #GtkAccessibleProperty enumeration.
+Each state name is part of the #GtkAccessibleState enumeration.
| State name | ARIA attribute | Value type | Notes |
|------------|----------------|------------|-------|
@@ -121,9 +128,9 @@ Each state name is part of the #GtkAccessibleProperty enumeration.
| %GTK_ACCESSIBLE_STATE_PRESSED | “aria-pressed” | #GtkAccessibleTristate | Indicates the current state of a #GtkToggleButton |
| %GTK_ACCESSIBLE_STATE_SELECTED | “aria-selected” | boolean or undefined | Set when a widget is selected |
-#### List of accessible relations
+#### List of accessible properties
-Each state name is part of the #GtkAccessibleRelation enumeration.
+Each property name is part of the #GtkAccessibleProperty enumeration.
| State name | ARIA attribute | Value type |
|------------|----------------|------------|
@@ -147,9 +154,9 @@ Each state name is part of the #GtkAccessibleRelation enumeration.
| %GTK_ACCESSIBLE_PROPERTY_VALUE_NOW | “aria-valuenow” | double |
| %GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT | “aria-valuetext” | translatable string |
-#### List of accessible states
+#### List of accessible relations
-Each state name is part of the #GtkAccessibleState enumeration.
+Each relation name is part of the #GtkAccessibleRelation enumeration.
| State name | ARIA attribute | Value type |
|------------|----------------|------------|
diff --git a/gtk/a11y/gtkatspiaction.c b/gtk/a11y/gtkatspiaction.c
index 2c28c0fbbd..42392a00f3 100644
--- a/gtk/a11y/gtkatspiaction.c
+++ b/gtk/a11y/gtkatspiaction.c
@@ -32,6 +32,7 @@
#include "gtkbutton.h"
#include "gtkentryprivate.h"
#include "gtkexpander.h"
+#include "gtkmodelbuttonprivate.h"
#include "gtkpasswordentryprivate.h"
#include "gtkswitch.h"
#include "gtkwidgetprivate.h"
@@ -810,7 +811,8 @@ static const GDBusInterfaceVTable widget_action_vtable = {
const GDBusInterfaceVTable *
gtk_atspi_get_action_vtable (GtkAccessible *accessible)
{
- if (GTK_IS_BUTTON (accessible))
+ if (GTK_IS_BUTTON (accessible) ||
+ GTK_IS_MODEL_BUTTON (accessible))
return &button_action_vtable;
else if (GTK_IS_ENTRY (accessible))
return &entry_action_vtable;
diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c
index bef2ced14e..a98bd90ae2 100644
--- a/gtk/gtkaccessible.c
+++ b/gtk/gtkaccessible.c
@@ -746,7 +746,8 @@ gtk_accessible_should_present (GtkAccessible *self)
!gtk_widget_get_visible (GTK_WIDGET (self)))
return FALSE;
- if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE)
+ if (gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_NONE ||
+ gtk_accessible_get_accessible_role (self) == GTK_ACCESSIBLE_ROLE_PRESENTATION)
return FALSE;
return TRUE;
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index 561a273b59..9a64124c49 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -1165,9 +1165,8 @@ typedef enum {
* @GTK_ACCESSIBLE_ROLE_COMBO_BOX: An input that controls another element,
* such as a list or a grid, that can dynamically pop up to help the user
* set the value of the input
- * @GTK_ACCESSIBLE_ROLE_COMMAND: An abstract widget that performs an
- * action, but does not receive input
- * @GTK_ACCESSIBLE_ROLE_COMPOSITE: Unused
+ * @GTK_ACCESSIBLE_ROLE_COMMAND: Abstract role.
+ * @GTK_ACCESSIBLE_ROLE_COMPOSITE: Abstract role.
* @GTK_ACCESSIBLE_ROLE_DIALOG: A dialog is a window that is designed to interrupt
* the current processing of an application in order to prompt the user to enter
* information or require a response.
@@ -1180,11 +1179,11 @@ typedef enum {
* @GTK_ACCESSIBLE_ROLE_GROUP: Unused
* @GTK_ACCESSIBLE_ROLE_HEADING: Unused
* @GTK_ACCESSIBLE_ROLE_IMG: An image.
- * @GTK_ACCESSIBLE_ROLE_INPUT: Unused
+ * @GTK_ACCESSIBLE_ROLE_INPUT: Abstract role.
* @GTK_ACCESSIBLE_ROLE_LABEL: A visible name or caption for a user interface component.
- * @GTK_ACCESSIBLE_ROLE_LANDMARK: Unused
+ * @GTK_ACCESSIBLE_ROLE_LANDMARK: Abstract role.
* @GTK_ACCESSIBLE_ROLE_LEGEND: Unused
- * @GTK_ACCESSIBLE_ROLE_LINK: Unused
+ * @GTK_ACCESSIBLE_ROLE_LINK: A clickable link.
* @GTK_ACCESSIBLE_ROLE_LIST: A list of items.
* @GTK_ACCESSIBLE_ROLE_LIST_BOX: Unused.
* @GTK_ACCESSIBLE_ROLE_LIST_ITEM: An item in a list.
@@ -1193,22 +1192,22 @@ typedef enum {
* @GTK_ACCESSIBLE_ROLE_MARQUEE: Unused
* @GTK_ACCESSIBLE_ROLE_MATH: Unused
* @GTK_ACCESSIBLE_ROLE_METER: An element that represents a value within a known range.
- * @GTK_ACCESSIBLE_ROLE_MENU: Unused
- * @GTK_ACCESSIBLE_ROLE_MENU_BAR: Unused
- * @GTK_ACCESSIBLE_ROLE_MENU_ITEM: Unused
- * @GTK_ACCESSIBLE_ROLE_MENU_ITEM_CHECKBOX: Unused
- * @GTK_ACCESSIBLE_ROLE_MENU_ITEM_RADIO: Unused
+ * @GTK_ACCESSIBLE_ROLE_MENU: A menu.
+ * @GTK_ACCESSIBLE_ROLE_MENU_BAR: A menubar.
+ * @GTK_ACCESSIBLE_ROLE_MENU_ITEM: An item in a menu.
+ * @GTK_ACCESSIBLE_ROLE_MENU_ITEM_CHECKBOX: A check item in a menu.
+ * @GTK_ACCESSIBLE_ROLE_MENU_ITEM_RADIO: A radio item in a menu.
* @GTK_ACCESSIBLE_ROLE_NAVIGATION: Unused
- * @GTK_ACCESSIBLE_ROLE_NONE: Unused
+ * @GTK_ACCESSIBLE_ROLE_NONE: An element that is not represented to accessibility technologies.
* @GTK_ACCESSIBLE_ROLE_NOTE: Unused
* @GTK_ACCESSIBLE_ROLE_OPTION: Unused
- * @GTK_ACCESSIBLE_ROLE_PRESENTATION: Unused
+ * @GTK_ACCESSIBLE_ROLE_PRESENTATION: An element that is not represented to accessibility technologies.
* @GTK_ACCESSIBLE_ROLE_PROGRESS_BAR: An element that displays the progress
* status for tasks that take a long time.
* @GTK_ACCESSIBLE_ROLE_RADIO: A checkable input in a group of radio roles,
* only one of which can be checked at a time.
* @GTK_ACCESSIBLE_ROLE_RADIO_GROUP: Unused
- * @GTK_ACCESSIBLE_ROLE_RANGE: Unused
+ * @GTK_ACCESSIBLE_ROLE_RANGE: Abstract role.
* @GTK_ACCESSIBLE_ROLE_REGION: Unused
* @GTK_ACCESSIBLE_ROLE_ROW: A row in a columned list.
* @GTK_ACCESSIBLE_ROLE_ROW_GROUP: Unused
@@ -1219,9 +1218,9 @@ typedef enum {
* @GTK_ACCESSIBLE_ROLE_SEARCH: Unused
* @GTK_ACCESSIBLE_ROLE_SEARCH_BOX: A type of textbox intended for specifying
* search criteria.
- * @GTK_ACCESSIBLE_ROLE_SECTION: Unused
- * @GTK_ACCESSIBLE_ROLE_SECTION_HEAD: Unused
- * @GTK_ACCESSIBLE_ROLE_SELECT: Unused
+ * @GTK_ACCESSIBLE_ROLE_SECTION: Abstract role.
+ * @GTK_ACCESSIBLE_ROLE_SECTION_HEAD: Abstract role.
+ * @GTK_ACCESSIBLE_ROLE_SELECT: Abstract role.
* @GTK_ACCESSIBLE_ROLE_SEPARATOR: A divider that separates and distinguishes
* sections of content or groups of menuitems.
* @GTK_ACCESSIBLE_ROLE_SLIDER: A user input where the user selects a value
@@ -1229,7 +1228,7 @@ typedef enum {
* @GTK_ACCESSIBLE_ROLE_SPIN_BUTTON: A form of range that expects the user to
* select from among discrete choices.
* @GTK_ACCESSIBLE_ROLE_STATUS: Unused
- * @GTK_ACCESSIBLE_ROLE_STRUCTURE: Unused
+ * @GTK_ACCESSIBLE_ROLE_STRUCTURE: Abstract role.
* @GTK_ACCESSIBLE_ROLE_SWITCH: A type of checkbox that represents on/off values,
* as opposed to checked/unchecked values.
* @GTK_ACCESSIBLE_ROLE_TAB: An item in a list of tab used for switching pages.
diff --git a/gtk/gtklevelbar.c b/gtk/gtklevelbar.c
index 5c005e1262..a62968b3f1 100644
--- a/gtk/gtklevelbar.c
+++ b/gtk/gtklevelbar.c
@@ -540,7 +540,9 @@ update_block_nodes (GtkLevelBar *self)
self->block_widget = g_renew (GtkWidget*, self->block_widget, n_blocks);
for (i = self->n_blocks; i < n_blocks; i++)
{
- self->block_widget[i] = gtk_gizmo_new ("block", NULL, NULL, NULL, NULL, NULL, NULL);
+ self->block_widget[i] = gtk_gizmo_new_with_role ("block",
+ GTK_ACCESSIBLE_ROLE_NONE,
+ NULL, NULL, NULL, NULL, NULL, NULL);
gtk_widget_insert_before (self->block_widget[i], GTK_WIDGET (self->trough_widget), NULL);
}
self->n_blocks = n_blocks;
@@ -1024,12 +1026,13 @@ gtk_level_bar_init (GtkLevelBar *self)
self->inverted = FALSE;
- self->trough_widget = gtk_gizmo_new ("trough",
- gtk_level_bar_measure_trough,
- gtk_level_bar_allocate_trough,
- gtk_level_bar_render_trough,
- NULL,
- NULL, NULL);
+ self->trough_widget = gtk_gizmo_new_with_role ("trough",
+ GTK_ACCESSIBLE_ROLE_NONE,
+ gtk_level_bar_measure_trough,
+ gtk_level_bar_allocate_trough,
+ gtk_level_bar_render_trough,
+ NULL,
+ NULL, NULL);
gtk_widget_set_parent (self->trough_widget, GTK_WIDGET (self));
gtk_level_bar_ensure_offset (self, GTK_LEVEL_BAR_OFFSET_LOW, 0.25);
diff --git a/gtk/gtklinkbutton.c b/gtk/gtklinkbutton.c
index 53a01cc207..e3baf93bc6 100644
--- a/gtk/gtklinkbutton.c
+++ b/gtk/gtklinkbutton.c
@@ -50,7 +50,7 @@
*
* # Accessibility
*
- * GtkLinkButton uses the #GTK_ACCESSIBLE_ROLE_BUTTON role.
+ * GtkLinkButton uses the #GTK_ACCESSIBLE_ROLE_LINK role.
*/
#include "config.h"
@@ -220,7 +220,7 @@ gtk_link_button_class_init (GtkLinkButtonClass *klass)
G_TYPE_BOOLEAN, 0);
gtk_widget_class_set_css_name (widget_class, I_("button"));
- gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON);
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_LINK);
/**
* GtkLinkButton|clipboard.copy:
diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c
index 3ed2e7af2e..4807be3994 100644
--- a/gtk/gtkmenubutton.c
+++ b/gtk/gtkmenubutton.c
@@ -106,6 +106,10 @@
*
* GtkMenuButton has a single CSS node with name button. To differentiate
* it from a plain #GtkButton, it gets the .popup style class.
+ *
+ * # Accessibility
+ *
+ * GtkMenuButton uses the #GTK_ACCESSIBLE_ROLE_BUTTON role.
*/
#include "config.h"
@@ -269,9 +273,18 @@ gtk_menu_button_toggled (GtkMenuButton *self)
if (self->popover)
{
if (active)
- gtk_popover_popup (GTK_POPOVER (self->popover));
+ {
+ gtk_popover_popup (GTK_POPOVER (self->popover));
+ gtk_accessible_update_state (GTK_ACCESSIBLE (self),
+ GTK_ACCESSIBLE_STATE_EXPANDED, TRUE,
+ -1);
+ }
else
- gtk_popover_popdown (GTK_POPOVER (self->popover));
+ {
+ gtk_popover_popdown (GTK_POPOVER (self->popover));
+ gtk_accessible_reset_state (GTK_ACCESSIBLE (self),
+ GTK_ACCESSIBLE_STATE_EXPANDED);
+ }
}
}
@@ -417,6 +430,7 @@ gtk_menu_button_class_init (GtkMenuButtonClass *klass)
g_object_class_install_properties (gobject_class, LAST_PROP, menu_button_props);
gtk_widget_class_set_css_name (widget_class, I_("menubutton"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON);
}
static void
@@ -495,9 +509,23 @@ gtk_menu_button_new (void)
static void
update_sensitivity (GtkMenuButton *self)
{
- gtk_widget_set_sensitive (self->button,
- self->popover != NULL ||
- self->create_popup_func != NULL);
+ gboolean has_popup;
+
+ has_popup = self->popover != NULL || self->create_popup_func != NULL;
+
+ gtk_widget_set_sensitive (self->button, has_popup);
+
+ gtk_accessible_update_property (GTK_ACCESSIBLE (self),
+ GTK_ACCESSIBLE_PROPERTY_HAS_POPUP, has_popup,
+ -1);
+ if (self->popover != NULL)
+ gtk_accessible_update_relation (GTK_ACCESSIBLE (self),
+ GTK_ACCESSIBLE_RELATION_CONTROLS,
+ g_list_append (NULL, self->popover),
+ -1);
+ else
+ gtk_accessible_reset_relation (GTK_ACCESSIBLE (self),
+ GTK_ACCESSIBLE_RELATION_CONTROLS);
}
static gboolean
diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c
index 93f9d011fc..31d0bf10c5 100644
--- a/gtk/gtkmodelbutton.c
+++ b/gtk/gtkmodelbutton.c
@@ -45,6 +45,7 @@
#include "gtkshortcuttrigger.h"
#include "gtkshortcutcontroller.h"
#include "gtkshortcut.h"
+#include "gtkaccessibleprivate.h"
/**
* SECTION:gtkmodelbutton
@@ -175,6 +176,8 @@ struct _GtkModelButton
guint open_timeout;
GtkEventController *controller;
+ GtkATContext *at_context;
+
guint active : 1;
guint centered : 1;
guint iconic : 1;
@@ -190,7 +193,11 @@ struct _GtkModelButtonClass
};
static void gtk_model_button_actionable_iface_init (GtkActionableInterface *iface);
+
+static void gtk_model_button_accessible_iface_init (GtkAccessibleInterface *iface);
+
G_DEFINE_TYPE_WITH_CODE (GtkModelButton, gtk_model_button, GTK_TYPE_WIDGET,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_ACCESSIBLE, gtk_model_button_accessible_iface_init)
G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_model_button_actionable_iface_init))
GType
@@ -295,6 +302,50 @@ gtk_model_button_actionable_iface_init (GtkActionableInterface *iface)
iface->set_action_target_value = gtk_model_button_set_action_target_value;
}
+static GtkATContext *
+create_at_context (GtkModelButton *button)
+{
+ GdkDisplay *display = _gtk_widget_get_display (GTK_WIDGET (button));
+ GtkAccessibleRole role;
+
+ switch (button->role)
+ {
+ default:
+ case GTK_BUTTON_ROLE_NORMAL:
+ case GTK_BUTTON_ROLE_TITLE:
+ role = GTK_ACCESSIBLE_ROLE_MENU_ITEM;
+ break;
+ case GTK_BUTTON_ROLE_CHECK:
+ role = GTK_ACCESSIBLE_ROLE_MENU_ITEM_CHECKBOX;
+ break;
+ case GTK_BUTTON_ROLE_RADIO:
+ role = GTK_ACCESSIBLE_ROLE_MENU_ITEM_RADIO;
+ break;
+ }
+
+ return gtk_at_context_create (role, GTK_ACCESSIBLE (button), display);
+}
+
+static GtkATContext *
+gtk_model_button_get_at_context (GtkAccessible *accessible)
+{
+ GtkModelButton *button = GTK_MODEL_BUTTON (accessible);
+
+ if (button->at_context == NULL)
+ button->at_context = create_at_context (button);
+
+ return button->at_context;
+}
+
+static void
+gtk_model_button_accessible_iface_init (GtkAccessibleInterface *iface)
+{
+ GtkAccessibleInterface *parent_iface = g_type_interface_peek_parent (iface);
+
+ iface->get_at_context = gtk_model_button_get_at_context;
+ iface->get_platform_state = parent_iface->get_platform_state;
+}
+
static void
update_node_ordering (GtkModelButton *button)
{
@@ -519,6 +570,35 @@ update_node_name (GtkModelButton *self)
}
static void
+update_accessible_properties (GtkModelButton *button)
+{
+ if (button->menu_name || button->popover)
+ gtk_accessible_update_property (GTK_ACCESSIBLE (button),
+ GTK_ACCESSIBLE_PROPERTY_HAS_POPUP, TRUE,
+ -1);
+ else
+ gtk_accessible_reset_property (GTK_ACCESSIBLE (button),
+ GTK_ACCESSIBLE_PROPERTY_HAS_POPUP);
+
+ if (button->popover)
+ gtk_accessible_update_relation (GTK_ACCESSIBLE (button),
+ GTK_ACCESSIBLE_RELATION_CONTROLS, g_list_append (NULL, button->popover),
+ -1);
+ else
+ gtk_accessible_reset_relation (GTK_ACCESSIBLE (button),
+ GTK_ACCESSIBLE_RELATION_CONTROLS);
+
+ if (button->role == GTK_BUTTON_ROLE_CHECK ||
+ button->role == GTK_BUTTON_ROLE_RADIO)
+ gtk_accessible_update_state (GTK_ACCESSIBLE (button),
+ GTK_ACCESSIBLE_STATE_CHECKED, button->active,
+ -1);
+ else
+ gtk_accessible_reset_state (GTK_ACCESSIBLE (button),
+ GTK_ACCESSIBLE_STATE_CHECKED);
+}
+
+static void
gtk_model_button_set_role (GtkModelButton *self,
GtkButtonRole role)
{
@@ -541,6 +621,10 @@ gtk_model_button_set_role (GtkModelButton *self,
update_node_name (self);
gtk_model_button_update_state (self);
+ g_set_object (&self->at_context, create_at_context (self));
+
+ update_accessible_properties (self);
+
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ROLE]);
}
@@ -622,6 +706,9 @@ gtk_model_button_set_active (GtkModelButton *button,
return;
button->active = active;
+
+ update_accessible_properties (button);
+
gtk_model_button_update_state (button);
gtk_widget_queue_draw (GTK_WIDGET (button));
g_object_notify_by_pspec (G_OBJECT (button), properties[PROP_ACTIVE]);
@@ -637,6 +724,8 @@ gtk_model_button_set_menu_name (GtkModelButton *button,
update_node_name (button);
gtk_model_button_update_state (button);
+ update_accessible_properties (button);
+
gtk_widget_queue_resize (GTK_WIDGET (button));
g_object_notify_by_pspec (G_OBJECT (button), properties[PROP_MENU_NAME]);
}
@@ -704,6 +793,8 @@ gtk_model_button_set_popover (GtkModelButton *button,
gtk_popover_set_position (GTK_POPOVER (button->popover), GTK_POS_RIGHT);
}
+ update_accessible_properties (button);
+
update_node_name (button);
gtk_model_button_update_state (button);
@@ -918,12 +1009,14 @@ gtk_model_button_set_property (GObject *object,
}
static void
-gtk_model_button_dispose (GObject *object)
+gtk_model_button_dispose (GObject *object)
{
GtkModelButton *model_button = GTK_MODEL_BUTTON (object);
g_clear_pointer (&model_button->menu_name, g_free);
+ g_clear_object (&model_button->at_context);
+
G_OBJECT_CLASS (gtk_model_button_parent_class)->dispose (object);
}
@@ -1186,7 +1279,8 @@ gtk_model_button_class_init (GtkModelButtonClass *class)
widget_class->activate_signal = signals[SIGNAL_CLICKED];
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
- gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("modelbutton"));
+ gtk_widget_class_set_css_name (widget_class, I_("modelbutton"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_MENU_ITEM);
}
static void
diff --git a/gtk/gtkpopovermenu.c b/gtk/gtkpopovermenu.c
index 3e429a1820..dab6635530 100644
--- a/gtk/gtkpopovermenu.c
+++ b/gtk/gtkpopovermenu.c
@@ -122,6 +122,12 @@
* custom content to it, therefore it has the same CSS nodes.
* It is one of the cases that add a .menu style class to
* the popover's main node.
+ *
+ * # Accessibility
+ *
+ * GtkPopoverMenu uses the #GTK_ACCESSIBLE_ROLE_MENU role, and its
+ * items use the #GTK_ACCESSIBLE_ROLE_MENU_ITEM, #GTK_ACCESSIBLE_ROLE_MENU_ITEM_CHECKBOX or #GTK_ACCESSIBLE_ROLE_MENU_ITEM_RADIO roles, depending on the
+ * action they are connected to.
*/
typedef struct _GtkPopoverMenuClass GtkPopoverMenuClass;
@@ -494,6 +500,16 @@ gtk_popover_menu_move_focus (GtkWidget *widget,
}
static void
+gtk_popover_menu_root (GtkWidget *widget)
+{
+ GTK_WIDGET_CLASS (gtk_popover_menu_parent_class)->root (widget);
+
+ gtk_accessible_update_property (GTK_ACCESSIBLE (widget),
+ GTK_ACCESSIBLE_PROPERTY_ORIENTATION, GTK_ORIENTATION_VERTICAL,
+ -1);
+}
+
+static void
gtk_popover_menu_class_init (GtkPopoverMenuClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
@@ -503,6 +519,7 @@ gtk_popover_menu_class_init (GtkPopoverMenuClass *klass)
object_class->set_property = gtk_popover_menu_set_property;
object_class->get_property = gtk_popover_menu_get_property;
+ widget_class->root = gtk_popover_menu_root;
widget_class->map = gtk_popover_menu_map;
widget_class->unmap = gtk_popover_menu_unmap;
widget_class->focus = gtk_popover_menu_focus;
@@ -545,6 +562,8 @@ gtk_popover_menu_class_init (GtkPopoverMenuClass *klass)
"activate-default", NULL);
gtk_widget_class_add_binding_signal (widget_class, GDK_KEY_KP_Space, 0,
"activate-default", NULL);
+
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_MENU);
}
/**
diff --git a/gtk/gtkpopovermenubar.c b/gtk/gtkpopovermenubar.c
index 1f172e3088..1401c998eb 100644
--- a/gtk/gtkpopovermenubar.c
+++ b/gtk/gtkpopovermenubar.c
@@ -45,6 +45,12 @@
*
* The item whose popover is currently open gets the .active
* style class.
+ *
+ * # Accessibility
+ *
+ * GtkPopoverMenuBar uses the #GTK_ACCESSIBLE_ROLE_MENU_BAR role,
+ * the menu items use the #GTK_ACCESSIBLE_ROLE_MENU_ITEM role and
+ * the menus use the #GTK_ACCESSIBLE_ROLE_MENU role.
*/
@@ -126,7 +132,12 @@ set_active_item (GtkPopoverMenuBar *bar,
was_popup = FALSE;
if (was_popup && changed)
- gtk_popover_popdown (bar->active_item->popover);
+ {
+ gtk_accessible_update_state (GTK_ACCESSIBLE (bar->active_item),
+ GTK_ACCESSIBLE_STATE_EXPANDED, FALSE,
+ -1);
+ gtk_popover_popdown (bar->active_item->popover);
+ }
if (changed)
{
@@ -142,7 +153,12 @@ set_active_item (GtkPopoverMenuBar *bar,
if (bar->active_item)
{
if (popup || (was_popup && changed))
- gtk_popover_popup (bar->active_item->popover);
+ {
+ gtk_popover_popup (bar->active_item->popover);
+ gtk_accessible_update_state (GTK_ACCESSIBLE (bar->active_item),
+ GTK_ACCESSIBLE_STATE_EXPANDED, FALSE,
+ -1);
+ }
else if (changed)
gtk_widget_grab_focus (GTK_WIDGET (bar->active_item));
}
@@ -317,6 +333,22 @@ gtk_popover_menu_bar_item_activate (GtkPopoverMenuBarItem *item)
}
static void
+gtk_popover_menu_bar_item_root (GtkWidget *widget)
+{
+ GtkPopoverMenuBarItem *item = GTK_POPOVER_MENU_BAR_ITEM (widget);
+
+ GTK_WIDGET_CLASS (gtk_popover_menu_bar_item_parent_class)->root (widget);
+
+ gtk_accessible_update_relation (GTK_ACCESSIBLE (widget),
+ GTK_ACCESSIBLE_RELATION_LABELLED_BY, g_list_append (NULL, item->label),
+ GTK_ACCESSIBLE_RELATION_CONTROLS, g_list_append (NULL, item->popover),
+ -1);
+ gtk_accessible_update_property (GTK_ACCESSIBLE (widget),
+ GTK_ACCESSIBLE_PROPERTY_HAS_POPUP, TRUE,
+ -1);
+}
+
+static void
gtk_popover_menu_bar_item_class_init (GtkPopoverMenuBarItemClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -325,6 +357,7 @@ gtk_popover_menu_bar_item_class_init (GtkPopoverMenuBarItemClass *klass)
object_class->dispose = gtk_popover_menu_bar_item_dispose;
object_class->finalize = gtk_popover_menu_bar_item_finalize;
+ widget_class->root = gtk_popover_menu_bar_item_root;
widget_class->measure = gtk_popover_menu_bar_item_measure;
widget_class->size_allocate = gtk_popover_menu_bar_item_size_allocate;
@@ -340,6 +373,7 @@ gtk_popover_menu_bar_item_class_init (GtkPopoverMenuBarItemClass *klass)
G_TYPE_NONE, 0);
gtk_widget_class_set_css_name (widget_class, I_("item"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_MENU_ITEM);
}
enum
{
@@ -552,6 +586,10 @@ gtk_popover_menu_bar_root (GtkWidget *widget)
toplevel = GTK_WIDGET (gtk_widget_get_root (widget));
add_to_window (GTK_WINDOW (toplevel), bar);
+
+ gtk_accessible_update_property (GTK_ACCESSIBLE (bar),
+ GTK_ACCESSIBLE_PROPERTY_ORIENTATION, GTK_ORIENTATION_HORIZONTAL,
+ -1);
}
static void
@@ -598,6 +636,7 @@ gtk_popover_menu_bar_class_init (GtkPopoverMenuBarClass *klass)
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BOX_LAYOUT);
gtk_widget_class_set_css_name (widget_class, I_("menubar"));
+ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_MENU_BAR);
}
static void
diff --git a/gtk/gtkprogressbar.c b/gtk/gtkprogressbar.c
index 819cc5eb59..30a91d447c 100644
--- a/gtk/gtkprogressbar.c
+++ b/gtk/gtkprogressbar.c
@@ -446,15 +446,18 @@ gtk_progress_bar_init (GtkProgressBar *pbar)
pbar->text = NULL;
pbar->fraction = 0.0;
- pbar->trough_widget = gtk_gizmo_new ("trough",
- NULL,
- allocate_trough,
- NULL,
- NULL,
- NULL, NULL);
+ pbar->trough_widget = gtk_gizmo_new_with_role ("trough",
+ GTK_ACCESSIBLE_ROLE_NONE,
+ NULL,
+ allocate_trough,
+ NULL,
+ NULL,
+ NULL, NULL);
gtk_widget_set_parent (pbar->trough_widget, GTK_WIDGET (pbar));
- pbar->progress_widget = gtk_gizmo_new ("progress", NULL, NULL, NULL, NULL, NULL, NULL);
+ pbar->progress_widget = gtk_gizmo_new_with_role ("progress",
+ GTK_ACCESSIBLE_ROLE_NONE,
+ NULL, NULL, NULL, NULL, NULL, NULL);
gtk_widget_set_parent (pbar->progress_widget, pbar->trough_widget);
/* horizontal is default */
@@ -874,6 +877,7 @@ gtk_progress_bar_set_show_text (GtkProgressBar *pbar,
char *text = get_current_text (pbar);
pbar->label = g_object_new (GTK_TYPE_LABEL,
+ "accessible-role", GTK_ACCESSIBLE_ROLE_NONE,
"css-name", "text",
"label", text,
"ellipsize", pbar->ellipsize,
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c
index d9928636cf..af17b39af2 100644
--- a/gtk/gtkscale.c
+++ b/gtk/gtkscale.c
@@ -1698,12 +1698,13 @@ gtk_scale_add_mark (GtkScale *scale,
{
if (!priv->top_marks_widget)
{
- priv->top_marks_widget = gtk_gizmo_new ("marks",
- gtk_scale_measure_marks,
- gtk_scale_allocate_marks,
- NULL,
- NULL,
- NULL, NULL);
+ priv->top_marks_widget = gtk_gizmo_new_with_role ("marks",
+ GTK_ACCESSIBLE_ROLE_NONE,
+ gtk_scale_measure_marks,
+ gtk_scale_allocate_marks,
+ NULL,
+ NULL,
+ NULL, NULL);
gtk_widget_insert_after (priv->top_marks_widget,
GTK_WIDGET (scale),
@@ -1716,12 +1717,13 @@ gtk_scale_add_mark (GtkScale *scale,
{
if (!priv->bottom_marks_widget)
{
- priv->bottom_marks_widget = gtk_gizmo_new ("marks",
- gtk_scale_measure_marks,
- gtk_scale_allocate_marks,
- NULL,
- NULL,
- NULL, NULL);
+ priv->bottom_marks_widget = gtk_gizmo_new_with_role ("marks",
+ GTK_ACCESSIBLE_ROLE_NONE,
+ gtk_scale_measure_marks,
+ gtk_scale_allocate_marks,
+ NULL,
+ NULL,
+ NULL, NULL);
gtk_widget_insert_before (priv->bottom_marks_widget,
GTK_WIDGET (scale),
diff --git a/gtk/gtkseparator.c b/gtk/gtkseparator.c
index c6b391fe8f..fe9ac58437 100644
--- a/gtk/gtkseparator.c
+++ b/gtk/gtkseparator.c
@@ -139,9 +139,6 @@ gtk_separator_init (GtkSeparator *separator)
gtk_widget_update_orientation (GTK_WIDGET (separator),
separator->orientation);
- gtk_accessible_update_property (GTK_ACCESSIBLE (separator),
- GTK_ACCESSIBLE_PROPERTY_ORIENTATION, separator->orientation,
- -1);
}
static void
diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c
index a178672595..bb681d9123 100644
--- a/gtk/gtkswitch.c
+++ b/gtk/gtkswitch.c
@@ -651,13 +651,21 @@ gtk_switch_init (GtkSwitch *self)
gtk_switch_allocate);
gtk_widget_set_layout_manager (GTK_WIDGET (self), layout);
- self->on_image = gtk_image_new_from_icon_name ("switch-on-symbolic");
+ self->on_image = g_object_new (GTK_TYPE_IMAGE,
+ "accessible-role", GTK_ACCESSIBLE_ROLE_NONE,
+ "icon-name", "switch-on-symbolic",
+ NULL);
gtk_widget_set_parent (self->on_image, GTK_WIDGET (self));
- self->off_image = gtk_image_new_from_icon_name ("switch-off-symbolic");
+ self->off_image = g_object_new (GTK_TYPE_IMAGE,
+ "accessible-role", GTK_ACCESSIBLE_ROLE_NONE,
+ "icon-name", "switch-off-symbolic",
+ NULL);
gtk_widget_set_parent (self->off_image, GTK_WIDGET (self));
- self->slider = gtk_gizmo_new ("slider", NULL, NULL, NULL, NULL, NULL, NULL);
+ self->slider = gtk_gizmo_new_with_role ("slider",
+ GTK_ACCESSIBLE_ROLE_NONE,
+ NULL, NULL, NULL, NULL, NULL, NULL);
gtk_widget_set_parent (self->slider, GTK_WIDGET (self));
gtk_accessible_update_state (GTK_ACCESSIBLE (self),
diff --git a/testsuite/a11y/button.c b/testsuite/a11y/button.c
index a5e44280a4..803a2fecf8 100644
--- a/testsuite/a11y/button.c
+++ b/testsuite/a11y/button.c
@@ -49,7 +49,7 @@ linkbutton_role (void)
GtkWidget *button = gtk_link_button_new ("Hello");
g_object_ref_sink (button);
- gtk_test_accessible_assert_role (button, GTK_ACCESSIBLE_ROLE_BUTTON);
+ gtk_test_accessible_assert_role (button, GTK_ACCESSIBLE_ROLE_LINK);
g_object_unref (button);
}