diff options
author | Matthias Clasen <mclasen@redhat.com> | 2020-10-22 02:52:46 +0000 |
---|---|---|
committer | Matthias Clasen <mclasen@redhat.com> | 2020-10-22 02:52:46 +0000 |
commit | daf3b3a3b4cc70c5db278fd7142a6b49af91ae1d (patch) | |
tree | 23d317eccfeec9fdd1188e19e779fc5919270c11 | |
parent | b5b8f42a0c6ac94722c62a27c0635b6484f5d72d (diff) | |
parent | 800eb76a2de85b4e1844b28b50d440602bf9c4f8 (diff) | |
download | gtk+-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.md | 8 | ||||
-rw-r--r-- | docs/reference/gtk/section-accessibility.md | 19 | ||||
-rw-r--r-- | gtk/a11y/gtkatspiaction.c | 4 | ||||
-rw-r--r-- | gtk/gtkaccessible.c | 3 | ||||
-rw-r--r-- | gtk/gtkenums.h | 35 | ||||
-rw-r--r-- | gtk/gtklevelbar.c | 17 | ||||
-rw-r--r-- | gtk/gtklinkbutton.c | 4 | ||||
-rw-r--r-- | gtk/gtkmenubutton.c | 38 | ||||
-rw-r--r-- | gtk/gtkmodelbutton.c | 98 | ||||
-rw-r--r-- | gtk/gtkpopovermenu.c | 19 | ||||
-rw-r--r-- | gtk/gtkpopovermenubar.c | 43 | ||||
-rw-r--r-- | gtk/gtkprogressbar.c | 18 | ||||
-rw-r--r-- | gtk/gtkscale.c | 26 | ||||
-rw-r--r-- | gtk/gtkseparator.c | 3 | ||||
-rw-r--r-- | gtk/gtkswitch.c | 14 | ||||
-rw-r--r-- | testsuite/a11y/button.c | 2 |
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); } |