You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm a blind ham (AI5OS, VoiceOver user on macOS Apple Silicon) and I want to use D-Rats with my Kenwood TH-D75. After auditing the codebase I have to report that the macOS build of D-Rats is structurally inaccessible to blind users, and the cause is not something that can be fixed by adding accessibility metadata. I want to file this honestly so it's on the public record, and to share what I'm doing about it.
Once the app does launch, VoiceOver (Apple's built-in screen reader) cannot see any of the controls inside the main D-Rats window. The entire window is reported as a single opaque element. Tab/VO+arrow navigation does not reach any of the chat panel, station list, file panel, message panel, config panels, or the menu bar's GTK-rendered children.
Why this is a structural problem, not a metadata problem
I want to be careful here, because this is the part that most often gets misunderstood. The issue is not that D-Rats is missing setAccessibleName calls (although it is — grep for a11y and atk- in ui/mainwindow.glade returns 0 results). The issue is the toolkit itself.
GTK 3 on macOS draws its own widgets via Quartz; it does not create real NSView / NSButton / NSTextField / etc. AppKit, and therefore NSAccessibility (the macOS accessibility API that VoiceOver reads), sees a single opaque NSView for the entire D-Rats window. ATK (GTK's own accessibility layer) bridges to AT-SPI on Linux and to IAccessible2 on Windows, but the bridge from ATK to NSAccessibility was never finished and is not part of upstream GTK. There have been proof-of-concept efforts over the years (most visible in gtk-mac-integration, which handles menu bar integration but not general AX), but no production GTK→NSAccessibility bridge exists today on either GTK 3 or GTK 4.
What this means concretely: even if every widget in ui/mainwindow.glade had perfect ATK accessibility names and roles, VoiceOver on macOS would still see one giant unlabeled "Window" element with nothing inside it. There is no metadata fix that resolves this. The only ways forward are:
Replace the toolkit on the macOS build — port the UI layer to a Mac-friendly Python toolkit (Toga / BeeWare → real AppKit → real NSAccessibility, or PySide6 / Qt6 → which does have a working QAccessible→NSAccessibility bridge). The protocol/session/transport layers would not change. This is a significant amount of work and would arguably benefit Linux and Windows users too if it were done as a clean abstraction.
Build a separate native macOS client that speaks the D-Rats protocol — i.e., a Swift/SwiftUI app that reimplements DDT2 framing, yEncode, CRC, the session state machines, and the serial/Bluetooth transport in Swift, with first-class VoiceOver support from day one.
Headless D-Rats core + web UI — restructure the Python app so the core can run without GTK, then build a Flask/FastAPI web UI on top. This makes the full feature set accessible from any browser, which is the most accessible UI platform on the planet. The downside is decoupling mainapp.py and mainwindow.py is a substantial refactor, and "always-on host" becomes a deployment requirement.
What I'm doing
I'm starting on option 2 — a clean native macOS Swift client called MacRats, GPL-3 licensed (matching D-Rats upstream so the lineage is honored). It will reimplement the DDT2 wire format, yEncode, CRC, zlib framing, and the chat + file transfer session state machines in Swift, with a SwiftUI UI built accessibility-first against the macOS NSAccessibility API. v1 will target chat, station list, file transfer, and config — the bare minimum to actually make a D-STAR data QSO from a Mac. My test radio will be a Kenwood TH-D75 over USB serial.
I want to be very clear: MacRats is not a fork of D-Rats and is not trying to replace D-Rats on Linux or Windows. D-Rats is the right tool on those platforms and I have no interest in fragmenting the project. MacRats exists because GTK on macOS is a structural dead end for screen reader users, and the only honest path forward is a separate native client. If the upstream maintainers ever want to take a different path (a Toga port, a Qt6 port, a headless+web split), that would be wonderful and I would gladly contribute and stop maintaining MacRats.
What I'd ask of the maintainers
I am not asking for someone to drop everything and rewrite the toolkit. I am asking for three smaller things, in order of how much they would help:
Acknowledge in the README and the install docs that the current macOS build is not accessible to blind users with VoiceOver, and link to whatever alternative exists. Once MacRats has a v1 release I will offer to add the link via PR. Until then, a one-line note pointing to this issue would be enough. Blind hams searching for "D-Rats macOS" deserve to find an honest answer rather than to spend hours fighting Python venvs and GTK installs only to discover the result is unusable to them.
Treat D-STAR protocol documentation as a first-class artifact. The DDT2 frame format, the session state machines, yEncode usage, CRC algorithm, and the wire-level description of chat / file / form sessions currently live only in the Python source. If you ever produced a short docs/PROTOCOL.md describing the on-air bytes (even just by copying what's already in d_rats/ddt2.py, d_rats/transport.py, d_rats/sessions/*.py into prose), it would dramatically help anyone building an interoperable client — including MacRats.
If you're ever interested in a longer conversation about a Toga or PySide6 port of the UI layer to make the macOS build first-class, I'd be happy to help scope it. I genuinely think a clean d_rats/ui/ abstraction with multiple backends would be valuable to the project's long-term health on all three platforms, not just for accessibility.
I want to thank you both — Maurizio (IZ2LXI) and John (WB8TYW) — for keeping D-Rats alive and for the Python 3 conversion. D-Rats fills a genuinely important niche for emergency communications and rural ham operation, and the work of maintaining it is real and unglamorous. Nothing in this issue is meant as criticism of that work. The toolkit limitation predates either of you and isn't anyone's fault.
Environment
Platform: macOS 14/15 (Apple Silicon)
Screen reader: VoiceOver
Radio I'd like to use D-Rats with: Kenwood TH-D75 (built-in TNC, USB-C serial, D-STAR DV slow-data)
Comparable structural-vs-metadata accessibility analysis on a Qt6 project: macOS build is not accessible with VoiceOver aethersdr/AetherSDR#870 (where the toolkit does bridge to NSAccessibility, so the work is metadata-only — this is the contrast that makes D-Rats's situation harder)
Summary
I'm a blind ham (AI5OS, VoiceOver user on macOS Apple Silicon) and I want to use D-Rats with my Kenwood TH-D75. After auditing the codebase I have to report that the macOS build of D-Rats is structurally inaccessible to blind users, and the cause is not something that can be fixed by adding accessibility metadata. I want to file this honestly so it's on the public record, and to share what I'm doing about it.
What I observe on macOS
gi/ PyGObject / GTK 3 / pycairo running on Apple Silicon is significantly harder than on Linux. Several existing open issues already document this (Macbook install #178, MacOs - D-Rats get stuck while rendering map #185, macbook - d-rats app in the menu bar shows as "python 3.11" #194, Macbook - "test sound" result in error #195, Mac OS GIO application issues #196, Issue pressing ESC on Mac: gtk_widget_event: assertion 'WIDGET_REALIZED_FOR_EVENT (widget, event)' failed #256, macos - map - not showing "my station" #293, smtpd discontinued vs aiosmtpd #296).Why this is a structural problem, not a metadata problem
I want to be careful here, because this is the part that most often gets misunderstood. The issue is not that D-Rats is missing
setAccessibleNamecalls (although it is —grepfora11yandatk-inui/mainwindow.gladereturns 0 results). The issue is the toolkit itself.GTK 3 on macOS draws its own widgets via Quartz; it does not create real
NSView/NSButton/NSTextField/ etc. AppKit, and therefore NSAccessibility (the macOS accessibility API that VoiceOver reads), sees a single opaqueNSViewfor the entire D-Rats window. ATK (GTK's own accessibility layer) bridges to AT-SPI on Linux and to IAccessible2 on Windows, but the bridge from ATK to NSAccessibility was never finished and is not part of upstream GTK. There have been proof-of-concept efforts over the years (most visible ingtk-mac-integration, which handles menu bar integration but not general AX), but no production GTK→NSAccessibility bridge exists today on either GTK 3 or GTK 4.What this means concretely: even if every widget in
ui/mainwindow.gladehad perfect ATK accessibility names and roles, VoiceOver on macOS would still see one giant unlabeled "Window" element with nothing inside it. There is no metadata fix that resolves this. The only ways forward are:QAccessible→NSAccessibility bridge). The protocol/session/transport layers would not change. This is a significant amount of work and would arguably benefit Linux and Windows users too if it were done as a clean abstraction.mainapp.pyandmainwindow.pyis a substantial refactor, and "always-on host" becomes a deployment requirement.What I'm doing
I'm starting on option 2 — a clean native macOS Swift client called MacRats, GPL-3 licensed (matching D-Rats upstream so the lineage is honored). It will reimplement the DDT2 wire format, yEncode, CRC, zlib framing, and the chat + file transfer session state machines in Swift, with a SwiftUI UI built accessibility-first against the macOS NSAccessibility API. v1 will target chat, station list, file transfer, and config — the bare minimum to actually make a D-STAR data QSO from a Mac. My test radio will be a Kenwood TH-D75 over USB serial.
I want to be very clear: MacRats is not a fork of D-Rats and is not trying to replace D-Rats on Linux or Windows. D-Rats is the right tool on those platforms and I have no interest in fragmenting the project. MacRats exists because GTK on macOS is a structural dead end for screen reader users, and the only honest path forward is a separate native client. If the upstream maintainers ever want to take a different path (a Toga port, a Qt6 port, a headless+web split), that would be wonderful and I would gladly contribute and stop maintaining MacRats.
What I'd ask of the maintainers
I am not asking for someone to drop everything and rewrite the toolkit. I am asking for three smaller things, in order of how much they would help:
docs/PROTOCOL.mddescribing the on-air bytes (even just by copying what's already ind_rats/ddt2.py,d_rats/transport.py,d_rats/sessions/*.pyinto prose), it would dramatically help anyone building an interoperable client — including MacRats.d_rats/ui/abstraction with multiple backends would be valuable to the project's long-term health on all three platforms, not just for accessibility.I want to thank you both — Maurizio (IZ2LXI) and John (WB8TYW) — for keeping D-Rats alive and for the Python 3 conversion. D-Rats fills a genuinely important niche for emergency communications and rural ham operation, and the work of maintaining it is real and unglamorous. Nothing in this issue is meant as criticism of that work. The toolkit limitation predates either of you and isn't anyone's fault.
Environment
References
73,
AI5OS