Repository: spyder-ide/spyder

Issue:
I never want to restart Spyder when the display dpi changes 
## Description

### What steps will reproduce the problem?

<!--- You can use Markdown here --->

Spyder asks me when connecting or disconnecting  my second monitor to restart because the dpi changed.

Both internal lapotp, as well as external are 1080p. The external one is connected via HDMI to a dock which connects via Thunderbolt to my laptop.
The windows scaling setting for both monitors is 100%

No spyder setting (automatic, personal or fixed dpi) seem to prevent this dialog and it is very annoying. It also appears when awaking my pc from sleep.

A soulution could be "hide this dialog for ever" instead of hide this dialog for the current sesseion



## Versions

* Spyder version: 4.1.3 
* Python version: 3.7.7
* Qt version: 5.9.6
* PyQt5 version: 5.9.2
* Operating System: Windows 10

### Dependencies

```

# Mandatory:
atomicwrites >=1.2.0           :  1.4.0 (OK)
chardet >=2.0.0                :  3.0.4 (OK)
cloudpickle >=0.5.0            :  1.4.1 (OK)
diff_match_patch >=20181111    :  20181111 (OK)
intervaltree                   :  None (OK)
IPython >=4.0                  :  7.13.0 (OK)
jedi =0.15.2                   :  0.15.2 (OK)
nbconvert >=4.0                :  5.6.1 (OK)
numpydoc >=0.6.0               :  0.9.2 (OK)
paramiko >=2.4.0               :  2.7.1 (OK)
parso =0.5.2                   :  0.5.2 (OK)
pexpect >=4.4.0                :  4.8.0 (OK)
pickleshare >=0.4              :  0.7.5 (OK)
psutil >=5.3                   :  5.7.0 (OK)
pygments >=2.0                 :  2.6.1 (OK)
pylint >=0.25                  :  2.5.0 (OK)
pyls >=0.31.9;<0.32.0          :  0.31.10 (OK)
qdarkstyle >=2.8               :  2.8.1 (OK)
qtawesome >=0.5.7              :  0.7.0 (OK)
qtconsole >=4.6.0              :  4.7.3 (OK)
qtpy >=1.5.0                   :  1.9.0 (OK)
rtree >=0.8.3                  :  0.9.4 (OK)
sphinx >=0.6.6                 :  3.0.3 (OK)
spyder_kernels >=1.9.1;<1.10.0 :  1.9.1 (OK)
watchdog                       :  None (OK)
zmq >=17                       :  18.1.1 (OK)

# Optional:
cython >=0.21                  :  None (OK)
matplotlib >=2.0.0             :  3.1.3 (OK)
numpy >=1.7                    :  1.18.1 (OK)
pandas >=0.13.1                :  1.0.3 (OK)
scipy >=0.17.0                 :  1.4.1 (OK)
sympy >=0.7.3                  :  None (OK)
```



Discussion:
Hi @Nosferuity thanks for the feedback! I also think that the behavior of the message should be improved (the way we are detecting the screen scale change). We will be looking to improve this for a future release :+1: 
What do you guys think @spyder-ide/core-developers ?
>I also think that the behavior of the message should be improved (the way we are detecting the screen scale change). We will be looking to improve this for a future release 👍

Until we implement some validation of this functionality (with actual external monitors) we might not provide the best UX, so I agree that this dialog should allow for a (don't show ever again) until we sort issues out with Docks, External monitors, Sleep etc.

The problem with not showing the message ever again is that people wouldn't know that a restart is effectively necessary in some scenarios.

That's why we added the option to ignore the message during the current session. Is that not enough for you @Nosferuity?
>The problem with not showing the message ever again is that people wouldn't know that a restart is effectively necessary in some scenarios.

I understand, but since we cannot provide its use reliably it will become a nuisance until properly fixed and for that we need actual hardware.


>That's why we added the option to ignore the message during the current session. Is that not enough for you @Nosferuity?

The user wrote:

>A soulution could be "hide this dialog for ever" instead of hide this dialog for the current sesseion
> I understand, but since we cannot provide its use reliably it will become a nuisance until properly fixed and for that we need actual hardware.

There's no way to "fix" this (we discussed the situation at length with @dalthviz). It's a problem in Qt and we really can't do anything about it.

> A soulution could be "hide this dialog for ever" instead of hide this dialog for the current sesseion

I don't agree with this.
> That's why we added the option to ignore the message during the current session. Is that not enough for you @Nosferuity?

Upon restarting Spyder or the PC the message gets again displayed when switching displays, because as the message says it: is only deacitvated for the current session.

I understand that the user who has this the first couple of time might want to restart spyder or react to this in some way, but the user who awakes his laptop from sleep with a second monitor connected or switches from Mirrored/Duplicated/Only Interal/Only External Display has seen this message a lot. 

(It is very easy to loose the progress in the console when clicking on "yes" accidentally. Though this is not really the point as one could have just clicked carefully.)

I would whish for a less interruptive dialog. If this message should not be possible to be hidden by the settings, maybe changing it from:
"click yes to restart spyder because your DPI changed ->Yes/No" 
to a:
"your DPI changed, you should restart spyder manually ->OK" would work?
> "your DPI changed, you should restart spyder manually ->OK" would work?

I agree with this, i.e. making the default action (the one you get when pressing Enter) to dismiss the dialog instead of triggering a restart.

@dalthviz, what do you think?
Sure, could be an initial measure to improve the UX of the dialog 👍 (maybe something like `Dismiss` and `Restart now` making dismiss the default option).

However, I think that a more in deep refactor needs to be done to properly trigger the dialog only in the correct scenarios (change in the scale factor which I think was the goal of this dialog in the first place)
> maybe something like Dismiss and Restart now making dismiss the default option).

