Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add window states API #2473

Open
wants to merge 284 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 175 commits
Commits
Show all changes
284 commits
Select commit Hold shift + click to select a range
d82c615
Corrected gtk backend and core
proneon267 Mar 30, 2024
96ef3ed
Fixed winforms backend and cocoa
proneon267 Mar 31, 2024
4657567
Fixed core tests
proneon267 Mar 31, 2024
00491c8
Fixed cocoa backend and tests
proneon267 Mar 31, 2024
41c1dd7
Fixed testbed tests
proneon267 Mar 31, 2024
60d5e43
corrected testbed
proneon267 Mar 31, 2024
f497a1d
Added android implementation
proneon267 Apr 1, 2024
d34cb2f
Fixed core
proneon267 Apr 1, 2024
4d790b2
Fixed core
proneon267 Apr 1, 2024
18b0cbc
Added stub implementations for iOS, textual, web
proneon267 Apr 2, 2024
618d647
Merge branch 'beeware:main' into window_states
proneon267 Apr 2, 2024
b7eb117
Added mobile platform tests
proneon267 Apr 2, 2024
cadc4cc
Added changelog
proneon267 Apr 2, 2024
bf3511a
Restart CI
proneon267 Apr 3, 2024
d61a644
Merge remote-tracking branch 'remotes/origin/main' into window_states
proneon267 May 10, 2024
5b58045
Merge branch 'beeware:main' into window_states
proneon267 May 10, 2024
c9a1307
Minor modifications
proneon267 May 22, 2024
ab9b778
Minor modifications
proneon267 May 22, 2024
0a90a12
Minor modifications
proneon267 May 22, 2024
73721b3
Minor modifications
proneon267 May 22, 2024
c809698
Fixed bug on Window.close()
proneon267 May 23, 2024
06b7f2a
Fixed dummy backend
proneon267 May 23, 2024
11fea69
Fixed tests
proneon267 Jun 1, 2024
938504c
Minor cleanup
proneon267 Jun 1, 2024
be87113
Code Cleanup
proneon267 Jun 1, 2024
9aefd30
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Jun 1, 2024
13d2ff3
Merge branch 'beeware:main' into window_states
proneon267 Jun 1, 2024
176e879
Code Cleanup
proneon267 Jun 1, 2024
1ba73b8
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Jun 1, 2024
d4bfdaa
Restart CI for Linux Testbed failure
proneon267 Jun 1, 2024
d993b80
Merge branch 'main' into window_states
proneon267 Jun 12, 2024
38bf5c3
Updated to latest main branch
proneon267 Jun 12, 2024
b710eaf
Parameterized test on core
proneon267 Jun 16, 2024
b461295
Merge branch 'main' into window_states
proneon267 Jun 16, 2024
0c7900b
Updating to latest main branch
proneon267 Jun 16, 2024
97a6c66
Changed attribute to is_presentation_mode
proneon267 Jun 16, 2024
ba28194
Misc cleanup
proneon267 Jun 16, 2024
c7320ce
Name cleanups
proneon267 Jun 16, 2024
aed5251
Modified as per review
proneon267 Jun 17, 2024
a76bf9b
Added _PLATFORM_ALLOWS_CLOSE attribute on required backends
proneon267 Jun 17, 2024
f0d5d80
Handled deprecation warning on testbed tests
proneon267 Jun 17, 2024
e416f20
Removed explicit closing from dummy backend
proneon267 Jun 17, 2024
1fa8cde
100% coverage on core
proneon267 Jun 17, 2024
6350b5f
100% coverage on Android & iOS
proneon267 Jun 17, 2024
d091955
Restart CI for windows failure
proneon267 Jun 17, 2024
5c2a53b
Merge branch 'main' into window_states
proneon267 Jun 23, 2024
564c5ed
Updated to latest `main` branch
proneon267 Jun 23, 2024
e36e596
Delete changes/1857.bugfix.rst
proneon267 Jun 23, 2024
174d66b
Merge branch 'beeware:main' into window_states
proneon267 Jun 26, 2024
17564a8
Fixed testbed failures
proneon267 Jun 26, 2024
51cea93
Restart CI for pre-commit failure
proneon267 Jun 26, 2024
feb78a8
 
proneon267 Jun 26, 2024
4632738
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Jun 26, 2024
8286b86
 
proneon267 Jun 26, 2024
16d5758
Fix testbed for macOS
proneon267 Jun 26, 2024
5b59b14
Wayland test
proneon267 Jun 26, 2024
85dd202
Fix testbed for wayland
proneon267 Jun 26, 2024
552c0fc
Fix testbed for wayland
proneon267 Jun 26, 2024
56edec1
Restart CI for macOS
proneon267 Jun 26, 2024
971b8da
Merge branch 'main' into window_states
proneon267 Jun 27, 2024
934b6b1
Updated to latest main branch
proneon267 Jun 27, 2024
1e6bd76
Merge branch 'main' into window_states
proneon267 Jun 29, 2024
426e8b9
Updated to latest main branch
proneon267 Jun 29, 2024
ccef113
Merge branch 'beeware:main' into window_states
proneon267 Jul 4, 2024
4d83d19
Update changes/1857.removal.rst
proneon267 Jul 4, 2024
067e988
Update core/src/toga/constants/__init__.py
proneon267 Jul 4, 2024
3c84a80
Update core/src/toga/app.py
proneon267 Jul 4, 2024
a276f22
Various changes as per review: 1
proneon267 Jul 4, 2024
78cdd3b
Various changes as per review: 2
proneon267 Jul 4, 2024
b9e87c5
Various changes as per review: 3
proneon267 Jul 4, 2024
06d5a9e
Various changes as per review: 4
proneon267 Jul 4, 2024
b0c37fe
Various changes as per review: 5
proneon267 Jul 4, 2024
09ee428
Various changes as per review: 6
proneon267 Jul 4, 2024
1bd1f39
Various changes as per review: 7
proneon267 Jul 5, 2024
2b6d347
Added new tests as per review: 8
proneon267 Jul 5, 2024
8bba100
Minor change on cocoa
proneon267 Jul 6, 2024
6b3e883
Added tests as per review: 9
proneon267 Jul 6, 2024
74685d1
Restored to app presentation mode test to non-parameterized form to c…
proneon267 Jul 6, 2024
25c420f
Fixed testbed failures
proneon267 Jul 6, 2024
83dcab4
Minor change on testbed
proneon267 Jul 6, 2024
ab0ed45
Fixed cocoa backend and tests
proneon267 Jul 6, 2024
4fa4af6
Fixed dummy backend
proneon267 Jul 6, 2024
71f4314
Fixed gtk test backend
proneon267 Jul 7, 2024
a308ea7
Fixed core and added new test
proneon267 Jul 7, 2024
42642ee
Fixed winforms
proneon267 Jul 7, 2024
6b513c7
Fixed gtk backend
proneon267 Jul 7, 2024
ccc8f11
Fixed Android backend
proneon267 Jul 7, 2024
56f32a7
Test to diagnose wayland failure
proneon267 Jul 7, 2024
5da8231
Removed diagnostic tests
proneon267 Jul 7, 2024
4c6070d
Diagnostic test
proneon267 Jul 9, 2024
cfa255a
Various code cleanups
proneon267 Jul 9, 2024
87383f3
Fixed core
proneon267 Jul 10, 2024
c3f32c7
Minor cleanup
proneon267 Jul 9, 2024
4b2fdbb
Removed diagnostic tests
proneon267 Jul 7, 2024
b592ee2
Added review notes
proneon267 Jul 10, 2024
a5891e8
Fixed testbed tests
proneon267 Jul 10, 2024
e8ad898
100% coverage
proneon267 Jul 10, 2024
8684038
Removed diagnostic code
proneon267 Jul 10, 2024
1b53c16
diagnosing failure
proneon267 Jul 10, 2024
3cebc76
Revert change
proneon267 Jul 10, 2024
d2510e0
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Jul 10, 2024
4485cda
100% coverage
proneon267 Jul 10, 2024
d0dcb35
Merge branch 'beeware:main' into window_states
proneon267 Jul 16, 2024
f429307
Removed overspecified assertions and test
proneon267 Jul 25, 2024
6aedeea
changed is_presentation_mode to in_presentation_mode
proneon267 Jul 25, 2024
d7228ba
skipped some tests on the unimplemented iOS backend
proneon267 Jul 25, 2024
600e4c9
Modified cocoa implementation
proneon267 Jul 29, 2024
3689314
Typo fix on cocoa
proneon267 Jul 29, 2024
1a6b4ad
Merge branch 'beeware:main' into window_states
proneon267 Jul 29, 2024
2885d1c
Typo fix on cocoa
proneon267 Jul 29, 2024
cd9e00b
Typo fix on cocoa
proneon267 Jul 29, 2024
57fd1e3
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Jul 29, 2024
7835fe8
Fix cocoa
proneon267 Jul 29, 2024
1c0a969
Implemented new window states handling on cocoa and gtk
proneon267 Aug 6, 2024
cf23ce9
Fixed cocoa implementation
proneon267 Aug 6, 2024
e6f4dcc
Reimplemented on cocoa backend
proneon267 Aug 10, 2024
30e5968
Reimplemented on winforms
proneon267 Aug 12, 2024
c623254
 
