Repository: electron/electron (language: cpp)

Issue:
[Bug]: BrowserWindow.unmaximize Will Restore Minimized Window
### Preflight Checklist

- [X] I have read the [Contributing Guidelines](https://github.com/electron/electron/blob/main/CONTRIBUTING.md) for this project.
- [X] I agree to follow the [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md) that this project adheres to.
- [X] I have searched the [issue tracker](https://www.github.com/electron/electron/issues) for a bug report that matches the one I want to file, without success.

### Electron Version

17.0.0-alpha.6

### What operating system are you using?

Windows

### Operating System Version

Windows 10

### What arch are you using?

x64

### Last Known Working Electron version

_No response_

### Expected Behavior

`BrowserWindow.unmaximize` should not restore a minimized window

### Actual Behavior

`BrowserWindow.unmaximize` does restore a minimized window

### Testcase Gist URL

https://gist.github.com/eb364ab237b856b11c9570fa2b257cfb

### Additional Information

The provided gist is a test so it should be runnable by `bugbot`. I've confirmed the behavior on Windows, macOS seems unaffected, I haven't tested Linux.

Root cause might be [that `NativeWindowViews::Unmaximize` calls `widget()->Restore()`](https://github.com/electron/electron/blob/bd10b19b0cdc46cdbadb570af89305e64541b679/shell/browser/native_window_views.cc#L591), so it does the restore behavior, regardless of if the window is maximized or minimized. It should probably do an `IsMaximized()` check before calling `Restore()` to prevent this issue. Could also use some more test coverage to ensure `unmaximize` is a no-op when the window isn't maximized.


Discussion / hints:
Looks like this is a long-standing issue.

@dsanders11 thank you :heart: for writing a test for this. Bisecting with fiddle-core on Linux yields this:

```
$ yarn start bisect 13.0.0 17.0.0-alpha.6 https://gist.github.com/eb364ab237b856b11c9570fa2b257cfb

🏁 finished bisecting across 283 versions [13.0.0 ... 17.0.0-alpha.6]...
#   1 🔴 failed 13.0.1 (test #9)
#   2 🔴 failed 13.1.0 (test #8)
#   3 🔴 failed 13.1.1 (test #7)
#   5 🔴 failed 13.1.3 (test #6)
#   9 🔴 failed 13.1.7 (test #5)
#  18 🔴 failed 13.5.0 (test #4)
#  36 🔴 failed 14.0.0-nightly.20210323 (test #3)
#  71 🔴 failed 14.0.0-beta.5 (test #2)
# 141 🔴 failed 15.0.0-alpha.2 (test #1)
```

Since you say the macOS build is unaffected, it's likely that the issue lies in some of the libviews code that's shared between the Linux and Windows builds but unused by the macOS build.

Fix patch:
diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc
index 2b7abf15e736f..022e7598b4ad0 100644
--- a/shell/browser/native_window_views.cc
+++ b/shell/browser/native_window_views.cc
@@ -581,14 +581,16 @@ void NativeWindowViews::Maximize() {
 #endif
 
 void NativeWindowViews::Unmaximize() {
+  if (IsMaximized()) {
 #if defined(OS_WIN)
-  if (transparent()) {
-    SetBounds(restore_bounds_, false);
-    return;
-  }
+    if (transparent()) {
+      SetBounds(restore_bounds_, false);
+      return;
+    }
 #endif
 
-  widget()->Restore();
+    widget()->Restore();
+  }
 }
 
 bool NativeWindowViews::IsMaximized() {
diff --git a/spec-main/api-browser-window-spec.ts b/spec-main/api-browser-window-spec.ts
index fddfaa6f3bd07..121dbe10e9f65 100644
--- a/spec-main/api-browser-window-spec.ts
+++ b/spec-main/api-browser-window-spec.ts
@@ -3379,6 +3379,29 @@ describe('BrowserWindow module', () => {
       w.unmaximize();
       expectBoundsEqual(w.getPosition(), initialPosition);
     });
+
+    // TODO(dsanders11): Enable once minimize event works on Linux again.
+    //                   See https://github.com/electron/electron/issues/28699
+    ifit(process.platform !== 'linux')('should not restore a minimized window', async () => {
+      const w = new BrowserWindow();
+      const minimize = emittedOnce(w, 'minimize');
+      w.minimize();
+      await minimize;
+      w.unmaximize();
+      await delay(1000);
+      expect(w.isMinimized()).to.be.true();
+    });
+
+    it('should not change the size or position of a normal window', async () => {
+      const w = new BrowserWindow();
+
+      const initialSize = w.getSize();
+      const initialPosition = w.getPosition();
+      w.unmaximize();
+      await delay(1000);
+      expectBoundsEqual(w.getSize(), initialSize);
+      expectBoundsEqual(w.getPosition(), initialPosition);
+    });
   });
 
   describe('setFullScreen(false)', () => {


Test patch: