qt: add PARITY.md tracking 80+ findings vs macOS/GTK
Result of a four-agent parallel audit comparing every action handler,
input event, window/tab/split lifecycle path, and config option
across Qt, macOS, and GTK. Findings are deduplicated and grouped:
- 49 BUGS (user-visible wrong behavior): lifecycle/quit, action
coverage, input/mouse, window/tab/split, quick terminal, misc.
- 10 INCONSISTENT items (works but feels wrong).
- 21 MISSING config options (silently dropped).
Each finding cites Qt's file:line plus the macOS/GTK reference, with
checkboxes for tracking as items land. Recommended fix order is
tiered by implementation effort within each user-impact bucket.
Co-Authored-By: claude-flow <ruv@ruv.net>
pull/12846/head
parent
433fa62100
commit
b7e94c01cc
|
|
@ -0,0 +1,208 @@
|
|||
# Qt Frontend — Platform Parity Tracker
|
||||
|
||||
This document tracks where the Qt frontend lacks consistency with the
|
||||
upstream Ghostty macOS and GTK frontends. It came out of a four-agent
|
||||
parallel audit that compared every action handler, input event,
|
||||
window/tab/split lifecycle path, and config option across the three
|
||||
implementations.
|
||||
|
||||
Findings are deduplicated, grouped by severity, and ordered by
|
||||
implementation effort within each tier. As items land, tick the
|
||||
checkbox and link the commit hash.
|
||||
|
||||
**Authoritative sources of truth used during the audit:**
|
||||
|
||||
- `include/ghostty.h` — every `GHOSTTY_ACTION_*` tag the apprt may receive.
|
||||
- `src/apprt/action.zig` — corresponding Zig types.
|
||||
- `src/config/Config.zig` — config field declarations + doc comments.
|
||||
|
||||
**Frontend file roots:**
|
||||
|
||||
- Qt: `qt/src/`
|
||||
- macOS: `macos/Sources/Ghostty/`, `macos/Sources/Features/`, `macos/Sources/App/macOS/`
|
||||
- GTK: `src/apprt/gtk/class/`
|
||||
|
||||
---
|
||||
|
||||
## 🔴 Bugs (user-visible wrong behavior)
|
||||
|
||||
### Lifecycle / quit
|
||||
|
||||
- [ ] **B1.** `quit-after-last-window-closed-delay` does nothing on natural close (`MainWindow.cpp:255`). Delay timer only fires when libghostty issues `QUIT_TIMER`, but closing the last window via the title-bar X keeps the process alive forever (since Qt's `quitOnLastWindowClosed` was set false to allow the delay path). macOS handles via `applicationShouldTerminateAfterLastWindowClosed`; GTK wires last-window-close → `startQuitTimer` (`application.zig:820-862`).
|
||||
- [ ] **B2.** `CLOSE_ALL_WINDOWS` always force-terminates (`MainWindow.cpp:1367-1370`, `:602-621`). Qt collapses `QUIT` and `CLOSE_ALL_WINDOWS` into the same path, both calling `qApp->quit()`. macOS keeps them distinct (close-all doesn't terminate). User binds close-all-windows → app quits unexpectedly.
|
||||
- [ ] **B3.** `m_skipCloseConfirm` never cleared (`MainWindow.cpp:577-585`, `:454`, `:474`, `:509`). After one skip-confirmed close, if the window is re-shown via `toggleVisibility`, the next close also skips confirmation. macOS resets per-action.
|
||||
- [ ] **B4.** `confirm-close-surface` config option ignored (`MainWindow.cpp:587-599`). Qt always uses libghostty's `needs_confirm_quit`. User setting `false` / `always` / `always-cwd` has no effect.
|
||||
- [ ] **B5.** `closeAllWindows` ignores `quit-after-last-window-closed=false` — windowless keep-alive impossible after close-all.
|
||||
|
||||
### Action coverage
|
||||
|
||||
- [ ] **B6.** `CLOSE_TAB` ignores `close_tab_mode` (`MainWindow.cpp:1241-1247`). Always treats as `mode=THIS`. "Close other tabs" / "Close tabs to the right" keybinds silently close only the current tab.
|
||||
- [ ] **B7.** `INITIAL_SIZE` halves window on HiDPI (`MainWindow.cpp:1429-1433`). Width/height from libghostty are already logical pixels; Qt divides by `devicePixelRatioF()` again. macOS uses unmodified.
|
||||
- [ ] **B8.** `MOUSE_VISIBILITY` clobbers cursor shape on un-hide (`MainWindow.cpp:1512-1520`). Sets `Qt::ArrowCursor` on un-hide, destroying the previous shape from `MOUSE_SHAPE`. macOS preserves shape.
|
||||
- [ ] **B9.** Performable-action-returns-true: `MOVE_TAB`, `GOTO_TAB`, `GOTO_SPLIT`, `RESIZE_SPLIT`, `EQUALIZE_SPLITS`, `TOGGLE_SPLIT_ZOOM` all unconditionally return `true`, swallowing chords on unsplit/single-tab surfaces. macOS returns false; GTK gates on `tree.getIsSplit()`.
|
||||
- [ ] **B10.** `MOVE_TAB` with target=APP moves a tab in arbitrary first window (`MainWindow.cpp:1504`). macOS returns false for app target.
|
||||
- [ ] **B11.** `RELOAD_CONFIG` only reloads ONE window (`MainWindow.cpp:1410-1414`). Other windows stay on stale config. macOS reloads globally.
|
||||
- [ ] **B12.** `CONFIG_CHANGE` only refreshes chrome (`MainWindow.cpp:1416-1421`). Doesn't push the new config to running surfaces. `applyWindowConfig` only updates tab-bar + theme — `window-decoration`, `fullscreen`, `maximize` changes don't propagate to existing windows.
|
||||
- [ ] **B13.** `OPEN_URL` ignores `kind` (`MainWindow.cpp:1471-1480`). `.text` payloads (e.g. config files) open with whatever the desktop says is default for `.txt` (usually a browser). macOS routes `.text` to a text editor.
|
||||
- [ ] **B14.** `OPEN_CONFIG` opens via `QDesktopServices::openUrl` without `text` kind hint — same problem.
|
||||
- [ ] **B15.** `SHOW_CHILD_EXITED` fires unconditionally (`MainWindow.cpp:1379-1387`, `GhosttySurface.cpp:466-498`). macOS gates on `runtime_ms > 0` and `abnormalCommandExitRuntime` config; Qt shows the banner for fast `exit 0` cases.
|
||||
- [ ] **B16.** `COPY_TITLE_TO_CLIPBOARD` copies the WINDOW title (`MainWindow.cpp:1280-1284`, `:552`), not the surface title. On a multi-tab window, the wrong title gets copied. macOS copies per-surface.
|
||||
- [ ] **B17.** `PROMPT_TITLE` with target=APP is no-op (`MainWindow.cpp:1271`). macOS promotes to `NSApp.mainWindow`.
|
||||
- [ ] **B18.** Many actions in `default: return false;` (`MainWindow.cpp:1603-1604`):
|
||||
- `PWD` — breaks new tab/split working-dir inheritance.
|
||||
- `GOTO_WINDOW` — multi-window cycle.
|
||||
- `PRESENT_TERMINAL` — bring-to-front.
|
||||
- `KEY_TABLE` — bindable mode tables silent.
|
||||
- `READONLY` — read-only state silent.
|
||||
- `COLOR_CHANGE` — OSC 4/10/11/12 routing silent.
|
||||
- `RENDER_INSPECTOR` — inspector won't repaint between frames.
|
||||
- `CELL_SIZE` — window won't snap to cell grid.
|
||||
- `SIZE_LIMIT` — never honors min-size from libghostty.
|
||||
- `TOGGLE_BACKGROUND_OPACITY`, `FLOAT_WINDOW`, `SECURE_INPUT`, `UNDO`/`REDO`, `CHECK_FOR_UPDATES`, `TOGGLE_TAB_OVERVIEW`, `TOGGLE_WINDOW_DECORATIONS` — feature gaps (mostly matching GTK).
|
||||
|
||||
### Input / keyboard / mouse
|
||||
|
||||
- [ ] **B19.** Mouse buttons 4-11 not delivered (`GhosttySurface.cpp:710-715`). Only Left/Right/Middle mapped; back/forward buttons silently dropped. macOS + GTK both handle 4-11.
|
||||
- [ ] **B20.** Modifier release doesn't synthesize event (`sendKey`). Bare Shift/Ctrl/Alt presses don't produce kitty progressive-enhancement events. macOS uses `flagsChanged`; GTK derives from physical_key.
|
||||
- [ ] **B21.** `consumed_mods` only computed for printable events (`GhosttySurface.cpp:699-701`). Keypad/function/Backspace/arrows lose consumed-mods info. macOS + GTK compute unconditionally.
|
||||
- [ ] **B22.** Caps Lock + Num Lock state never set in mods (`translateMods`). Kitty CSI-u relies on these bits.
|
||||
- [ ] **B23.** Sided modifiers (left vs right) not reported. `left_shift` vs `right_shift` keybinds can't fire. macOS + GTK both populate `mods.sides.*`.
|
||||
- [ ] **B24.** No mouse-enter/leave callback to libghostty (`GhosttySurface.cpp:927-930`). Hover state, OSC-8 link arming, mouse-report sequences stay armed after pointer leaves. macOS + GTK both notify libghostty.
|
||||
- [ ] **B25.** `MOUSE_SHAPE` action not honored at all. Cursor stays OS default regardless of what the running program (e.g. `vim`) requests. macOS + GTK both implement.
|
||||
- [ ] **B26.** `MOUSE_VISIBILITY` (hide-on-typing) not honored. macOS + GTK both implement.
|
||||
- [ ] **B27.** Right-click swallowed when program isn't mouse-capturing (`GhosttySurface.cpp:742-745`, `:782-787`). Qt opens its context menu without ever sending the right-press to libghostty. macOS + GTK send press first, only show menu if core didn't consume — so word-select-then-menu can fire.
|
||||
- [ ] **B28.** Click-to-focus also reports the click to libghostty. macOS + GTK suppress the matching mouse-up. Qt sends both, so a focus-grabbing click is visible to running programs.
|
||||
- [ ] **B29.** `XkbState` uses default layout, not the live one (`GhosttySurface.cpp:629-641`). User with us+ru layouts gets us-only `unshifted_codepoint` regardless of active group. GTK uses `event.getLayout()`.
|
||||
- [ ] **B30.** Wheel: `pixelDelta` ignored, momentum/precision unset (`GhosttySurface.cpp:919-925`). Trackpad on Wayland is notchy; kitty smooth-scroll never engages. macOS uses precise + momentum flags.
|
||||
- [ ] **B31.** Drag-drop URL escaping uses bash-only `'\''` (`GhosttySurface.cpp:889-894`). macOS + GTK use a unified `Shell.escape` / `ShellEscapeWriter` that handles backslashes, newlines, and non-POSIX shells.
|
||||
- [ ] **B32.** Plain URL drop not distinguished from file drop. `http://...` becomes a quoted argument instead of pasted text.
|
||||
|
||||
### Window / tab / split
|
||||
|
||||
- [ ] **B33.** No new-window cascade or position restore. Every Ghastty window opens at 800×600 stacked on top of the previous on X11. Doesn't read `window-position-x/y`, `window-width/height`. macOS cascades + restores; GTK reads the size from the surface.
|
||||
- [ ] **B34.** Tab tear-off can't be dropped on another window's bar (`TabWidget.cpp:165-173`). macOS + GTK both natively support cross-window tab adoption.
|
||||
- [ ] **B35.** Split focus order sorts by widget center, not split tree (`MainWindow.cpp:809-858`). Nested unbalanced trees cycle in a different order than macOS+GTK use.
|
||||
- [ ] **B36.** QSplitter handle drag bypasses libghostty (`MainWindow.cpp:381`). Mouse-drag updates Qt's splitter ratios but never tells libghostty; "split equalize" later won't restore correctly.
|
||||
- [ ] **B37.** Split equalize is per-splitter, not tree-aware (`MainWindow.cpp:886-896`). 3-pane vertical next to 1-pane gets 1:1 instead of 3:1. macOS + GTK use `surfaceTree.equalized()` which weights by leaf count.
|
||||
- [ ] **B38.** No `split-preserve-zoom` config. macOS persists zoom across focus moves with `navigation` setting.
|
||||
- [ ] **B39.** Tab right-click context menu absent. macOS + GTK have full menu (Close/Close-Others/Close-Right/Rename/Pin).
|
||||
- [ ] **B40.** `window-decoration` only handles `none` (`MainWindow.cpp:268`). `auto`/`client`/`server` all collapse.
|
||||
- [ ] **B41.** `window-theme` partial (`MainWindow.cpp:1040`). `ghostty` mode (luminance-detected from background color) and full OS-scheme follow not implemented; pre-Qt 6.8 has zero theming.
|
||||
|
||||
### Quick terminal
|
||||
|
||||
- [ ] **B42.** No animation (slide-in/out). macOS uses `NSAnimationContext`.
|
||||
- [ ] **B43.** `quick-terminal-screen` not honored. macOS resolves which monitor.
|
||||
- [ ] **B44.** `quick-terminal-position = center` not handled (`MainWindow.cpp:700`).
|
||||
- [ ] **B45.** `quick-terminal-space-behavior` not honored.
|
||||
- [ ] **B46.** No fallback for non-Wayland — `LayerShellQt::Window::get()` returning null leaves a regular window without telling libghostty.
|
||||
|
||||
### Misc
|
||||
|
||||
- [ ] **B47.** `reload-config` doesn't propagate `window-decoration` / `fullscreen` / `maximize` to existing windows.
|
||||
- [ ] **B48.** `s_quitDelayMs` cached at init — runtime config reload doesn't update it.
|
||||
- [ ] **B49.** Inspector window: hard-coded 800×600 each time — no autosave.
|
||||
|
||||
---
|
||||
|
||||
## 🟡 Inconsistent (works, but feels wrong)
|
||||
|
||||
- [ ] **I1.** Close-confirmation buttons "Yes/No" instead of "Cancel/Close" with destructive style. Not localized. macOS uses native NSAlert; GTK uses Adw.MessageDialog with `close-response: cancel`.
|
||||
- [ ] **I2.** Bell mark `"● "` prefix vs macOS 🔔 vs GTK `setNeedsAttention`.
|
||||
- [ ] **I3.** `MOVE_TAB` clamps; GTK wraps. Qt matches macOS but mismatches GTK.
|
||||
- [ ] **I4.** `GOTO_TAB:99` does nothing; macOS clamps to last tab; GTK clamps via `@min`.
|
||||
- [ ] **I5.** `MOUSE_OVER_LINK` becomes a Qt tooltip; macOS+GTK use a dedicated overlay.
|
||||
- [ ] **I6.** `PROGRESS_REPORT` collapses ERROR/PAUSE/INDETERMINATE to a boolean.
|
||||
- [ ] **I7.** `COMMAND_FINISHED` ignores `notify-on-command-finish` config (`.never`/`.unfocused`/`.always`), `notify-on-command-finish-after`, and bell mode.
|
||||
- [ ] **I8.** `DESKTOP_NOTIFICATION` is app-target only; `requireFocus` not honored.
|
||||
- [ ] **I9.** Bell `attention` fallback hardcoded (`MainWindow.cpp:910`) — `configGet` failing silently falls back to `BellAttention`, ignoring user config.
|
||||
- [ ] **I10.** Cross-window split DnD unsupported. GTK matches; macOS has it.
|
||||
|
||||
---
|
||||
|
||||
## ⚪ Missing config options (silently dropped)
|
||||
|
||||
- [ ] **C1.** `window-save-state`
|
||||
- [ ] **C2.** `window-step-resize`
|
||||
- [ ] **C3.** `window-width`, `window-height`
|
||||
- [ ] **C4.** `window-position-x`, `window-position-y`
|
||||
- [ ] **C5.** `window-padding-balance`, `window-padding-color`
|
||||
- [ ] **C6.** `window-colorspace`
|
||||
- [ ] **C7.** `window-inherit-working-directory`
|
||||
- [ ] **C8.** `window-inherit-font-size`
|
||||
- [ ] **C9.** `window-title-font-family`
|
||||
- [ ] **C10.** `bell-audio-path`, `bell-audio-volume`
|
||||
- [ ] **C11.** `quick-terminal-screen`
|
||||
- [ ] **C12.** `quick-terminal-animation-duration`
|
||||
- [ ] **C13.** `mouse-hide-while-typing`
|
||||
- [ ] **C14.** `background-image*`
|
||||
- [ ] **C15.** `split-divider-color`
|
||||
- [ ] **C16.** `clipboard-trim-trailing-spaces`
|
||||
- [ ] **C17.** `clipboard-paste-protection`
|
||||
- [ ] **C18.** `progress-style`
|
||||
- [ ] **C19.** `split-preserve-zoom`
|
||||
- [ ] **C20.** `initial-window`
|
||||
- [ ] **C21.** `app-notifications` (per-category gating)
|
||||
|
||||
---
|
||||
|
||||
## ✅ Already correct (audit confirmed)
|
||||
|
||||
- HiDPI mouse coords (logical px to libghostty)
|
||||
- Tab/Backtab focus traversal capture
|
||||
- Auto-repeat synthesized release dropping
|
||||
- Tab title elide + width cap
|
||||
- Inspector lifetime via QPointer + dtor ordering
|
||||
- Most QPointer captures in onAction queued lambdas
|
||||
- Clipboard read/write via QClipboard
|
||||
- IME preedit gating against ASCII duplicate-typing on text-input-v3 (KDE)
|
||||
- Frame timer single-shared
|
||||
- `unfocused-split-opacity` + `unfocused-split-fill`
|
||||
|
||||
---
|
||||
|
||||
## Recommended fix order
|
||||
|
||||
### Tier 1 — short (≤30 lines each), user-visible
|
||||
|
||||
- B1 quit-timer on natural close
|
||||
- B4 `confirm-close-surface` config read
|
||||
- B6 `CLOSE_TAB` mode
|
||||
- B7 `INITIAL_SIZE` HiDPI
|
||||
- B11 `RELOAD_CONFIG` global
|
||||
- B16 `COPY_TITLE_TO_CLIPBOARD` per-surface
|
||||
- B19 mouse buttons 4-11
|
||||
- B25 `MOUSE_SHAPE`
|
||||
- B26 `MOUSE_VISIBILITY`
|
||||
- B29 XKB live layout
|
||||
- B44 `quick-terminal-position = center`
|
||||
- I9 bell-attention fallback
|
||||
|
||||
### Tier 2 — medium (50-150 lines), user-visible
|
||||
|
||||
- B15 child-exited gating
|
||||
- B22-23 modifier mods (caps/num/sided)
|
||||
- B24 mouse-enter/leave callbacks
|
||||
- B27-28 right-click + click-to-focus suppression
|
||||
- B33 window placement (cascade + position config)
|
||||
- B37 tree-aware equalize
|
||||
- B39 tab right-click menu
|
||||
- B40 window-decoration full enum
|
||||
- B42 quick-terminal animation
|
||||
|
||||
### Tier 3 — feature work (200+ lines or new modules)
|
||||
|
||||
- Undo close-tab/window
|
||||
- Window save/restore
|
||||
- Cross-window tab/split DnD
|
||||
- Inspector autosave + presentation
|
||||
- Many of the action `default: return false;` items (PWD, GOTO_WINDOW, PRESENT_TERMINAL, KEY_TABLE, COLOR_CHANGE, etc.)
|
||||
|
||||
---
|
||||
|
||||
## How to use this document
|
||||
|
||||
1. Pick an item and tick `[ ]` → `[x]` when the commit lands.
|
||||
2. Append the commit hash next to the line: `[x] **B7.** ... — fixed in abc1234`.
|
||||
3. If a finding turns out to be wrong on closer inspection, strike it through with `~~B7.~~ ...` and add a one-line explanation.
|
||||
4. New parity issues discovered during implementation: add to the appropriate section with the next ID in sequence.
|
||||
Loading…
Reference in New Issue