qt: fix resize-overlay first-grid logic so it actually shows

The previous rewrite suppressed the first grid step under
'after-first' mode, but conflated 'first' with 'first grid step'
instead of 'initial size at surface creation.' Net effect: short
window resizes that crossed exactly one grid boundary never showed
the overlay because the only grid step they produced was treated
as the suppressed first step.

Restructure: m_firstGridSeen now tracks the very first
showResizeOverlay call (the implicit layout pass before the user
has touched anything), records that initial size, and bails under
'after-first'. Every subsequent call — whether the grid steps or
not — caches the current "cols × rows" text, pushes the deadline,
and triggers update(). The user-visible behaviour:

  - resize-overlay = always: overlay shows on every resize event,
    starting at surface layout.
  - resize-overlay = after-first (default): overlay is suppressed
    on the surface's first layout but shows on every later resize.
  - resize-overlay = never: never shows.

Also drop the m_image.isNull() early-return at the top of paintEvent
so the overlay can still draw before the first FBO render lands.

Co-Authored-By: claude-flow <ruv@ruv.net>
pull/12846/head
ntomsic 2026-05-20 17:00:01 -05:00
parent af567feb83
commit 56918dc3db
1 changed files with 25 additions and 23 deletions

View File

@ -275,16 +275,15 @@ void GhosttySurface::renderTerminal() {
}
void GhosttySurface::paintEvent(QPaintEvent *) {
if (m_image.isNull()) return;
QPainter painter(this);
// Blit the framebuffer 1:1. m_image carries the device pixel ratio, so
// the QPointF overload draws it at its true logical size: when in sync
// that exactly fills the widget, and mid-resize the content keeps its
// real size instead of stretching to the (already-resized) widget.
// CompositionMode_Source replaces the transparent widget pixels with
// the terminal image, alpha included, so its translucency is kept.
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawImage(QPointF(0, 0), m_image);
// Blit the framebuffer 1:1 if we have one. m_image carries the
// device pixel ratio, so the QPointF overload draws it at its true
// logical size. CompositionMode_Source replaces the transparent
// widget pixels with the terminal image (alpha included).
if (!m_image.isNull()) {
painter.setCompositionMode(QPainter::CompositionMode_Source);
painter.drawImage(QPointF(0, 0), m_image);
}
// Unfocused-split dimming: a translucent fill over an inactive pane.
// Only split panes (a QSplitter parent) are dimmed, matching GTK.
@ -470,24 +469,27 @@ void GhosttySurface::showResizeOverlay() {
const QString mode = cfgString(cfg, "resize-overlay");
if (mode == QLatin1String("never")) return;
// The "after-first" mode hides the overlay until the grid has
// stepped at least once after the surface was created.
const bool gridChanged =
sz.columns != m_lastCols || sz.rows != m_lastRows;
if (gridChanged) {
const bool first = !m_firstGridSeen;
// First-call short-circuit. resizeEvent fires once when the
// surface is first laid out, before the user has done any
// resizing. Per `resize-overlay = after-first` (the default),
// we suppress that initial show — record the grid size and
// bail. Subsequent resizes always flow through.
if (!m_firstGridSeen) {
m_firstGridSeen = true;
m_lastCols = sz.columns;
m_lastRows = sz.rows;
m_firstGridSeen = true;
m_resizeOverlayText =
QStringLiteral("%1 × %2").arg(sz.columns).arg(sz.rows);
if (mode == QLatin1String("after-first") && first) return;
} else if (m_resizeOverlayText.isEmpty()) {
// No grid step has happened yet AND no overlay text is cached —
// nothing to display.
return;
if (mode == QLatin1String("after-first")) return;
// mode == "always": fall through and show the initial size too.
}
// Update the cached text whenever the grid actually steps.
if (sz.columns != m_lastCols || sz.rows != m_lastRows) {
m_lastCols = sz.columns;
m_lastRows = sz.rows;
}
m_resizeOverlayText =
QStringLiteral("%1 × %2").arg(sz.columns).arg(sz.rows);
// Push the hide deadline forward on every resizeEvent so the
// overlay stays visible until the user actually stops resizing.
// Without this, slow drags between cell-boundary crossings would