proneon267 Aug 12, 2024
f2bd750
 
proneon267 Aug 12, 2024
11444e3
Reimplemented on gtk
proneon267 Aug 14, 2024
0771349
Update 1857.feature.rst
proneon267 Aug 14, 2024
c9b7b90
Removed unncessary complexity from cocoa implementation
proneon267 Aug 14, 2024
3441cb3
Misc fixes
proneon267 Aug 14, 2024
62dcd7d
Update cocoa/src/toga_cocoa/window.py
proneon267 Aug 15, 2024
4f36f28
proneon267 Aug 15, 2024
ea8058a
Update test_window.py
proneon267 Aug 15, 2024
11c3ec3
Reimplemented on cocoa backend
proneon267 Aug 16, 2024
0bd68c4
Reimplemented on gtk
proneon267 Aug 16, 2024
edef651
Merge branch 'beeware:main' into window_states
proneon267 Aug 16, 2024
3c8b0f1
Correcting test failure on cocoa
proneon267 Aug 17, 2024
e915d72
Correcting test failure on cocoa
proneon267 Aug 17, 2024
fb6e657
Correcting test failure on cocoa
proneon267 Aug 17, 2024
b810d65
Correcting test failure on cocoa
proneon267 Aug 17, 2024
1e59da1
Correcting test failure on cocoa
proneon267 Aug 17, 2024
9dba56b
Fix delegate error on cocoa
proneon267 Aug 17, 2024
56cc124
Fixing delegate error on cocoa
proneon267 Aug 17, 2024
2d29072
Add check guards for invalid impl on cocoa delegate
proneon267 Aug 17, 2024
c2e88e5
Removed unused state flags from gtk
proneon267 Aug 17, 2024
279dfda
Removed unused branch in cocoa implementation
proneon267 Aug 17, 2024
73bf7aa
Added checks for wayland
proneon267 Aug 18, 2024
af6a292
Added checks for wayland
proneon267 Aug 18, 2024
5a0352f
Minor gtk fix
proneon267 Aug 19, 2024
ef68572
Added no cover for wayland
proneon267 Aug 19, 2024
ca48ba2
parameterized tests on core
proneon267 Aug 20, 2024
cd8eba2
Reimplemented on Android
proneon267 Aug 20, 2024
e5eff2b
Merge branch 'main' into window_states
proneon267 Aug 20, 2024
26eb01c
Use the new wayland detection
proneon267 Aug 20, 2024
3a6aaf7
Removed legacy code from window example.
proneon267 Aug 20, 2024
78b5ddf
Added checks for wayland
proneon267 Aug 20, 2024
e0f5bf0
Minor fix on testbed
proneon267 Aug 20, 2024
54cfaab
Restart CI for intermittent failures
proneon267 Aug 20, 2024
8b8685e
Removed unused flags from Android implementation
proneon267 Aug 20, 2024
d599730
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Aug 20, 2024
91b70da
Reorganized test
proneon267 Aug 20, 2024
b38ff03
Merge branch 'beeware:main' into window_states
proneon267 Aug 20, 2024
2cf1839
Merge branch 'main' into window_states
proneon267 Aug 29, 2024
aa120e9
Resolving file conflicts with main branch
proneon267 Aug 29, 2024
3661110
Merge branch 'main' into window_states
proneon267 Sep 3, 2024
c928ac1
Fixed cocoa delegate
proneon267 Sep 3, 2024
f9c18f5
Modified testbed test
proneon267 Sep 9, 2024
ace13ce
Testing native OS delay for each platform
proneon267 Sep 10, 2024
ef7b3dc
Restart CI as previous run dropped by intermittent failure
proneon267 Sep 10, 2024
bc19c7f
Re-running CI to confirm cocoa errors are consistently produced
proneon267 Sep 10, 2024
c2235f7
Testing native OS delay for each platform
proneon267 Sep 10, 2024
b0ead86
Removed unused flag from gtk
proneon267 Sep 10, 2024
7bbf330
Restart CI for intermittent failures
proneon267 Sep 10, 2024
0f7fe4f
Removed unused flag on gtk
proneon267 Sep 10, 2024
7308e11
Enable presentation and fullscreen mode on wayland
proneon267 Sep 11, 2024
8f858be
Enable skipped test on wayland
proneon267 Sep 11, 2024
9f95554
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Sep 11, 2024
295cd59
Fix test timing
proneon267 Sep 11, 2024
5bd410e
Restart CI for intermittent failures
proneon267 Sep 11, 2024
00a742e
Delay tests according to native platforms
proneon267 Sep 11, 2024
4ef9c50
Covered missing coverage
proneon267 Sep 12, 2024
a1613be
Covered missing coverage
proneon267 Sep 12, 2024
138d0e3
Covered missing coverage
proneon267 Sep 13, 2024
450efad
Added XFAIL for iOS
proneon267 Sep 13, 2024
51d3590
Replace use of app_probe.redraw with window_probe.wait_for_window
proneon267 Sep 13, 2024
3de8eef
Moved presentation implementation on cocoa to window from app
proneon267 Sep 16, 2024
77e2b7e
Removed miniaturization delay from cocoa
proneon267 Sep 16, 2024
7db80d2
Removed miniaturization delay from cocoa
proneon267 Sep 16, 2024
aaee1f9
Ensuring coverage on macOS
proneon267 Sep 16, 2024
903860b
Ensuring coverage on macOS
proneon267 Sep 16, 2024
a6df392
Ensuring coverage on macOS
proneon267 Sep 19, 2024
f9f1375
Merge branch 'main' into window_states
proneon267 Sep 19, 2024
ad427ab
Ensuring coverage on macOS
proneon267 Sep 19, 2024
56de33d
Ensuring coverage on macOS
proneon267 Sep 19, 2024
59012cd
Ensuring coverage on macOS
proneon267 Sep 19, 2024
5a66725
Merge branch 'beeware:main' into window_states
proneon267 Sep 25, 2024
bb22a9f
Ensuring coverage on macOS
proneon267 Sep 25, 2024
f6a851d
Modified rapid state switching delay timing
proneon267 Sep 25, 2024
35bbb8e
Resolve error
proneon267 Sep 25, 2024
8bddf0e
Ensuring coverage on macOS
proneon267 Sep 25, 2024
03dd538
Update core/src/toga/window.py
proneon267 Sep 25, 2024
2af1509
Modified to correct expected error in test
proneon267 Sep 25, 2024
8b56d66
Clarified reasoning comment regarding state checks being performed at…
proneon267 Sep 27, 2024
7cd1489
Clarified reasoning comment regarding state checks being performed at…
proneon267 Sep 27, 2024
598021f
Modified testbed tests
proneon267 Sep 27, 2024
596acc4
Removed unused probe method from backends
proneon267 Sep 29, 2024
d3f90ba
Removed repeated tests
proneon267 Sep 29, 2024
945caf5
Removed repeated tests
proneon267 Sep 29, 2024
116eec3
Checking for coverage issues on macOS
proneon267 Sep 29, 2024
71aec38
Added no-cover on cocoa
proneon267 Sep 29, 2024
2559fa0
Improved tests
proneon267 Sep 30, 2024
d822ff0
Added platform notes
proneon267 Oct 2, 2024
14b64b7
Added platform notes
proneon267 Oct 3, 2024
d8c8422
Improved tests on mobile platform
proneon267 Oct 3, 2024
bb513d3
Merge branch 'beeware:main' into window_states
proneon267 Oct 3, 2024
eb2d9a5
Apply suggestions from code review
proneon267 Oct 7, 2024
abfa707
corrected pre-commit issues
proneon267 Oct 7, 2024
8f7c954
Moved implementation of app presentation mode to core from backends
proneon267 Oct 7, 2024
379e002
Removed unused code from dummy backend
proneon267 Oct 7, 2024
e3f31ff
corrected core tests
proneon267 Oct 7, 2024
383e027
Restart CI for intermittent Android failures
proneon267 Oct 7, 2024
c986e3d
Improved tests
proneon267 Oct 8, 2024
5f365c6
Improved tests
proneon267 Oct 8, 2024
2961507
Moved same state transition tests to core
proneon267 Oct 8, 2024
9ca14ed
Improved tests
proneon267 Oct 8, 2024
b6edc2a
Restart CI for Intermittent Android failure
proneon267 Oct 8, 2024
0f74ad9
Merge branch 'beeware:main' into window_states
proneon267 Oct 12, 2024
589e3c7
Restart CI for intermittent Android failures
proneon267 Oct 12, 2024
621c723
Restart CI for intermittent Android failures
proneon267 Oct 12, 2024
655a146
Restart CI for intermittent Android failures
proneon267 Oct 12, 2024
4f2f2a5
Debugging android CI failure
proneon267 Oct 13, 2024
c29ab39
Merge branch 'window_states' of https://github.com/proneon267/toga in…
proneon267 Oct 13, 2024
0d67322
Debugging android CI failure
proneon267 Oct 13, 2024
07e82f9
replaced with
proneon267 Oct 15, 2024
8be4d8d
replaced with
proneon267 Oct 15, 2024
1692a0d
added new method on window probe
proneon267 Oct 15, 2024
f8ee69d
Revert commented code
proneon267 Oct 15, 2024
b82b6d0
Revert
proneon267 Oct 15, 2024
247847e
Corrected probe method on android
proneon267 Oct 15, 2024
1b624ad
Merge branch 'beeware:main' into window_states
proneon267 Oct 16, 2024
5560e3d
Diagnosing macOS-arm64 failures
proneon267 Oct 16, 2024
a8fed19
Merge branch 'beeware:main' into window_states
proneon267 Oct 18, 2024
5f0c1a2
Correcting testbed failure
proneon267 Oct 18, 2024
136cdcf
Removed unused android code
proneon267 Oct 21, 2024
8fcdbd6
Fixed testbed for macOS
proneon267 Oct 25, 2024
ef584b1
Fixed testbed for Android
proneon267 Oct 25, 2024
7f28348
Enable additional test cases
proneon267 Oct 25, 2024
6e0c091
Removed stray comments
proneon267 Oct 25, 2024
f535cd6
Restart CI for intermittent Android failure
proneon267 Oct 25, 2024
c175b6a
Fix Android delay
proneon267 Oct 25, 2024
bc1f902
Added note on state setter
proneon267 Oct 27, 2024
e8864d5
Merge branch 'beeware:main' into window_states
proneon267 Oct 28, 2024
0f0103c
Merge branch 'beeware:main' into window_states
proneon267 Nov 5, 2024
4162e4b
Fixed window size after restoration to NORMAL state on wayland
proneon267 Nov 7, 2024
eb51730
Fixed window size setting on wayland
proneon267 Nov 7, 2024
b25b902
Revert changes
proneon267 Nov 7, 2024
8df6c4b
Add delay to prevent glitching on wayland
proneon267 Nov 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions android/src/toga_android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import toga
from toga.command import Command, Group, Separator
from toga.constants import WindowState
from toga.dialogs import InfoDialog
from toga.handlers import simple_handler

