Repository: kivy/kivy

Issue:
Animation doesn't finish correctly for Window
### Versions

* Python: 3.5.2
* OS: Win 8.1
* Kivy: master

### Description

Animation visually ends too soon if the duration is `> 0.5` for `Window`. If the duration is `<= 0.5`, it still isn't correctly completed, but at least looks like that. It works just fine for widgets. Am I getting into some kind of undefined behavior here with resizing "too often"? Can anyone reproduce it on other platform i.e. if it's just Window thing and/or SDL2?

The `progress` value happily continues to `1.0` even though the resizing stopped, so I think it's not really fault of `Animation`, but rather a fail with let's say `SDL_SetWindowSize()`. Also, I noticed that "sometimes" it completes the resizing correctly but mostly on `0.5` and lower with multiple tries.

### Code and Logs

```python
from kivy.clock import Clock
from kivy.base import runTouchApp
from kivy.animation import Animation
from kivy.core.window import Window

Window.bind(size=lambda *values: print(values))  # + print(anim['widget']) in Animation._update()
an = Animation(size=(1, 1))  # , d=0.5)  # huh?
Clock.schedule_once(lambda *_: an.start(Window), 1)

runTouchApp()
```

values for Window (`d=1.0`):

```
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (800, 600))
(800, 600)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (789.61007, 592.2108))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (789.61007, 592.2108))
(789.61007, 592.2108)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (775.92995, 581.95499))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (775.92995, 581.95499))
(775.92995, 581.95499)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (762.35405, 571.77732))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (762.35405, 571.77732))
(762.35405, 571.77732)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (749.41576, 562.07764))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (749.41576, 562.07764))
(749.41576, 562.07764)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (735.66081, 551.76574))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (735.66081, 551.76574))
(735.66081, 551.76574)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (722.7437, 542.08195))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (722.7437, 542.08195))
(722.7437, 542.08195)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (709.59355, 532.22345))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (709.59355, 532.22345))
(709.59355, 532.22345)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (696.60092, 522.48305))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (696.60092, 522.48305))
(696.60092, 522.48305)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (683.49998, 512.66144))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (683.49998, 512.66144))
(683.49998, 512.66144)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (670.31225, 502.77476))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (670.31225, 502.77476))
(670.31225, 502.77476)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (657.05515, 492.83609))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (657.05515, 492.83609))
(657.05515, 492.83609)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (643.79464, 482.89485))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (643.79464, 482.89485))
(643.79464, 482.89485)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (630.25188, 472.74202))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (630.25188, 472.74202))
(630.25188, 472.74202)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (617.1711, 462.93553))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (617.1711, 462.93553))
(617.1711, 462.93553)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (603.89623, 452.98353))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (603.89623, 452.98353))
(603.89623, 452.98353)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (590.57865, 442.99952))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (590.57865, 442.99952))
(590.57865, 442.99952)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (577.39878, 433.11873))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (577.39878, 433.11873))
(577.39878, 433.11873)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (564.22266, 423.24077))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (564.22266, 423.24077))
(564.22266, 423.24077)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (551.04108, 413.35871))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (551.04108, 413.35871))
(551.04108, 413.35871)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (537.55983, 403.25199))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (537.55983, 403.25199))
(537.55983, 403.25199)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (524.35809, 393.35481))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (524.35809, 393.35481))
(524.35809, 393.35481)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (511.11295, 383.4251))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (511.11295, 383.4251))
(511.11295, 383.4251)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (497.91018, 373.52716))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (497.91018, 373.52716))
(497.91018, 373.52716)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (484.85092, 363.7368))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (484.85092, 363.7368))
(484.85092, 363.7368)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (471.40453, 353.65621))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (471.40453, 353.65621))
(471.40453, 353.65621)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (458.24618, 343.79157))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (458.24618, 343.79157))
(458.24618, 343.79157)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (444.81823, 333.72481))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (444.81823, 333.72481))
(444.81823, 333.72481)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (431.86935, 324.01719))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (431.86935, 324.01719))
(431.86935, 324.01719)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (418.56578, 314.04368))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (418.56578, 314.04368))
(418.56578, 314.04368)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (405.09614, 303.94567))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (405.09614, 303.94567))
(405.09614, 303.94567)
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (392.00853, 294.13405))
(<kivy.core.window.window_sdl2.WindowSDL object at 0x0317A730>, (392.00853, 294.13405))
(392.00853, 294.13405)
(392.00853, 294.13405)
(392.00853, 294.13405)
...
```

values for Window (`d=0.5`):

```
(800, 600)
(779.2283371964725, 584.4277521660663)
(723.50191931028, 542.6503750523876)
(670.4038223697153, 502.84341626966136)
(642.4558729697135, 481.8911988846788)
(615.7667293892246, 461.88269199517583)
(589.3024213758478, 442.04274143195596)
(562.6645321039712, 422.0726592368945)
(536.3662880504971, 402.3572046836643)
(509.5855701052883, 382.2800456734264)
(483.90784488141145, 363.02978608756626
(458.0913913288911, 343.6755236620848)
(431.58539647784323, 323.8043210140527)
(405.1798600716745, 304.0084307671252)
(378.96020595807283, 284.3518940787054)
(352.27447933149153, 264.3459488354987)
(326.1655345244917, 244.77240948707203)
(299.86045656320266, 225.05183164124955
(272.93554316309866, 204.8665711573167)
(246.97216059255703, 185.40215794110347
(220.68826774549441, 165.69746230231684
(193.8412608944805, 145.5706073539347)
(167.57923655242587, 125.88230625144315
(141.01857043885815, 105.97011726267338
(114.4134839244933, 86.02462687205443)
(60.396909773599816, 45.529097564939036
(35.16748890238372, 26.614925973126216)
(8.751018243711217, 6.810838458051338)
(8.751018243711217, 6.810838458051338)
(8.751018243711217, 6.810838458051338)
...
```

A workaround for now seems to be using a really short duration (so that it's still comfortable) and at the same time use `schedule_interval` with a small delay to kick it until it sets the correct size if it "freezes". It's a really ugly fix though.


Discussion:

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
@@ -571,6 +571,10 @@ def _set_rotation(self, x):
 
     _keyboard_changed = BooleanProperty(False)
     _kheight = NumericProperty(0)
+    _kanimation = None
+
+    def _free_kanimation(self, *largs):
+        WindowBase._kanimation = None
 
     def _animate_content(self):
         '''Animate content to IME height.
@@ -579,10 +583,13 @@ def _animate_content(self):
         global Animation
         if not Animation:
             from kivy.animation import Animation
-        Animation.cancel_all(self)
-        Animation(
+        if WindowBase._kanimation:
+            WindowBase._kanimation.cancel(self)
+        WindowBase._kanimation = kanim = Animation(
             _kheight=self.keyboard_height + self.keyboard_padding,
-            d=kargs['d'], t=kargs['t']).start(self)
+            d=kargs['d'], t=kargs['t'])
+        kanim.bind(on_complete=self._free_kanimation)
+        kanim.start(self)
 
     def _upd_kbd_height(self, *kargs):
         self._keyboard_changed = not self._keyboard_changed


Test patch: