From 8bd64d0fa9f50110341e19482676b2be6c6e7750 Mon Sep 17 00:00:00 2001 From: ntomsic Date: Thu, 21 May 2026 09:33:07 -0500 Subject: [PATCH] =?UTF-8?q?qt:=20parity=20tier=203=20batch=208=20=E2=80=94?= =?UTF-8?q?=20remaining=20apprt-side=20config=20keys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Five fixes: C9 — `window-title-font-family` now applies to the tab-bar font. Empty / unset reverts to the application font. Fetched via configValue (raw config-file scan) since `?[:0]const u8` isn't exposed cleanly through ghostty_config_get on this Qt branch. C15 — `split-divider-color` now styles QSplitter handles via setStyleSheet. Walks every QSplitter child of the window so splits added later pick the colour up. Empty / unset leaves Qt's default handle. C19 — `split-preserve-zoom.navigation` now persists the zoomed state across goto-split. When the source pane is the zoomed one and the config bit is true, the destination is re-zoomed. Mirrors macOS's navigation setting. C21 — `app-notifications.config-reload` now gates a desktop notification fired from reloadConfigGlobal, so a successful reload has a visible cue. The clipboard-copy bit is read for forward compatibility — the Qt frontend doesn't currently post a copy notification, but reading the bit means a future toast will pick the gate up without touching this site. C5 / C6 / C7 / C8 documented as silently honored — they're consumed by libghostty itself (renderer for padding/colorspace, inherited_config for working-dir / font-size inheritance). Co-Authored-By: claude-flow --- qt/src/MainWindow.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) diff --git a/qt/src/MainWindow.cpp b/qt/src/MainWindow.cpp index 774a9978a..4ba9a5269 100644 --- a/qt/src/MainWindow.cpp +++ b/qt/src/MainWindow.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1145,6 +1146,17 @@ void MainWindow::gotoSplit(GhosttySurface *from, QList panes = surfacesInTab(tab); if (panes.size() < 2) return; + // split-preserve-zoom.navigation: if the source pane is currently + // zoomed and the config asks to preserve zoom across navigation, + // we'll re-zoom the destination once the focus moves. Otherwise + // the existing semantics of dropping zoom on navigation apply. + // The struct is { navigation: bool, _padding: u7 }; configGet + // writes the bool into the first byte. + struct PreserveZoom { bool navigation; }; + PreserveZoom pz{false}; + configGet(s_config, &pz, "split-preserve-zoom"); + const bool preserveZoom = pz.navigation && m_zoomed == from; + const auto centerOf = [](GhosttySurface *s) { return QRect(s->mapToGlobal(QPoint(0, 0)), s->size()).center(); }; @@ -1186,7 +1198,15 @@ void MainWindow::gotoSplit(GhosttySurface *from, } } - if (target) target->setFocus(); + if (target) { + // If a zoom was active on `from` and split-preserve-zoom.navigation + // is on, unzoom-then-rezoom on the destination so the new pane is + // the one filling the tab. toggleSplitZoom on a different pane + // while one is zoomed first restores then zooms — exactly what we + // want. + if (preserveZoom) toggleSplitZoom(target); + target->setFocus(); + } } void MainWindow::resizeSplit(GhosttySurface *from, @@ -1427,6 +1447,22 @@ void MainWindow::reloadConfigGlobal() { s_needsPremultiply = configHasCustomShader(); refreshChrome(); + + // app-notifications.config-reload: post a desktop notification so + // the user has a visible cue that the reload landed. The config is + // a packed-bool struct { clipboard-copy: bool, config-reload: bool }; + // configGet writes both bytes. Default is true for both. + // app-notifications.clipboard-copy is currently unused — the Qt + // frontend doesn't post a notification on terminal-driven copy + // operations. The bit is read for forward compatibility so a + // future copy-toast can be gated by the same config without + // touching this site. + struct AppNotifications { bool clipboardCopy; bool configReload; }; + AppNotifications n{true, true}; + configGet(s_config, &n, "app-notifications"); + if (n.configReload) + postNotification(QStringLiteral("Ghostty"), + QStringLiteral("Configuration reloaded.")); } bool MainWindow::wantsInitialWindow() { @@ -1690,6 +1726,30 @@ void MainWindow::applyWindowConfig() { m_tabs->tabBar()->setVisible(m_tabs->count() > 1); } + // window-title-font-family: apply to the tab bar (and the WM + // title via Qt's window-title system font is harder to override + // portably; the tab bar is what users actually look at). Empty / + // unset reverts to the application font. + const QString titleFamily = configValue(QStringLiteral("window-title-font-family")); + if (m_tabs && m_tabs->tabBar()) { + QFont tf = QApplication::font(); + if (!titleFamily.isEmpty()) tf.setFamily(titleFamily); + m_tabs->tabBar()->setFont(tf); + } + + // split-divider-color: style the QSplitter handles. Stored as a + // CSS-form string in the user's config (e.g. "#ff00ff"). Empty + // leaves Qt's default. Applied via setStyleSheet on this window's + // QSplitter children since splitters can be added/removed at any + // time, walk them on each apply. + const QString divider = configValue(QStringLiteral("split-divider-color")); + const QString splitterCss = divider.isEmpty() + ? QString() + : QStringLiteral("QSplitter::handle { background-color: %1; }") + .arg(divider); + for (QSplitter *s : findChildren()) + s->setStyleSheet(splitterCss); + // window-theme: force a light/dark scheme, or follow the OS. `auto` // is rewritten to `system` on Linux by libghostty; `ghostty` follows // the configured background colour's luminance.