Repository: beeware/toga

Issue:
GTK animated widgets freeze until first resize
### Describe the bug

GTK Widgets that contain an "animated" component - e.g., Switch (the slide left/right animation) or an indeterminate ProgressBar (pulse animation) won't animate when the window is first drawn. However, if you resize the window, the animation will resume, including any historical state.

### Steps to reproduce

1. Run the toga_switch example.

Try to toggle the "initial state" button. The color of the switch will change, but the switch itself won't "slide".

Also worth note: The exterior border of the "change label" button is very slightly clipped.

2. Run the progressbar example

The indeterminate progress bar may not start. 

Toggle the Running Mode and Indeterminate Mode buttons. With sufficient toggling, you will eventually be able to cause the running indeterminate progress bar to stop animating.


### Expected behavior

Animated widgets should consistently render.

### Screenshots

_No response_

### Environment

- Operating System: Linux (any; tested on Fedora 36 and Ubuntu 22.04)
- Python version: 3.10 (but likely any)
- Software versions:
  - Toga: 0.3.0+; tested at 235ff2e, but anything after the landing of #1794 will show the problem


### Logs

```

```


### Additional context

The problem appears to be related to the GTK Container fixes introduced in #1794.

In both examples listed above, I have found that the *first* time I run examples after making a code change, it *sometimes* works. However, on second and subsequent runs, the problem reliably occurs. There may be a timing issue at play - maybe the slowdown of PYC recompilation is sufficient to mask event order problems?

A suboptimal fix: if the optimisation on L166 that only does a refresh() `if resized or self.needs_redraw` is removed (so a lot more refreshes are performed), the problem goes away

A partial fix: If `window` listens for the `window-state-event` signal, and marks the container dirty when that event occurs, the switch demo works. The switches on the progress bar demo are also fixed. However, the animation of the indeterminate progress bar *isn't* fixed (at least, not consistently)

This suggests that the issue is a signal that constitutes a "dirty" window, but isn't being treated as a dirty signal.



Discussion:

Resolving patch:
diff --git a/gtk/src/toga_gtk/container.py b/gtk/src/toga_gtk/container.py
--- a/gtk/src/toga_gtk/container.py
+++ b/gtk/src/toga_gtk/container.py
@@ -161,12 +161,13 @@ def do_size_allocate(self, allocation):
         resized = (allocation.width, allocation.height) != (self.width, self.height)
         self.set_allocation(allocation)
 
-        # This function may be called in response to irrelevant events like button clicks,
-        # so only refresh if we really need to.
-        if self._content and (resized or self.needs_redraw):
-            # Re-evaluate the layout using the allocation size as the basis for geometry
-            # print("REFRESH LAYOUT", allocation.width, allocation.height)
-            self._content.interface.refresh()
+        if self._content:
+            # This function may be called in response to irrelevant events like button clicks,
+            # so only refresh if we really need to.
+            if resized or self.needs_redraw:
+                # Re-evaluate the layout using the allocation size as the basis for geometry
+                # print("REFRESH LAYOUT", allocation.width, allocation.height)
+                self._content.interface.refresh()
 
             # WARNING! This is the list of children of the *container*, not
             # the Toga widget. Toga maintains a tree of children; all nodes


Test patch: