Repository: kivy/kivy

Issue:
Window on_resize event fires twice with different widths
### Versions

* Python: 3.7
* OS: Mac OS Mojave
* Kivy: 1.10.1
* Kivy installation method: pip

### Description

I'm subscribed to the window.on_resize event. I expect to get 1 callback per resize. Instead I get 2, one for width, one for width * 2.

width 1680
width 3360
width 785
width 1570
width 366
width 732

### Code and Logs

```python
class Example(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Window.maximize()
        Window.bind(on_resize=self.on_window_resize)

    def on_window_resize(self, window, width, height):
        print("width", width)

class MainApp(App):
    def build(self):
        return Example()

if __name__ == '__main__':
    MainApp().run()
```



Discussion:
Same versions/os/installation-method, but on a dual monitor setup (one external, one on my laptop), and I get the double event as well, but the width stays the same.

I get the double event on maximize, as in the above example.  I also get it on manual resizing.  I get double events on both monitors.

I do *not* get a double event (I get a single event) when I drag my window from one monitor to another (resizes because of the DPI change).

Resolving patch:
diff --git a/kivy/core/window/__init__.py b/kivy/core/window/__init__.py
--- a/kivy/core/window/__init__.py
+++ b/kivy/core/window/__init__.py
@@ -399,7 +399,7 @@ def _set_size(self, size):
             else:
                 self._size = size[1], size[0]
 
-            self.dispatch('on_resize', *size)
+            self.dispatch('on_pre_resize', *size)
             return True
         else:
             return False
@@ -531,7 +531,7 @@ def _set_rotation(self, x):
         self._rotation = x
         if not self.initialized:
             return
-        self.dispatch('on_resize', *self.size)
+        self.dispatch('on_pre_resize', *self.size)
         self.dispatch('on_rotate', x)
 
     rotation = AliasProperty(_get_rotation, _set_rotation,
@@ -868,7 +868,10 @@ def __self__(self):
         'on_request_close', 'on_cursor_enter', 'on_cursor_leave',
         'on_joy_axis', 'on_joy_hat', 'on_joy_ball',
         'on_joy_button_down', 'on_joy_button_up', 'on_memorywarning',
-        'on_textedit')
+        'on_textedit',
+
+        # internal
+        'on_pre_resize')
 
     def __new__(cls, **kwargs):
         if cls.__instance is None:
@@ -1240,14 +1243,14 @@ def create_window(self, *largs):
             # XXX check how it's working on embed platform.
             if platform == 'linux' or Window.__class__.__name__ == 'WindowSDL':
                 # on linux, it's safe for just sending a resize.
-                self.dispatch('on_resize', *self.system_size)
+                self.dispatch('on_pre_resize', *self.size)
 
             else:
                 # on other platform, window are recreated, we need to reload.
                 from kivy.graphics.context import get_context
                 get_context().reload()
                 Clock.schedule_once(lambda x: self.canvas.ask_update(), 0)
-                self.dispatch('on_resize', *self.system_size)
+                self.dispatch('on_pre_resize', *self.size)
 
         # ensure the gl viewport is correct
         self.update_viewport()
@@ -1417,6 +1420,13 @@ def on_touch_up(self, touch):
             if w.dispatch('on_touch_up', touch):
                 return True
 
+    def on_pre_resize(self, width, height):
+        key = (width, height)
+        if hasattr(self, '_last_resize') and self._last_resize == key:
+            return
+        self._last_resize = key
+        self.dispatch('on_resize', width, height)
+
     def on_resize(self, width, height):
         '''Event called when the window is resized.'''
         self.update_viewport()
diff --git a/kivy/core/window/window_sdl2.py b/kivy/core/window/window_sdl2.py
--- a/kivy/core/window/window_sdl2.py
+++ b/kivy/core/window/window_sdl2.py
@@ -678,7 +678,7 @@ def _mainloop(self):
     def _do_resize(self, dt):
         Logger.debug('Window: Resize window to %s' % str(self.size))
         self._win.resize_window(*self._size)
-        self.dispatch('on_resize', *self.size)
+        self.dispatch('on_pre_resize', *self.size)
 
     def do_pause(self):
         # should go to app pause mode (desktop style)


Test patch: