From ca8e1e4af6a45d61bd0abc8104f6d8cfc3e9ac14 Mon Sep 17 00:00:00 2001 From: "trop[bot]" <37223003+trop[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 10:53:04 -0500 Subject: [PATCH] fix: improve single-pixel resize handling on Windows (#44722) * fix: improve single-pixel resize handling Co-authored-by: Shelley Vohr * Update spec/api-browser-window-spec.ts Co-authored-by: Niklas Wenzel Co-authored-by: Shelley Vohr * Update shell/browser/native_window_views.cc Co-authored-by: Niklas Wenzel Co-authored-by: Shelley Vohr --------- Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr --- shell/browser/native_window_views.cc | 22 ++++++++++++++++------ spec/api-browser-window-spec.ts | 21 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index 12617c1db77..c6b9d1cf23c 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -1661,18 +1661,28 @@ void NativeWindowViews::OnWidgetBoundsChanged(views::Widget* changed_widget, if (changed_widget != widget()) return; - // |GetWindowBoundsInScreen| has a ~1 pixel margin of error, so if we check - // existing bounds directly against the new bounds without accounting for that - // we'll have constant false positives when the window is moving but the user - // hasn't changed its size at all. - auto areWithinOnePixel = [](gfx::Size old_size, gfx::Size new_size) -> bool { +#if BUILDFLAG(IS_WIN) + // OnWidgetBoundsChanged is emitted both when a window is moved and when a + // window is resized. If the window is moving, then + // WidgetObserver::OnWidgetBoundsChanged is being called from + // Widget::OnNativeWidgetMove() and not Widget::OnNativeWidgetSizeChanged. + // |GetWindowBoundsInScreen| has a ~1 pixel margin + // of error because it converts from floats to integers between calculations, + // so if we check existing bounds directly against the new bounds without + // accounting for that we'll have constant false positives when the window is + // moving but the user hasn't changed its size at all. + auto isWithinOnePixel = [](gfx::Size old_size, gfx::Size new_size) -> bool { return base::IsApproximatelyEqual(old_size.width(), new_size.width(), 1) && base::IsApproximatelyEqual(old_size.height(), new_size.height(), 1); }; + if (is_moving_ && isWithinOnePixel(widget_size_, bounds.size())) + return; +#endif + // We use |GetBounds| to account for minimized windows on Windows. const auto new_bounds = GetBounds(); - if (!areWithinOnePixel(widget_size_, new_bounds.size())) { + if (widget_size_ != new_bounds.size()) { NotifyWindowResize(); widget_size_ = new_bounds.size(); } diff --git a/spec/api-browser-window-spec.ts b/spec/api-browser-window-spec.ts index 74affcf5bd1..6d72d8efca1 100755 --- a/spec/api-browser-window-spec.ts +++ b/spec/api-browser-window-spec.ts @@ -1544,6 +1544,16 @@ describe('BrowserWindow module', () => { await expect(once(w, 'resized')).to.eventually.be.fulfilled(); }); }); + + it('does not emits the resize event for move-only changes', async () => { + const [x, y] = w.getPosition(); + + w.once('resize', () => { + expect.fail('resize event should not be emitted'); + }); + + w.setBounds({ x: x + 10, y: y + 10 }); + }); }); describe('BrowserWindow.setSize(width, height)', () => { @@ -1557,6 +1567,17 @@ describe('BrowserWindow module', () => { expectBoundsEqual(w.getSize(), size); }); + it('emits the resize event for single-pixel size changes', async () => { + const [width, height] = w.getSize(); + const size = [width + 1, height - 1]; + + const resized = once(w, 'resize'); + w.setSize(size[0], size[1]); + await resized; + + expectBoundsEqual(w.getSize(), size); + }); + ifit(process.platform === 'darwin')('on macOS', () => { it('emits \'resized\' event after animating', async () => { const size = [300, 400];