Expand Down Expand Up @@ -321,14 +322,19 @@ def set_current_window(self, window):
pass

######################################################################
# Full screen control
# Presentation mode controls
######################################################################

def enter_full_screen(self, windows):
pass
def enter_presentation_mode(self, screen_window_dict):
for screen, window in screen_window_dict.items():
window._impl._before_presentation_mode_screen = window.screen
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this variable in aid of? It doesn't appear to be used anywhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed it.

window.screen = screen
window._impl.set_window_state(WindowState.PRESENTATION)

def exit_full_screen(self, windows):
pass
def exit_presentation_mode(self):
for window in self.interface.windows:
if window.state == WindowState.PRESENTATION:
window._impl.set_window_state(WindowState.NORMAL)

######################################################################
# Platform-specific APIs
Expand Down
79 changes: 77 additions & 2 deletions android/src/toga_android/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from java import dynamic_proxy
from java.io import ByteArrayOutputStream

from toga.constants import WindowState
from toga.types import Position, Size

from .container import Container
Expand All @@ -31,11 +32,17 @@ def onGlobalLayout(self):


class Window(Container):
# ActionBar is always hidden on Window.
_actionbar_shown_by_default = False

def __init__(self, interface, title, position, size):
super().__init__()
self.interface = interface
self.interface._impl = self
self._initial_title = title
# Use a shadow variable since the presence of ActionBar is not
# a reliable indicator for confirmation of presentation mode.
self._in_presentation_mode = False

######################################################################
# Window properties
Expand Down Expand Up @@ -137,8 +144,73 @@ def get_visible(self):
# Window state
######################################################################

def set_full_screen(self, is_full_screen):
self.interface.factory.not_implemented("Window.set_full_screen()")
def get_window_state(self):
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
# window.state is called in _close(), which itself sometimes
# is called during early stages of app startup, during which
# the app attribute may not exist. In such cases, return NORMAL.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry? _close() is called during early stages of app startup? When?

Copy link
Contributor Author

@proneon267 proneon267 Jul 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree I was wrong. It should have been worded as "during the setup of a new test after completion of a previous test".

if I modify get_window_state() as:

def get_window_state(self):
    # window.state is called in _close(), which itself sometimes
    # is called during early stages of app startup, during which
    # the app attribute may not exist. In such cases, return NORMAL.

    if getattr(self, "app", None) is None:
        raise RuntimeError

    decor_view = self.app.native.getWindow().getDecorView()
    system_ui_flags = decor_view.getSystemUiVisibility()
    ....

Then on running the testbed on Android:

briefcase run android -ur --test -- tests/window/test_window.py

Every test after tests/window/test_window.py::test_secondary_window fails on Android:

I/python.stdout: ============================= test session starts ==============================
I/python.stdout: collecting ...
I/python.stdout: collected 12 items
I/python.stdout:
I/python.stdout: tests/window/test_window.py::test_title
I/python.stdout: PASSED                           [  8%]
I/python.stdout:
I/python.stdout: tests/window/test_window.py::test_visibility
I/python.stdout: PASSED                      [ 16%]
I/python.stdout:
I/python.stdout: tests/window/test_window.py::test_secondary_window
I/python.stdout: PASSED                [ 25%]
I/python.stdout:
I/python.stdout: tests/window/test_window.py::test_move_and_resize
I/python.stdout: ERROR                  [ 33%]
I/python.stdout:
I/python.stdout: ...

Stack dump of the test failure:

I/python.stdout: ____________________ ERROR at setup of test_move_and_resize ____________________
I/python.stdout: Traceback (most recent call last):
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/runner.py", line 341, in from_call
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/runner.py", line 241, in <lambda>
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_hooks.py", line 513, in __call__
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_manager.py", line 120, in _hookexec
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 139, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 122, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/unraisableexception.py", line 85, in pytest_runtest_setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/unraisableexception.py", line 65, in unraisable_exception_runtest_hook
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 122, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/logging.py", line 844, in pytest_runtest_setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/logging.py", line 833, in _runtest_for
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 122, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/capture.py", line 873, in pytest_runtest_setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 122, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/threadexception.py", line 82, in pytest_runtest_setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/threadexception.py", line 63, in thread_exception_runtest_hook
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 103, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/runner.py", line 159, in pytest_runtest_setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/runner.py", line 517, in setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/runner.py", line 514, in setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/python.py", line 1635, in setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/fixtures.py", line 686, in _fillfixtures
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/fixtures.py", line 521, in getfixturevalue
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/fixtures.py", line 606, in _get_active_fixturedef
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/fixtures.py", line 1076, in execute
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_hooks.py", line 513, in __call__
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_manager.py", line 120, in _hookexec
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 182, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_result.py", line 100, in get_result
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 167, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/setuponly.py", line 36, in pytest_fixture_setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pluggy/_callers.py", line 103, in _multicall
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/fixtures.py", line 1125, in pytest_fixture_setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/_pytest/fixtures.py", line 887, in call_fixture_func
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pytest_asyncio/plugin.py", line 366, in _async_fixture_wrapper
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/app/tests/conftest.py", line 130, in run_until_complete
I/python.stdout:     return asyncio.run_coroutine_threadsafe(coro, self.loop).result()
I/python.stdout:   File "stdlib/concurrent/futures/_base.py", line 458, in result
I/python.stdout:   File "stdlib/concurrent/futures/_base.py", line 403, in __get_result
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/pytest_asyncio/plugin.py", line 361, in setup
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/app/tests/conftest.py", line 73, in window_cleanup
I/python.stdout:     window.close()
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/toga/window.py", line 315, in close
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/toga/window.py", line 325, in _close
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/toga/window.py", line 471, in state
I/python.stdout:   File "/data/data/org.beeware.toga.testbed/files/chaquopy/AssetFinder/requirements/toga_android/window.py", line 152, in get_window_state
I/python.stdout:     raise RuntimeError
I/python.stdout: RuntimeError

This indicates that, the conftest is causing the expected call to window.close() after each test:

@fixture(autouse=True)
async def window_cleanup(app, main_window):
# Ensure that at the end of every test, all windows that aren't the
# main window have been closed and deleted. This needs to be done in
# 2 passes because we can't modify the list while iterating over it.
kill_list = []
for window in app.windows:
if window != main_window:
kill_list.append(window)
# Then purge everything on the kill list.
while kill_list:
window = kill_list.pop()
window.close()
del window
# Force a GC pass on the main thread. This isn't perfect, but it helps
# minimize garbage collection on the test thread.
gc.collect()

This cleanup behavior is expected, but I am a bit surprised that window.close() actually calls _close() on Android, since the same MainWindow is used for all the tests.

But, since get_window_state() encounters a situation, where self.app is not assigned, this check guard is needed.

if getattr(self, "app", None) is None:
return WindowState.NORMAL
decor_view = self.app.native.getWindow().getDecorView()
system_ui_flags = decor_view.getSystemUiVisibility()
if system_ui_flags & (
decor_view.SYSTEM_UI_FLAG_FULLSCREEN
| decor_view.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| decor_view.SYSTEM_UI_FLAG_IMMERSIVE
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
):
if self._in_presentation_mode:
return WindowState.PRESENTATION
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
else:
return WindowState.FULLSCREEN
return WindowState.NORMAL

def set_window_state(self, state):
current_state = self.get_window_state()
if current_state == state:
return
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this should be an optimisation at the core level - it's something that will be common to every implementation.

Copy link
Contributor Author

@proneon267 proneon267 Sep 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't be done at the core level because we can't reliably determine the current state. Backends like Cocoa and GTK use non-blocking state APIs, meaning the state might be in in-between transition when checked. As a result, we could end up comparing against an outdated state.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - but that means there are 2 possible interpretations of "window state" - the "current state", and the "state we're transitioning to". On blocking APIs, the two are always the same; on non-blocking, they might be different. This is easy enough to accomodate with a boolean argument to get_window_state() that allows the user to explicitly request "actual" state or "in progress" state.

For the purpose of the public API, I'd argue you always want the "state we're transitioning to" - as that is the answer that will be consistent across platforms, and will ensure that:

window.state = X
assert window.state == X

will always return the expected result. However, it would warrant a note on the state accessor to highlight that the value returned might not reflect the actual state immediately after making a request.

Copy link
Contributor Author

@proneon267 proneon267 Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have modified get_window_state() and moved same state checking to the core. I have also moved same state transition tests to the core.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which case - is the check right here still needed?

Copy link
Contributor Author

@proneon267 proneon267 Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, not really, since the Android API is blocking in nature and the internal API set_window_state() is not called internally anywhere on the implementation side.

It is only required on the non-blocking API backends like cocoa, as the internal API _apply_state() is called internally on the implementation side at different places.

So, I have removed it from the Android backend.

EDIT: On further testing, this check acts as a termination condition for some cases when set_window_state() is called internally. So, I have kept it.

decor_view = self.app.native.getWindow().getDecorView()
if (
current_state != WindowState.NORMAL
and state != WindowState.NORMAL
and (getattr(self, "_pending_window_state_transition", None) is None)
):
# Set Window state to NORMAL before changing to other states as some
# states block changing window state without first exiting them or
# can even cause rendering glitches.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok... but this block will result in calling set_window_state(FULLSCREEN) and getting back a NORMAL window. I don't see how the _pending flag is used for anything but changing the interpretation of future calls to set_window_state().

self._pending_window_state_transition = state
self.set_window_state(WindowState.NORMAL)

elif state in {WindowState.FULLSCREEN, WindowState.PRESENTATION}:
decor_view.setSystemUiVisibility(
decor_view.SYSTEM_UI_FLAG_FULLSCREEN
| decor_view.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| decor_view.SYSTEM_UI_FLAG_IMMERSIVE
)
if state == WindowState.PRESENTATION:
# Marking this as no branch, since the testbed can't create a simple
# window, so we can't test the other branch.
if self._actionbar_shown_by_default: # pragma: no branch
self.app.native.getSupportActionBar().hide()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this sort of functionality not be better served by having a "show/hide action bar" method that is a no-op on Window, and implemented on MainWindow? That removes the need for a bunch of private attribute flags.

self._in_presentation_mode = True
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved

else:
# On Android Maximized state is same as the Normal state
if state in {WindowState.NORMAL, WindowState.MAXIMIZED}:
if current_state in {
WindowState.FULLSCREEN,
WindowState.PRESENTATION,
}:
decor_view.setSystemUiVisibility(0)
if current_state == WindowState.PRESENTATION:
# Marking this as no branch, since the testbed can't create a simple
# window, so we can't test the other branch.
if self._actionbar_shown_by_default: # pragma: no branch
self.app.native.getSupportActionBar().show()
self._in_presentation_mode = False

# Complete any pending window state transition.
if getattr(self, "_pending_window_state_transition", None) is not None:
self.set_window_state(self._pending_window_state_transition)
del self._pending_window_state_transition
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This whole method is, quite literally, a state machine - and I'm having a great deal of difficulty understanding the state transitions.

In general, a state machine should be structured as :

if current state 1:
    if future state 1:
        ...
    elif future state 2:
       ...
elif current state 2:
    ...

and with that structure, you should be able to clearly exhaust all possible current and future states.


######################################################################
# Window capabilities
Expand All @@ -160,6 +232,9 @@ def get_image_data(self):


class MainWindow(Window):
# ActionBar is always hidden on MainWindow.
_actionbar_shown_by_default = True

def configure_titlebar(self):
# Display the titlebar on a MainWindow.
pass
Expand Down
18 changes: 18 additions & 0 deletions android/tests_backend/window.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from androidx.appcompat import R as appcompat_R

from toga.constants import WindowState

from .dialogs import DialogsMixin
from .probe import BaseProbe

Expand All @@ -20,6 +22,22 @@ def content_size(self):
self.root_view.getHeight() / self.scale_factor,
)

def get_window_state(self):
decor_view = self.native.getWindow().getDecorView()
system_ui_flags = decor_view.getSystemUiVisibility()
if system_ui_flags & (
decor_view.SYSTEM_UI_FLAG_FULLSCREEN
| decor_view.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| decor_view.SYSTEM_UI_FLAG_IMMERSIVE
):
if self.window._impl._in_presentation_mode:
current_state = WindowState.PRESENTATION
else:
current_state = WindowState.FULLSCREEN
else:
current_state = WindowState.NORMAL
return current_state
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this probe add anything. It's an literal reproduction of parts of the "real" get_window_state() method - what do we gain by the duplication?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is still current.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed it.


def _native_menu(self):
return self.native.findViewById(appcompat_R.id.action_bar).getMenu()

Expand Down
1 change: 1 addition & 0 deletions changes/1857.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Toga apps can now detect and set their window states including maximized, minimized, normal, full screen and presentation states.
1 change: 1 addition & 0 deletions changes/1857.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"Full screen mode" on an app has been renamed "Presentation mode" to avoid the ambiguity with "full screen mode" on a window. The ``toga.App.enter_full_screen`` and ``toga.App.exit_full_screen`` APIs have been renamed ``toga.App.enter_presentation_mode`` and ``toga.App.exit_presentation_mode``, respectively. ```
39 changes: 27 additions & 12 deletions cocoa/src/toga_cocoa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import toga
from toga.app import overridden
from toga.command import Command, Separator
from toga.constants import WindowState
from toga.handlers import NativeHandler, simple_handler

from .keys import cocoa_key
Expand Down Expand Up @@ -491,33 +492,47 @@ def set_current_window(self, window):
window._impl.native.makeKeyAndOrderFront(window._impl.native)

######################################################################
# Full screen control
# Presentation mode controls
######################################################################

def enter_full_screen(self, windows):
def enter_presentation_mode(self, screen_window_dict):
opts = NSMutableDictionary.alloc().init()
opts.setObject(
NSNumber.numberWithBool(True), forKey="NSFullScreenModeAllScreens"
)

for window, screen in zip(windows, NSScreen.screens):
window.content._impl.native.enterFullScreenMode(screen, 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.
for screen, window in screen_window_dict.items():
window.content._impl.native.enterFullScreenMode(
screen._impl.native, withOptions=opts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above - we try not to use the "all on one lines but indented" when there's more than one argument. Add a comma to the end of the argument list and black-format to 1 argument per line.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, Thanks.

)
# 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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I've asked this before, but this ticket has enough history that it's not easy to find a relevant comment...

Why is this logic in App, and not part of the set_window_state() handling for Window? It's literally per-window logic for performing per-window state changes - I can't see why there's a need to split up the logic, if only because it means there's a gap in Window.set_window_state() that would be picked up by a formal type analysis. If there is a reason, then the reason should be documented in a code comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During the design discussion, we had discussed to keep presentation mode on the app in cocoa. But looking at it now, moving the code to window makes more sense. So, I'll move it.


def exit_full_screen(self, windows):
# Process any pending window state.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this logic being done here, rather than as part of set_window_state()?

if (
window._impl._pending_state_transition
and window._impl._pending_state_transition != WindowState.PRESENTATION
):
window._impl._apply_state(WindowState.NORMAL)
else:
window._impl._pending_state_transition = None

def exit_presentation_mode(self):
opts = NSMutableDictionary.alloc().init()
opts.setObject(
NSNumber.numberWithBool(True), forKey="NSFullScreenModeAllScreens"
)

for window in windows:
window.content._impl.native.exitFullScreenModeWithOptions(opts)
window.content.refresh()
for window in self.interface.windows:
if window.state == WindowState.PRESENTATION:
window.content._impl.native.exitFullScreenModeWithOptions(opts)
window.content.refresh()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see how this mechanically exit presentation mode, but I don't see how this causes a change in the value of window.state. The windowDidExitFullScreen: selector will apply the pending state... but how is the pending state set? This either indicates (a) a gap in testing, or (b) the need for a comment explaining the workflow.

Also - as above, it's not clear why this isn't part of the set_window_state() implementation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved it to set_window_state().


# Process any pending window state.
window._impl._apply_state(window._impl._pending_state_transition)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again - why here, instead of as part of set_window_state()?



class DocumentApp(App): # pragma: no cover
Expand Down
Loading
Loading