Skip to content

Fix COMError crashes and performance in Thunderbird#19

Open
serrebi wants to merge 2 commits intojavidominguez:masterfrom
serrebi:fix-thunderbird-performance-and-comerror
Open

Fix COMError crashes and performance in Thunderbird#19
serrebi wants to merge 2 commits intojavidominguez:masterfrom
serrebi:fix-thunderbird-performance-and-comerror

Conversation

@serrebi
Copy link

@serrebi serrebi commented Mar 15, 2026

Thunderbird works much better

I vibe coded this. I just wanted this addon to help make Thunderbird very user friendly for blind users.

What was broken

  • COMError not caught anywhere. Every property access on Mozilla objects (.role, .firstChild, .parent, .IA2Attributes, .states, .name) throws _ctypes.COMError when objects go stale during UI updates. Only AttributeError/KeyError were caught. COMErrors hit NVDA's error handler 11+ times per focus change, triggering watchdog freeze recovery (0.5–0.9s freezes).
  • event_focusEntered ran expensive _IA2Relations COM call on every ancestor object in the focus chain. Also used a chain of if/if/if instead of if/elif, so every branch ran on every event.
  • event_documentLoadComplete read entire message body with makeTextInfo("all").text, blocking the main thread on large HTML emails before truncating to 4000 chars.
  • readPreviewPane swapped focus twice unnecessarily — called api.setFocusObject() twice just to get a tree interceptor reference, firing the entire focus event chain for no reason.
  • chooseNVDAObjectOverlayClasses made redundant COM calls — accessed parent IA2Attributes even when the object's own attributes already matched.
  • No auto-focus on startup — focus always landed on the preview pane (or Thunderbird's Home tab), requiring a manual Shift+Tab to reach the message list. The old shift+tab approach was unreliable due to variable focusable elements between panes.

What this PR does

  • Import COMError and catch it in all event handlers, overlay class methods, and property accessors
  • Restrict _IA2Relations lookup to INTERNALFRAME role only, with its own try/except and null check on objectWithFocus()
  • Optimize event_documentLoadComplete: limit the text range to 4000 chars before extracting .text (collapse + move end point), avoiding full virtual buffer processing
  • Optimize readPreviewPane: try obj.treeInterceptor and getTreeInterceptor() first, only fall back to the double focus swap if neither returns a tree interceptor
  • Optimize chooseNVDAObjectOverlayClasses: check obj.IA2Attributes first and short-circuit — only query parent attributes if the object's own xml-roles doesn't match
  • Reliable auto-focus on startup: schedule a 4-second delayed focus attempt (after Thunderbird's Home tab finishes and Inbox tab loads), then use F6 pane cycling with retry (up to 4 attempts) to land on the message list. Verifies landing by checking for threadTree-row* IA2 ID prefix (distinguishes message list from folder tree). Falls back gracefully if inbox hasn't loaded.

Testing

Manually tested with Thunderbird Daily 150.0a1 (2026-03-15) (64-bit) and NVDA 2026.1beta6.

🤖 Generated with Claude Code

admin and others added 2 commits March 15, 2026 12:57
Thunderbird works much better now.

- COMError from stale Mozilla COM objects was not caught anywhere.
  Every property access (.role, .firstChild, .parent, .IA2Attributes,
  .states, .name) can throw _ctypes.COMError when Thunderbird's UI
  updates. Only AttributeError/KeyError were caught, so COMErrors
  hit NVDA's error handler 11+ times per focus change, causing
  freezes (watchdog recovery of 0.5-0.9s per event).
- event_focusEntered ran expensive _IA2Relations COM call on every
  ancestor object in the focus chain. Now restricted to INTERNALFRAME
  role only. Also changed if/if/if chain to if/elif so only the
  matching branch runs.
- event_documentLoadComplete called api.setFocusObject() twice just
  to get a tree interceptor, firing the entire focus event chain
  twice. Removed. Also capped text to 4000 chars so large HTML
  emails don't block the main thread.
- initOverlayClass crashed with KeyError on IA2Attributes["id"]
  when "id" key was missing. Changed to .get("id", "").
- chooseNVDAObjectOverlayClasses used dict["key"] instead of
  .get("key") causing unnecessary KeyError exceptions.
- Added auto-focus to message list on Thunderbird startup instead
  of landing on the preview pane.

Tested with Thunderbird Daily 150.0a1 (2026-03-15) (64-bit).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace unreliable shift+tab startup focus with F6 pane cycling
  that retries until focus lands on the actual message list
  (identified by threadTree-row ID prefix)
- Schedule startup focus 4s after init to handle Thunderbird's
  Home tab loading before the Inbox tab
- Optimize event_documentLoadComplete to limit text extraction
  range before accessing .text (avoids processing entire large
  messages)
- Optimize readPreviewPane to avoid unnecessary double focus swap
  when tree interceptor is already available
- Reduce COM calls in chooseNVDAObjectOverlayClasses by
  short-circuiting parent attribute checks
- Add safety checks in event_focusEntered INTERNALFRAME case

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant