diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 4a8bc16ef6f2..2ae36bc36b3a 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -327,6 +327,7 @@ NativeWindowViews::NativeWindowViews( last_window_state_ = ui::SHOW_STATE_FULLSCREEN; else last_window_state_ = ui::SHOW_STATE_NORMAL; + last_normal_bounds_ = GetBounds(); #endif } diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 379dc4ceaaf3..110a4e9d4373 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -211,6 +211,23 @@ class NativeWindowViews : public NativeWindow, ui::WindowShowState last_window_state_; + // There's an issue with restore on Windows, that sometimes causes the Window + // to receive the wrong size (#2498). To circumvent that, we keep tabs on the + // size of the window while in the normal state (not maximized, minimized or + // fullscreen), so we restore it correctly. + gfx::Rect last_normal_bounds_; + gfx::Rect last_normal_bounds_before_move_; + + // last_normal_bounds_ may or may not require update on WM_MOVE. When a + // window is maximized, it is moved (WM_MOVE) to maximum size first and then + // sized (WM_SIZE). In this case, last_normal_bounds_ should not update. We + // keep last_normal_bounds_candidate_ as a candidate which will become valid + // last_normal_bounds_ if the moves are consecutive with no WM_SIZE event in + // between. + gfx::Rect last_normal_bounds_candidate_; + + bool consecutive_moves_; + // In charge of running taskbar related APIs. TaskbarHost taskbar_host_; diff --git a/atom/browser/native_window_views_win.cc b/atom/browser/native_window_views_win.cc index d6f57b6aead8..1b523e90b804 100644 --- a/atom/browser/native_window_views_win.cc +++ b/atom/browser/native_window_views_win.cc @@ -127,6 +127,10 @@ bool NativeWindowViews::PreHandleMSG( case WM_SIZE: { // Handle window state change. HandleSizeEvent(w_param, l_param); + + consecutive_moves_ = false; + last_normal_bounds_before_move_ = last_normal_bounds_; + return false; } case WM_MOVING: { @@ -134,6 +138,15 @@ bool NativeWindowViews::PreHandleMSG( ::GetWindowRect(GetAcceleratedWidget(), (LPRECT)l_param); return false; } + case WM_MOVE: { + if (last_window_state_ == ui::SHOW_STATE_NORMAL) { + if (consecutive_moves_) + last_normal_bounds_ = last_normal_bounds_candidate_; + last_normal_bounds_candidate_ = GetBounds(); + consecutive_moves_ = true; + } + return false; + } default: return false; } @@ -145,6 +158,9 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { switch (w_param) { case SIZE_MAXIMIZED: last_window_state_ = ui::SHOW_STATE_MAXIMIZED; + if (consecutive_moves_) { + last_normal_bounds_ = last_normal_bounds_before_move_; + } NotifyWindowMaximize(); break; case SIZE_MINIMIZED: @@ -152,20 +168,35 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) { NotifyWindowMinimize(); break; case SIZE_RESTORED: - switch (last_window_state_) { - case ui::SHOW_STATE_MAXIMIZED: - last_window_state_ = ui::SHOW_STATE_NORMAL; - NotifyWindowUnmaximize(); - break; - case ui::SHOW_STATE_MINIMIZED: - if (IsFullscreen()) { - last_window_state_ = ui::SHOW_STATE_FULLSCREEN; - NotifyWindowEnterFullScreen(); - } else { + if (last_window_state_ == ui::SHOW_STATE_NORMAL) { + // Window was resized so we save it's new size. + last_normal_bounds_ = GetBounds(); + last_normal_bounds_before_move_ = last_normal_bounds_; + } else { + switch (last_window_state_) { + case ui::SHOW_STATE_MAXIMIZED: last_window_state_ = ui::SHOW_STATE_NORMAL; - NotifyWindowRestore(); - } - break; + + // Don't force out last known bounds onto the window as Windows + // actually gets these correct + + NotifyWindowUnmaximize(); + break; + case ui::SHOW_STATE_MINIMIZED: + if (IsFullscreen()) { + last_window_state_ = ui::SHOW_STATE_FULLSCREEN; + NotifyWindowEnterFullScreen(); + } else { + last_window_state_ = ui::SHOW_STATE_NORMAL; + + // When the window is restored we resize it to the previous known + // normal size. + SetBounds(last_normal_bounds_, false); + + NotifyWindowRestore(); + } + break; + } } break; } diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index a0425d7ffc63..f7aa6436a47c 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -1320,6 +1320,34 @@ describe('browser-window module', function () { }) }) + describe('BrowserWindow.restore()', function () { + it('should restore the previous window size', function () { + if (w != null) w.destroy() + + w = new BrowserWindow({ + minWidth: 800, + width: 800 + }) + + const initialSize = w.getSize() + w.minimize() + w.restore() + assertBoundsEqual(w.getSize(), initialSize) + }) + }) + + describe('BrowserWindow.unmaximize()', function () { + it('should restore the previous window position', function () { + if (w != null) w.destroy() + w = new BrowserWindow() + + const initialPosition = w.getPosition() + w.maximize() + w.unmaximize() + assertBoundsEqual(w.getPosition(), initialPosition) + }) + }) + describe('parent window', function () { let c = null