Repository: napari/napari

Issue:
Persistence of full-screen mode confusing, hard to close/minimize
## 🐛 Bug

Issue copied from @optomanishk image.sc: https://forum.image.sc/t/napari-opens-in-full-screen-mode-and-doesnt-function/58286


----

I’m using the usual example code from a jupyter notebook to start napari UI.
Code:

```py
from skimage import data
import napari

viewer = napari.view_image(data.astronaut(), rgb=True)
napari.run()  # start the event loop and show viewer
```

napari opens in this full-screen mode where none of the options (File - View - Window - Plugins - Help) work. There is no close/maximize/minimize button either.

I get this warning:
```
WARNING: QWindowsWindow::setGeometry: Unable to set geometry 1920x1080+1928+31 (frame: 1936x1119+1920+0) on QWidgetWindow/"_QtMainWindowClassWindow" on "\\.\DISPLAY2". Resulting geometry: 1920x1061+1928+31 (frame: 1936x1100+1920+0) margins: 8, 31, 8, 8 minimum size: 608x520 MINMAXINFO maxSize=0,0 maxpos=0,0 mintrack=624,559 maxtrack=0,0)
```

----

solved by `napari --reset` ... but it would be nice to avoid that 


related issue: #2971 #3038 #3075 
cc @goanpeca 


Discussion:
Hi, just in case, I was able to reproduce this issue on Windows. I think this is related to https://bugreports.qt.io/browse/QTBUG-41309 

Some workarounds and more info available at:

* https://bugreports.qt.io/browse/QTBUG-41309?focusedCommentId=318322&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-318322
* https://doc.qt.io/qt-5/windows-issues.html#fullscreen-opengl-based-windows

In the maintime, as a way to workaround this without having to reset the preferences you can use the Toggle Fullscreen shortcut (`Ctrl + F` or `Alt + Enter`)

Resolving patch:
diff --git a/napari/_qt/qt_main_window.py b/napari/_qt/qt_main_window.py
--- a/napari/_qt/qt_main_window.py
+++ b/napari/_qt/qt_main_window.py
@@ -23,7 +23,16 @@
 )
 from weakref import WeakValueDictionary
 
-from qtpy.QtCore import QEvent, QEventLoop, QPoint, QProcess, QSize, Qt, Slot
+from qtpy.QtCore import (
+    QEvent,
+    QEventLoop,
+    QPoint,
+    QProcess,
+    QRect,
+    QSize,
+    Qt,
+    Slot,
+)
 from qtpy.QtGui import QIcon
 from qtpy.QtWidgets import (
     QApplication,
@@ -115,6 +124,8 @@ def __init__(
         self.setWindowTitle(self._qt_viewer.viewer.title)
 
         self._maximized_flag = False
+        self._fullscreen_flag = False
+        self._normal_geometry = QRect()
         self._window_size = None
         self._window_pos = None
         self._old_size = None
@@ -204,8 +215,63 @@ def event(self, e: QEvent) -> bool:
             with contextlib.suppress(ValueError):
                 inst = _QtMainWindow._instances
                 inst.append(inst.pop(inst.index(self)))
+
         return super().event(e)
 
+    def isFullScreen(self):
+        # Needed to prevent errors when going to fullscreen mode on Windows
+        # Use a flag attribute to determine if the window is in full screen mode
+        # See https://bugreports.qt.io/browse/QTBUG-41309
+        # Based on https://github.com/spyder-ide/spyder/pull/7720
+        return self._fullscreen_flag
+
+    def showNormal(self):
+        # Needed to prevent errors when going to fullscreen mode on Windows. Here we:
+        #   * Set fullscreen flag
+        #   * Remove `Qt.FramelessWindowHint` and `Qt.WindowStaysOnTopHint` window flags if needed
+        #   * Set geometry to previously stored normal geometry or default empty QRect
+        # Always call super `showNormal` to set Qt window state
+        # See https://bugreports.qt.io/browse/QTBUG-41309
+        # Based on https://github.com/spyder-ide/spyder/pull/7720
+        self._fullscreen_flag = False
+        if os.name == 'nt':
+            self.setWindowFlags(
+                self.windowFlags()
+                ^ (Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
+            )
+            self.setGeometry(self._normal_geometry)
+        super().showNormal()
+
+    def showFullScreen(self):
+        # Needed to prevent errors when going to fullscreen mode on Windows. Here we:
+        #   * Set fullscreen flag
+        #   * Add `Qt.FramelessWindowHint` and `Qt.WindowStaysOnTopHint` window flags if needed
+        #   * Call super `showNormal` to update the normal screen geometry to apply it later if needed
+        #   * Save window normal geometry if needed
+        #   * Get screen geometry
+        #   * Set geometry window to use total screen geometry +1 in every direction if needed
+        # If the workaround is not needed just call super `showFullScreen`
+        # See https://bugreports.qt.io/browse/QTBUG-41309
+        # Based on https://github.com/spyder-ide/spyder/pull/7720
+        self._fullscreen_flag = True
+        if os.name == 'nt':
+            self.setWindowFlags(
+                self.windowFlags()
+                | Qt.FramelessWindowHint
+                | Qt.WindowStaysOnTopHint
+            )
+            super().showNormal()
+            self._normal_geometry = self.normalGeometry()
+            screen_rect = self.windowHandle().screen().geometry()
+            self.setGeometry(
+                screen_rect.left() - 1,
+                screen_rect.top() - 1,
+                screen_rect.width() + 2,
+                screen_rect.height() + 2,
+            )
+        else:
+            super().showFullScreen()
+
     def _load_window_settings(self):
         """
         Load window layout settings from configuration.
@@ -285,8 +351,8 @@ def _set_window_settings(
             self._qt_viewer.dockConsole.setVisible(False)
 
         if window_fullscreen:
-            self.setWindowState(Qt.WindowState.WindowFullScreen)
             self._maximized_flag = window_maximized
+            self.showFullScreen()
         elif window_maximized:
             self.setWindowState(Qt.WindowState.WindowMaximized)
 


Test patch: