From 6b3e88391da04c2ca6d81e9a499fbe8681625c4e Mon Sep 17 00:00:00 2001 From: proneon267 Date: Sat, 6 Jul 2024 07:53:32 -0700 Subject: [PATCH] Added tests as per review: 9 --- cocoa/src/toga_cocoa/app.py | 6 +-- core/src/toga/constants/__init__.py | 6 ++- core/tests/app/test_app.py | 79 +++++++++++++++++++++++++++ dummy/src/toga_dummy/window.py | 3 ++ testbed/tests/app/test_desktop.py | 83 +++++++++++++++++++++++++++++ 5 files changed, 173 insertions(+), 4 deletions(-) diff --git a/cocoa/src/toga_cocoa/app.py b/cocoa/src/toga_cocoa/app.py index 94b72ff083..6ac8169c1d 100644 --- a/cocoa/src/toga_cocoa/app.py +++ b/cocoa/src/toga_cocoa/app.py @@ -504,9 +504,9 @@ def enter_presentation_mode(self, screen_window_dict): window.content._impl.native.enterFullScreenMode( screen._impl.native, withOptions=opts ) - # Going full screen causes the window content to be re-homed - # in a NSFullScreenWindow; teach the new parent window - # about its Toga representations. + # Going presentation mode causes the window content to be re-homed + # in a NSFullScreenWindow; teach the new parent window about its + # Toga representations. window.content._impl.native.window._impl = window._impl window.content._impl.native.window.interface = window window.content.refresh() diff --git a/core/src/toga/constants/__init__.py b/core/src/toga/constants/__init__.py index 70994c82b3..594e9d8e34 100644 --- a/core/src/toga/constants/__init__.py +++ b/core/src/toga/constants/__init__.py @@ -71,7 +71,11 @@ def __str__(self) -> str: class WindowState(Enum): - """The possible window states of an app.""" + """The possible window states of an app. + + Note: Changing window state while the app is in presentation mode will cause + the app to exit presentation mode, and the new window state will be set. + """ NORMAL = 0 """The ``NORMAL`` state represents the default state of the window or app when it is diff --git a/core/tests/app/test_app.py b/core/tests/app/test_app.py index 9eeead3267..3a18fc1019 100644 --- a/core/tests/app/test_app.py +++ b/core/tests/app/test_app.py @@ -9,6 +9,7 @@ import pytest import toga +from toga.constants import WindowState from toga_dummy.utils import ( EventLog, assert_action_not_performed, @@ -599,6 +600,84 @@ def test_presentation_mode_no_op(event_loop): assert not app.is_presentation_mode +@pytest.mark.parametrize( + "new_window_state", + [ + WindowState.MINIMIZED, + WindowState.MAXIMIZED, + WindowState.FULLSCREEN, + ], +) +def test_presentation_mode_exit_on_window_state_change(event_loop, new_window_state): + """Changing window state exits presentation mode and sets the new state.""" + app = toga.App(formal_name="Test App", app_id="org.example.test") + extra_window = toga.Window() + + # Enter presentation mode + app.enter_presentation_mode([app.main_window]) + assert_action_performed_with( + app, + "enter presentation mode", + screen_window_dict={app.screens[0]: app.main_window}, + ) + + assert app.is_presentation_mode + assert app.main_window.state == WindowState.PRESENTATION + assert extra_window.state != WindowState.PRESENTATION + + # Changing window state of main_window should make the app exit presentation mode. + app.main_window.state = new_window_state + assert_action_performed_with( + app.main_window, + f"set window state to {new_window_state}", + state=new_window_state, + ) + + assert not app.is_presentation_mode + assert_action_performed( + app, + "exit presentation mode", + ) + assert app.main_window.state != WindowState.PRESENTATION + assert app.main_window.state == new_window_state + + # Reset window states + app.main_window.state = WindowState.NORMAL + extra_window.state = WindowState.NORMAL + + # Enter presentation mode again + app.enter_presentation_mode([app.main_window]) + assert_action_performed_with( + app, + "enter presentation mode", + screen_window_dict={app.screens[0]: app.main_window}, + ) + + assert app.is_presentation_mode + assert app.main_window.state == WindowState.PRESENTATION + assert extra_window.state != WindowState.PRESENTATION + + # Changing window state of extra window should make the app exit presentation mode. + extra_window.state = new_window_state + assert_action_performed_with( + extra_window, + f"set window state to {new_window_state}", + state=new_window_state, + ) + + assert not app.is_presentation_mode + assert_action_performed( + app, + "exit presentation mode", + ) + assert app.main_window.state != WindowState.PRESENTATION + assert extra_window.state == new_window_state + + # Reset window states + app.main_window.state = WindowState.NORMAL + extra_window.state = WindowState.NORMAL + + def test_show_hide_cursor(app): """The app cursor can be shown and hidden.""" app.hide_cursor() diff --git a/dummy/src/toga_dummy/window.py b/dummy/src/toga_dummy/window.py index 8083a34043..79d4dde0c3 100644 --- a/dummy/src/toga_dummy/window.py +++ b/dummy/src/toga_dummy/window.py @@ -137,6 +137,9 @@ def get_window_state(self): return self._get_value("state", WindowState.NORMAL) def set_window_state(self, state): + if self.interface.app.is_presentation_mode and state != WindowState.NORMAL: + self.interface.app.exit_presentation_mode() + self.set_window_state(state) self._action(f"set window state to {state}", state=state) self._set_value("state", state) diff --git a/testbed/tests/app/test_desktop.py b/testbed/tests/app/test_desktop.py index 14baf916fc..60ecae280f 100644 --- a/testbed/tests/app/test_desktop.py +++ b/testbed/tests/app/test_desktop.py @@ -258,6 +258,7 @@ async def test_presentation_mode_with_excess_windows_list(app, app_probe): try: window_information_list = list() excess_windows_list = list() + # Generate an additional window compared to the number of screens present. for i in range(len(app.screens) + 1): window = toga.MainWindow( title=f"Test Window {i}", @@ -336,6 +337,88 @@ async def test_presentation_mode_with_excess_windows_list(app, app_probe): window.close() +@pytest.mark.parametrize( + "new_window_state", + [ + WindowState.MINIMIZED, + WindowState.MAXIMIZED, + WindowState.FULLSCREEN, + ], +) +async def test_presentation_mode_exit_on_window_state_change( + app, app_probe, main_window, main_window_probe, new_window_state +): + """Changing window state exits presentation mode and sets the new state.""" + try: + main_window.toolbar.add(app.cmd1) + extra_window = toga.MainWindow( + title="Extra Window", position=(150, 150), size=(200, 200) + ) + extra_window.content = toga.Box(style=Pack(background_color=CORNFLOWERBLUE)) + extra_window_probe = window_probe(app, extra_window) + extra_window.show() + # Add delay for gtk to show the windows + await app_probe.redraw("Extra window is shown", delay=0.5) + + # Enter presentation mode + app.enter_presentation_mode([main_window]) + # Add delay for gtk to show the windows + await app_probe.redraw("App is in presentation mode", delay=0.5) + + assert app.is_presentation_mode + assert main_window_probe.get_window_state() == WindowState.PRESENTATION + assert extra_window_probe.get_window_state() != WindowState.PRESENTATION + + # Changing window state of main window should make the app exit presentation mode. + main_window.state = new_window_state + # Add delay for gtk to show the windows + await app_probe.redraw( + "App is not in presentation mode" f"\nMain Window is in {new_window_state}", + delay=0.5, + ) + + assert not app.is_presentation_mode + assert main_window_probe.get_window_state != WindowState.PRESENTATION + assert main_window_probe.get_window_state() == new_window_state + + # Reset window states + main_window.state = WindowState.NORMAL + extra_window.state = WindowState.NORMAL + # Add delay for gtk to show the windows + await app_probe.redraw("All windows are in WindowState.NORMAL", delay=0.5) + + # Enter presentation mode again + app.enter_presentation_mode([main_window]) + # Add delay for gtk to show the windows + await app_probe.redraw("App is in presentation mode", delay=0.5) + assert app.is_presentation_mode + assert main_window_probe.get_window_state() == WindowState.PRESENTATION + assert extra_window_probe.get_window_state() != WindowState.PRESENTATION + + # Changing window state of extra window should make the app exit presentation mode. + extra_window.state = new_window_state + # Add delay for gtk to show the windows + await app_probe.redraw( + "App is not in presentation mode" + f"\nExtra Window is in {new_window_state}", + delay=0.5, + ) + + assert not app.is_presentation_mode + assert main_window_probe.get_window_state() != WindowState.PRESENTATION + assert extra_window_probe.get_window_state() == new_window_state + + # Reset window states + main_window.state = WindowState.NORMAL + extra_window.state = WindowState.NORMAL + # Add delay for gtk to show the windows + await app_probe.redraw("All windows are in WindowState.NORMAL", delay=0.5) + + finally: + main_window.toolbar.clear() + extra_window.close() + + async def test_show_hide_cursor(app, app_probe): """The app cursor can be hidden and shown""" assert app_probe.is_cursor_visible