I really like this suggestion!

> However, I think that a more in deep refactor needs to be done to properly trigger the dialog only in the correct scenarios (change in the scale factor which I think was the goal of this dialog in the first place)

Does Qt really have a correct way to detect this? (I thought it doesn't).
> I really like this suggestion!

:+1:
> Does Qt really have a correct way to detect this? (I thought it doesn't).

I'm not sure, so we need to check. Maybe we can check what the signal is retrieving and add a more in specific validation to trigger the dialog only on resolution/scale change and not in number of screens change.

> I'm not sure, so we need to check. Maybe we can check what the signal is retrieving and add a more in specific validation to trigger the dialog only on resolution/scale change and not in number of screens change.

Ok, please work on that for 4.1.4. If you find that's really not possible (or too hard to do), then please implement your proposed improvement to the message dialog we're showing at the moment.

Resolving patch:
diff --git a/spyder/app/mainwindow.py b/spyder/app/mainwindow.py
--- a/spyder/app/mainwindow.py
+++ b/spyder/app/mainwindow.py
@@ -1395,6 +1395,7 @@ def post_visible_setup(self):
             window = self.window().windowHandle()
             window.screenChanged.connect(self.handle_new_screen)
             self.screen = self.window().windowHandle().screen()
+            self.current_dpi = self.screen.logicalDotsPerInch()
             self.screen.logicalDotsPerInchChanged.connect(
                 self.show_dpi_change_message)
 
@@ -1412,12 +1413,19 @@ def handle_new_screen(self, screen):
         self.screen = screen
         self.screen.logicalDotsPerInchChanged.connect(
             self.show_dpi_change_message)
+        if self.current_dpi != screen.logicalDotsPerInch():
+            self.show_dpi_change_message(screen.logicalDotsPerInch())
 
-    def show_dpi_change_message(self):
+    def show_dpi_change_message(self, dpi):
         """Show message to restart Spyder since the DPI scale changed."""
         self.screen.logicalDotsPerInchChanged.disconnect(
             self.show_dpi_change_message)
 
+        if self.current_dpi == dpi:
+            # Reconnect DPI scale changes to show a restart message
+            self.screen.logicalDotsPerInchChanged.connect(
+                self.show_dpi_change_message)
+            return
         if not self.show_dpi_message:
             return
 
@@ -1442,15 +1450,16 @@ def show_dpi_change_message(self):
               "</tt><br><br>in <tt>Preferences > General > Interface</tt>, "
               "in case Spyder is not displayed correctly.<br><br>"
               "Do you want to restart Spyder?"))
-        yes_button = msgbox.addButton(QMessageBox.Yes)
-        msgbox.addButton(QMessageBox.No)
+        restart_button = msgbox.addButton(_('Restart now'), QMessageBox.NoRole)
+        dismiss_button = msgbox.addButton(_('Dismiss'), QMessageBox.NoRole)
         msgbox.setCheckBox(dismiss_box)
+        msgbox.setDefaultButton(dismiss_button)
         msgbox.exec_()
 
         if dismiss_box.isChecked():
             self.show_dpi_message = False
 
-        if msgbox.clickedButton() == yes_button:
+        if msgbox.clickedButton() == restart_button:
             # Activate HDPI auto-scaling option since is needed for a proper
             # display when using OS scaling
             CONF.set('main', 'normal_screen_resolution', False)
@@ -1459,6 +1468,8 @@ def show_dpi_change_message(self):
             self.restart()
         else:
             # Reconnect DPI scale changes to show a restart message
+            # also update current dpi for future checks
+            self.current_dpi = dpi
             self.screen.logicalDotsPerInchChanged.connect(
                 self.show_dpi_change_message)
 


Test patch: