Add wxWindow::SetAccessibleName() (PR #27056)

15 views
Skip to first unread message

Quin Gillespie

unread,
Sep 21, 2026, 9:52:40 PM (2 days ago) Sep 21
to wx-...@googlegroups.com, Subscribed

As discussed in #27051 and #27055, this adds wxWindow::SetAccessibleName() and GetAccessibleName(), allowing to set the name used by screen readers for any window, e.g. for buttons showing only a bitmap or text controls without a label before them.

Under MSW, the name is used by wxIAccessible::get_accName() for the window itself, whatever accessible object it uses, so it works for the controls with their own accessible classes too. Native controls don't have any accessible object by default, so a plain wxAccessible is created for them, which leaves everything except the name to the standard system object. This requires wxUSE_ACCESSIBILITY, which is on by default.

Under macOS, it sets the accessibility label of the native view, with 2 special cases found while testing with VoiceOver:

  • For views inside an NSScrollView, e.g. multiline wxTextCtrl, the document view is used, as this is what VoiceOver reads.
  • For buttons, the accessibility title is set instead, because VoiceOver uses the title and ignores the label for buttons with a title. Only one of them is set, as resetting both of them to nil results in an empty title instead of the default one.

Under the other platforms it only stores the name for now, as I can't test there.

Documentation and a unit test are included; under MSW the test also checks the name returned by IAccessible::get_accName().

Tested with NVDA on Windows 11: custom names are used for labelled and bitmap-only buttons, single and multiline text controls and a list control, whose items are still read normally.

Tested with VoiceOver on macOS 26: custom names are used for labelled and bitmap-only buttons and a multiline text control, and passing an empty string restores the default names.


You can view, comment on, or merge this pull request online at:

  https://github.com/wxWidgets/wxWidgets/pull/27056

Commit Summary

  • c545e67 Add wxWindow::SetAccessibleName()

File Changes

(10 files)

Patch Links:


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/27056@github.com>

VZ

unread,
Sep 22, 2026, 7:26:49 AM (yesterday) Sep 22
to wx-...@googlegroups.com, Subscribed

@vadz requested changes on this pull request.

Thanks, the new function looks good but I'm not convinced if we need the accessor.

@csomor Stefan, as usual, I'd be grateful for a review of macOS-specific parts, notably if there is a better way to implement the new function than using isKindOf tests. TIA!


In tests/controls/windowtest.cpp:

> @@ -710,3 +715,35 @@ TEST_CASE_METHOD(WindowTestCase, "Window::Refresh", "[window]")
     CHECK(isChild2Painted == true);
     CHECK(isChild3Painted == true);
 }
+
+TEST_CASE("Window::AccessibleName", "[window][accessibility]")
+{
+    auto button = make_unique<wxButton>(wxTheApp->GetTopWindow(), wxID_ANY, "Label");
+    CHECK( button->GetAccessibleName().empty() );
+
+    button->SetAccessibleName("Name");
+    CHECK( button->GetAccessibleName() == "Name" );
+
+#if defined(__WXMSW__) && wxUSE_ACCESSIBILITY
+    IAccessible* acc = nullptr;
+    REQUIRE( ::AccessibleObjectFromWindow(GetHwndOf(button.get()), OBJID_CLIENT,

This results in an error in the CI builds.


In tests/controls/windowtest.cpp:

> +    CHECK( button->GetAccessibleName().empty() );
+
+    button->SetAccessibleName("Name");
+    CHECK( button->GetAccessibleName() == "Name" );
+
+#if defined(__WXMSW__) && wxUSE_ACCESSIBILITY
+    IAccessible* acc = nullptr;
+    REQUIRE( ::AccessibleObjectFromWindow(GetHwndOf(button.get()), OBJID_CLIENT,
+                                          IID_IAccessible,
+                                          reinterpret_cast<void**>(&acc)) == S_OK );
+
+    VARIANT self;
+    self.vt = VT_I4;
+    self.lVal = CHILDID_SELF;
+
+    BSTR name = nullptr;

Could use wxBasicString from include/wx/msw/ole/oleutils.h.


In include/wx/window.h:

> @@ -1584,6 +1584,11 @@ class WXDLLIMPEXP_CORE wxWindowBase : public wxEvtHandler
 
     // accessibility
     // ----------------------
+
+    // Sets the name used by screen readers for this window.
+    void SetAccessibleName(const wxString& name);
+    const wxString& GetAccessibleName() const { return m_accessibleName; }

Do we actually need this and m_accessibleName? I know that wx is not particularly memory-efficient anyhow, but this adds a wxString which is going to be rarely used to all windows. I wouldn't add it for now, let's wait until we discover a real need for it.


In include/wx/window.h:

> +    // called by SetAccessibleName() to update the native name, if any
+    virtual void DoSetAccessibleName(const wxString& WXUNUSED(name)) { }

If we remove m_accessibleName we should also remove this one and just make SetAccessibleName() itself virtual.


In interface/wx/window.h:

> @@ -3587,6 +3587,39 @@ class wxWindow : public wxEvtHandler
     */
     void SetAccessible(wxAccessible* accessible);
 
+    /**
+        Sets the name used by screen readers for this window.
+
+        By default, screen readers use the label of the window, if it has
+        one, or, for some controls such as wxTextCtrl, the text of the label
+        preceding it. This function allows to give a name to the windows
+        without a label, e.g. buttons showing only a bitmap, or to use a
+        different name than the label.
+
+        Pass an empty string to use the default name again.
+
+        Currently this function is implemented under MSW, where it requires
+        @c wxUSE_ACCESSIBILITY to be enabled, and macOS. Under the other
+        platforms it only stores the name, which is returned by

This part will need to be removed if we remove the accessor.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/27056/review/5277255225@github.com>

Quin Gillespie

unread,
Sep 22, 2026, 10:04:13 AM (23 hours ago) Sep 22
to wx-...@googlegroups.com, Push

@trypsynth pushed 3 commits.

  • 1959e87 Store accessible name in wxAccessible instead of all windows
  • d3237e2 fix SetAccessibleName() being protected under macOS
  • 9484ec1 fix reusing wxBasicString in accessible name test


View it on GitHub or unsubscribe.


Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/27056/before/c545e674dc9568d5d2efa098bff0da6b4aded128/after/9484ec1d2c4cdf5c243b604f7ee802b69eab8adc@github.com>

Quin Gillespie

unread,
Sep 22, 2026, 10:04:18 AM (23 hours ago) Sep 22
to wx-...@googlegroups.com, Subscribed
trypsynth left a comment (wxWidgets/wxWidgets#27056)

Thanks, I've removed GetAccessibleName() and m_accessibleName and made SetAccessibleName() itself virtual. Under MSW the name is now stored in the window wxAccessible object, which only exists for the windows which need it, and it's overridden in wxOSX to set the native label. The test now uses wxBasicString and casts OBJID_CLIENT to avoid the signed/unsigned warning.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/pull/27056/c5777946630@github.com>

Reply all
Reply to author
Forward
0 new messages