Skip to content

Commit

Permalink
Add polling based window waiting for testbed (#3047)
Browse files Browse the repository at this point in the history
Replaces the delay-based mechanism of waiting for windows with a polling-based approach.
  • Loading branch information
proneon267 authored Dec 23, 2024
1 parent cd69b57 commit 832bba6
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 141 deletions.
43 changes: 36 additions & 7 deletions android/tests_backend/window.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import asyncio

from android.content import Context
from androidx.appcompat import R as appcompat_R

from toga.constants import WindowState

from .dialogs import DialogsMixin
from .probe import BaseProbe

Expand All @@ -18,14 +22,39 @@ def __init__(self, app, window):
async def wait_for_window(
self,
message,
minimize=False,
full_screen=False,
state_switch_not_from_normal=False,
state=None,
):
await self.redraw(
message,
delay=(0.5 if (full_screen or state_switch_not_from_normal) else 0.1),
)
await self.redraw(message, delay=0.1)
if state:
timeout = 5
polling_interval = 0.1
exception = None
loop = asyncio.get_running_loop()
start_time = loop.time()
while (loop.time() - start_time) < timeout:
try:
assert self.instantaneous_state == state
if state in {WindowState.FULLSCREEN, WindowState.PRESENTATION}:
# Add a slight delay to ensure window properties like
# `content_size` are updated according to the new state.
await self.redraw(delay=0.1)
return
except AssertionError as e:
exception = e
await asyncio.sleep(polling_interval)
continue
raise exception

async def cleanup(self):
# Store the pre closing window state as determination of
# window state after closing the window is unreliable.
pre_close_window_state = self.window.state
self.window.close()
if pre_close_window_state in {WindowState.FULLSCREEN, WindowState.PRESENTATION}:
delay = 0.5
else:
delay = 0.1
await self.redraw("Closing window", delay=delay)

@property
def content_size(self):
Expand Down
1 change: 1 addition & 0 deletions changes/3047.misc.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The `wait_for_window()` window probe method, now has a polling based waiting mechanism.
50 changes: 39 additions & 11 deletions cocoa/tests_backend/window.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import asyncio

from rubicon.objc import objc_id, send_message

from toga.constants import WindowState
from toga_cocoa.libs import NSWindow, NSWindowStyleMask

from .dialogs import DialogsMixin
Expand All @@ -25,18 +28,43 @@ def __init__(self, app, window):
async def wait_for_window(
self,
message,
minimize=False,
full_screen=False,
state_switch_not_from_normal=False,
state=None,
):
await self.redraw(
message,
delay=(
1.75
if state_switch_not_from_normal
else 0.75 if full_screen else 0.5 if minimize else 0.1
),
)
await self.redraw(message, delay=0.1)

if state:
timeout = 5
polling_interval = 0.1
exception = None
loop = asyncio.get_running_loop()
start_time = loop.time()
while (loop.time() - start_time) < timeout:
try:
assert self.instantaneous_state == state
assert self.window._impl._pending_state_transition is None
return
except AssertionError as e:
exception = e
await asyncio.sleep(polling_interval)
continue
raise exception

async def cleanup(self):
# Store the pre closing window state as determination of
# window state after closing the window is unreliable.
pre_close_window_state = self.window.state
self.window.close()
# We need to use fixed length delays here as NSWindow.close() is
# non-blocking in nature, and NSWindow doesn't provide a reliable
# indicator to indicate completion of all operations related to
# window closing.
if pre_close_window_state == WindowState.FULLSCREEN:
delay = 1
elif pre_close_window_state == WindowState.MINIMIZED:
delay = 0.5
else:
delay = 0.1
await self.redraw("Closing window", delay=delay)

def close(self):
self.native.performClose(None)
Expand Down
39 changes: 32 additions & 7 deletions gtk/tests_backend/window.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import asyncio

from toga.constants import WindowState
from toga_gtk.libs import IS_WAYLAND, Gdk, Gtk

from .dialogs import DialogsMixin
Expand Down Expand Up @@ -27,14 +30,36 @@ def __init__(self, app, window):
async def wait_for_window(
self,
message,
minimize=False,
full_screen=False,
state_switch_not_from_normal=False,
state=None,
):
await self.redraw(
message,
delay=(0.5 if (full_screen or minimize) else 0.1),
)
await self.redraw(message, delay=0.1)
if state:
timeout = 5
polling_interval = 0.1
exception = None
loop = asyncio.get_running_loop()
start_time = loop.time()
while (loop.time() - start_time) < timeout:
try:
assert self.instantaneous_state == state
assert self.window._impl._pending_state_transition is None
return
except AssertionError as e:
exception = e
await asyncio.sleep(polling_interval)
continue
raise exception

async def cleanup(self):
# Store the pre closing window state as determination of
# window state after closing the window is unreliable.
pre_close_window_state = self.window.state
self.window.close()
if pre_close_window_state in {WindowState.FULLSCREEN, WindowState.MINIMIZED}:
delay = 0.5
else:
delay = 0.1
await self.redraw("Closing window", delay=delay)

def close(self):
if self.is_closable:
Expand Down
25 changes: 22 additions & 3 deletions iOS/tests_backend/window.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import asyncio

import pytest

from toga_iOS.libs import UIApplication, UIWindow
Expand All @@ -21,11 +23,28 @@ def __init__(self, app, window):
async def wait_for_window(
self,
message,
minimize=False,
full_screen=False,
state_switch_not_from_normal=False,
state=None,
):
await self.redraw(message)
if state:
timeout = 5
polling_interval = 0.1
exception = None
loop = asyncio.get_running_loop()
start_time = loop.time()
while (loop.time() - start_time) < timeout:
try:
assert self.instantaneous_state == state
return
except AssertionError as e:
exception = e
await asyncio.sleep(polling_interval)
continue
raise exception

async def cleanup(self):
self.window.close()
await self.redraw("Closing window")

@property
def content_size(self):
Expand Down
Loading

0 comments on commit 832bba6

Please sign in to comment.