OpenFire Diagnostics Guide
March 24, 2026 · View on GitHub
This guide explains how to read the built-in Diagnostics window and how the current text-selection trigger pipeline works in v0.3.15.
Open The Diagnostics Window
- Open the OpenFire menu bar item.
- Click
Diagnostics.... - Click
Refreshafter reproducing the problem once. - Use
Copy Reportif you want to share the current report.
What The Diagnostics Window Shows
The Diagnostics panel is a snapshot of the current OpenFire context. It is built in DiagnosticsWindow.swift.
Core Context Fields
Frontmost app: The current foreground application name.Bundle ID: The current foreground application bundle identifier.Accessibility: Whether OpenFire currently has Accessibility permission.App exclusion: Whether the current app is disabled by the app blacklist.Focused element: The current focused accessibility role or role/subrole.Selected text length: The selected text length returned by Accessibility.Selected text preview: A short preview of the selected text.Clipboard: Whether the general pasteboard currently contains text.Empty-input probe point: The last location checked for thePaste / Clearcapsule.Selection source: The last successful acquisition path:Accessibility APICmd+C Fallback
Last selection failure: The most recent failed path, such as:accessibilityEmptySelectioncopyFallbackEmptySelectionobserverSetupFailedobserverTimedOutnoFocusedApplication
Menu readiness: Whether OpenFire currently believes the menu can be shown.
Plugin Visibility Section
The lower half of the report explains plugin visibility for the current text and app context.
Visible: The plugin matches the current context and can appear in the ring.Hidden: The plugin is currently blocked.- Common hidden reasons include:
- plugin disabled
- plugin disabled for current app
- selected text too short or too long
- regex mismatch
- current app not in allowlist
- missing execution trust for script plugins
Current Trigger Logic
The main selection trigger path lives in TextSelectionMonitor.swift and AccessibilityManager.swift.
High-Level Flow
- OpenFire records state on
leftMouseDown. - OpenFire evaluates the gesture on
leftMouseUp. - Non-text gestures are filtered out first.
- If the gesture still looks like text selection, OpenFire tries to acquire the selected text.
- If text is acquired, the radial menu is shown after a short presentation delay.
Gesture Filters Applied Before Triggering
OpenFire suppresses the menu before any text acquisition if any of the following is true:
- The drag pasteboard changed during the gesture and now contains file-drag types such as
public.file-url. - The frontmost app is a suppressed context:
- OpenFire itself
- Finder
- Dock
- Desktop / WindowManager
- known screenshot tools
- The current gesture moved the frontmost window itself.
That last rule is important in v0.3.15: window dragging is now blocked by comparing the frontmost window frame before and after the gesture instead of relying on fragile AX text hit-testing.
How OpenFire Decides A Gesture Is “Text-Like”
OpenFire captures these signals:
- whether the gesture started in a text context
- whether the gesture ended in a text context
- whether the pointer was inside the focused element bounds
- whether the Accessibility selection snapshot changed
Text context means one of:
- the hit-tested element is treated as text
- the point is inside an editable text input
- the point is inside a focused element that looks like rich-text selection context
Preferred Acquisition Path: Accessibility
OpenFire first tries native Accessibility selection state.
It succeeds when:
- the current selection snapshot is readable via Accessibility
- the selected text is non-empty
- the selection actually changed compared with the
mouseDownsnapshot
When this path works, Diagnostics shows:
Selection source: Accessibility API
Fallback Acquisition Path: Cmd+C
If native Accessibility does not yield text quickly enough, OpenFire falls back to synthetic Cmd+C.
This path:
- posts
Cmd+C - polls the pasteboard briefly
- waits for a fresh non-empty copied string
- restores the previous pasteboard snapshot only when a fresh copied value actually arrived
When this path works, Diagnostics shows:
Selection source: Cmd+C Fallback
Browser / WebView / Telegram Behavior
Different hosts expose different AX quality, so OpenFire treats them slightly differently.
Native Editors
Examples:
- TextEdit
- many native text fields
These typically succeed via native Accessibility snapshots.
Browsers And WebViews
Examples:
- Chrome
- Edge
- Brave
- Codex app
These may succeed either through Accessibility or through Cmd+C fallback, depending on timing and DOM accessibility exposure.
Telegram
Telegram is the most important special case in v0.3.15.
Observed behavior:
- on mouse-up, Telegram may expose no usable AX hit element
- on mouse-up, Telegram may expose no usable focused element
Because of that, OpenFire now avoids requiring stable AX hit/focus evidence for Telegram’s fallback path. Instead:
- if the gesture did not move the frontmost window
- and
Cmd+Cproduced fresh non-empty text
OpenFire still allows the radial menu to trigger.
This is the reason Telegram can now work again without reintroducing the old “dragging the window also triggers the menu” bug.
How To Read Common Failure Patterns
Case 1: Nothing Triggers Anywhere
Typical report:
Accessibility: MissingMenu readiness: BlockedLast selection failure: noFocusedApplicationor repeated empty selection
Usually means:
- Accessibility permission is missing or ineffective
Case 2: Text Selection Works In Some Apps But Not Others
Typical report:
Accessibility: GrantedApp exclusion: Active in current app- some plugins visible, some hidden
- repeated
copyFallbackEmptySelectionin the failing app
Usually means:
- the host app exposes poor AX selection state
- fallback copy did not produce a fresh clipboard value
- or the app is blacklisted / plugin-scoped filtered
Case 3: Dragging A Window Opens The Ring
In v0.3.15, this should no longer happen under normal conditions.
The relevant guard is:
- frontmost window movement detection
If this regresses again, compare:
- gesture path
- whether the frontmost app changed mid-gesture
- whether the moved surface was actually a separate panel instead of the main window
Case 4: Finder File Management Should Not Trigger, But Rename Should
Expected behavior:
- dragging files: blocked
- desktop / Dock file management: blocked
- Finder rename field text selection: allowed
This works because file-management contexts are suppressed broadly, but editable text context inside Finder still bypasses that suppression.
Practical Reproduction Workflow
When debugging a report:
- Reproduce the issue once.
- Open
Diagnostics.... - Click
Refresh. - Check:
- frontmost app
- Accessibility permission
- focused element
- selected text preview
- selection source
- last selection failure
- plugin visibility reasons
- If needed, reproduce again and compare whether the source flips between
Accessibility APIandCmd+C Fallback.
Source Pointers
- Trigger pipeline:
Sources/App/Core/TextSelectionMonitor.swift - Accessibility acquisition and fallback:
Sources/App/Core/AccessibilityManager.swift - Diagnostics UI:
Sources/App/UI/DiagnosticsWindow.swift