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

Merged
merged 301 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
301 commits
Select commit Hold shift + click to select a range
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
1097207
Removed intermediate states from mobile test
proneon267 Nov 8, 2024
7e7cc1e
Merge branch 'main' into window_states
proneon267 Nov 11, 2024
e01237a
Correct probe property
proneon267 Nov 12, 2024
3236559
Separated test
proneon267 Nov 19, 2024
ef8725b
Simplified test cases
proneon267 Nov 19, 2024
9520809
Merge branch 'main' into window_states
proneon267 Nov 19, 2024
4ff1fd0
Pre-commit fix
proneon267 Nov 19, 2024
0931280
Removed unused fixture
proneon267 Nov 19, 2024
2024626
Modified delay indicator name
proneon267 Nov 20, 2024
91a8f72
Modified delay duration
proneon267 Nov 20, 2024
68b0a44
Removed stray comments
proneon267 Nov 20, 2024
0d807f6
Ignore window state requests on a hidden window
proneon267 Nov 28, 2024
9add077
Ignore window resize requests while in fullscreen or presentation state.
proneon267 Nov 28, 2024
35a49a1
Merge branch 'main' into window_states
proneon267 Nov 29, 2024
c7ce202
Ignore window position requests while in fullscreen or presentation s…
proneon267 Nov 29, 2024
23319cf
Added docstrings
proneon267 Nov 29, 2024
5b5e44a
Reduce test cases for rapid state assignment
proneon267 Nov 29, 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
11 changes: 6 additions & 5 deletions android/src/toga_android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from org.beeware.android import IPythonApp, MainActivity

from toga.command import Command, Group, Separator
from toga.constants import WindowState

from .libs import events
from .screens import Screen as ScreenImpl
Expand Down Expand Up @@ -297,14 +298,14 @@ 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):
self.interface.main_window.state = WindowState.PRESENTATION

def exit_full_screen(self, windows):
pass
def exit_presentation_mode(self):
self.interface.main_window.state = WindowState.NORMAL

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

from toga.constants import WindowState

from .container import Container
from .screens import Screen as ScreenImpl

Expand Down Expand Up @@ -135,8 +137,70 @@ 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
# Windows are always full screen
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
)
) != 0:
Copy link
Member

Choose a reason for hiding this comment

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

!= 0 should be redundant here. Integers cleanly evaluate as booleans.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed it.

if not self.app.native.getSupportActionBar().isShowing():
return WindowState.PRESENTATION
freakboy3742 marked this conversation as resolved.
Show resolved Hide resolved
else:
return WindowState.FULLSCREEN
# elif getattr(self, "_is_minimized", False) is True:
# return WindowState.MINIMIZED
return WindowState.NORMAL

def set_window_state(self, state):
current_state = self.get_window_state()
decor_view = self.app.native.getWindow().getDecorView()
# 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:
self.app.native.getSupportActionBar().show()
Copy link
Member

Choose a reason for hiding this comment

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

Need to be careful about this - if the main window is a toga.Window, the support action bar will exist, but it shouldn't ever be shown.

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 changed it.


# Doesn't work consistently
Copy link
Member

Choose a reason for hiding this comment

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

If something doesn't work, it doesn't work. We shouldn't be committing large chunks of commented-out code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed it.

# elif current_state == WindowState.MINIMIZED:
# # Get the context
# context = self.app.native.getApplicationContext()
# # Create the intent to bring the activity to the foreground
# new_intent = Intent(context, self.app.native.getClass())
# # These 2 options work properly by resuming existing MainActivity instead of creating
# # a new instance of MainActivity, but they work only once:
# new_intent.addFlags(
# Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP
# )
# new_intent.setFlags(
# Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP
# )
# # This works every time but starts new instance of MainActivity
# new_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
# self.app.native.startActivity(new_intent)
# self._is_minimized = False
else:
if 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:
self.app.native.getSupportActionBar().hide()
# elif state == WindowState.MINIMIZED:
# # This works but the issue lies in restoring to normal state
# self.app.native.moveTaskToBack(True)
# self._is_minimized = True

######################################################################
# Window capabilities
Expand Down
22 changes: 22 additions & 0 deletions android/tests_backend/window.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pytest
from androidx.appcompat import R as appcompat_R

from toga.constants import WindowState

from .probe import BaseProbe


Expand All @@ -19,6 +21,26 @@ def content_size(self):
self.root_view.getHeight() / self.scale_factor,
)

def is_window_state(self, 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 the API is_window_state, and not get_window_state?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it.

# Windows are always full screen
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
)
) != 0:
if not self.native.getSupportActionBar().isShowing():
current_state = WindowState.PRESENTATION
else:
current_state = WindowState.FULLSCREEN
else:
current_state = WindowState.NORMAL
return bool(current_state == state)

async def close_info_dialog(self, dialog):
dialog_view = self.get_dialog_view()
self.assert_dialog_buttons(dialog_view, ["OK"])
Expand Down
1 change: 1 addition & 0 deletions changes/1857.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Calling `Window.close()` on platforms like Android and iOS now correctly performs a no-op and doesn't clear the window from the window registry.
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 @@
The older full screen APIs on `toga.App` and `toga.Window` are now deprecated and are instead replaced by their suitable newer API counterparts.
proneon267 marked this conversation as resolved.
Show resolved Hide resolved
22 changes: 12 additions & 10 deletions cocoa/src/toga_cocoa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import toga
from toga.command import Separator
from toga.constants import WindowState
from toga.handlers import NativeHandler

from .keys import cocoa_key
Expand Down Expand Up @@ -503,33 +504,34 @@ 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)
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 full screen 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):
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().



class DocumentApp(App): # pragma: no cover
Expand Down
67 changes: 63 additions & 4 deletions cocoa/src/toga_cocoa/window.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from rubicon.objc import CGSize

from toga.command import Command, Separator
from toga.constants import WindowState
from toga_cocoa.container import Container
from toga_cocoa.libs import (
SEL,
Expand Down Expand Up @@ -41,6 +42,11 @@ def windowDidResize_(self, notification) -> None:
# Set the window to the new size
self.interface.content.refresh()

@objc_method
def windowDidExitFullScreen_(self, notification) -> None:
# This can be used to ensure that the window has completed exiting full screen.
Copy link
Member

Choose a reason for hiding this comment

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

... but it doesn't do anything. Why is it required?

pass

######################################################################
# Toolbar delegate methods
######################################################################
Expand Down Expand Up @@ -205,8 +211,14 @@ def set_title(self, title):
######################################################################

def close(self):
if self.interface.content:
self.interface.content.window = None
self.interface.app.windows.discard(self.interface)

self.native.close()

self.interface._closed = True

def create_toolbar(self):
# Purge any existing toolbar items
self.purge_toolbar()
Expand Down Expand Up @@ -339,10 +351,57 @@ def get_visible(self):
# Window state
######################################################################

def set_full_screen(self, is_full_screen):
current_state = bool(self.native.styleMask & NSWindowStyleMask.FullScreen)
if is_full_screen != current_state:
self.native.toggleFullScreen(self.native)
def get_window_state(self):
if self.interface.content and bool(
self.interface.content._impl.native.isInFullScreenMode()
Copy link
Member

Choose a reason for hiding this comment

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

What happens if I take a window without content, and put it into full screen mode? It seems to me that this implies a window should always have content, even if it's a dummy box.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Entering presentation mode on cocoa re-homes the content(i.e., NSBox) in a separate NSFullScreenWindow. Here the window isn't going in presentation mode, rather the content is. So, without content, the API to enter presentation mode won't work on cocoa.

Copy link
Member

Choose a reason for hiding this comment

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

... but I can still call the API, so it needs to return an appropriate value. As currently written, this will return a value of NORMAL. The fact that the implementation works on the content doesn't alter the public API contract.

Alternatively, it needs to be either documented as a platform quirk, or there's a higher level "guarantee that the window has content, even if it's just a toga.Box" requirement.

Copy link
Contributor Author

@proneon267 proneon267 Aug 15, 2024

Choose a reason for hiding this comment

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

I have added to the docs, that it is mandatory to have a content on a window, for it to go on PRESENTATION mode. I have also added a new check on the core and a new test.

Copy link
Member

Choose a reason for hiding this comment

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

Or, we can avoid the documentation issue entirely, and fix the underlying problem. It seems relatively straightforward to define a toga.Box() as window content if the window doesn't explicitly provide content. Why not do that and avoid the edge case entirely?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is now solved by #2800.

):
return WindowState.PRESENTATION
elif bool(self.native.styleMask & NSWindowStyleMask.FullScreen):
return WindowState.FULLSCREEN
elif bool(self.native.isZoomed):
return WindowState.MAXIMIZED
elif bool(self.native.isMiniaturized):
return WindowState.MINIMIZED
else:
return WindowState.NORMAL

def set_window_state(self, state):
current_state = self.get_window_state()
if state == WindowState.NORMAL:
# If the window is maximized, restore it to its normal size
if current_state == WindowState.MAXIMIZED:
self.native.setIsZoomed(False)
# Deminiaturize the window to restore it to its previous state
elif current_state == WindowState.MINIMIZED:
self.native.setIsMiniaturized(False)
# If the window is in full-screen mode, exit full-screen mode
elif current_state == WindowState.FULLSCREEN:
# This doesn't wait for completely exiting full screen mode. Hence,
# this will cause problems when rapid window state switching is done.
# We should wait until `windowDidExitFullScreen_` is notified and then
# return to user.
self.native.toggleFullScreen(self.native)
# If the window is in presentation mode, exit presentation mode
elif current_state == WindowState.PRESENTATION:
self.interface.app.exit_presentation_mode()
else:
Copy link
Member

Choose a reason for hiding this comment

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

In terms of code organisation, it might make more sense for "NORMAL" to be the "else" case, since it's the "least special" case, and a more reasonable default.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it.

if state == WindowState.MAXIMIZED:
Copy link
Member

Choose a reason for hiding this comment

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

What happens if you maximise a window that is currently in presentation mode? Or maximise a window that isn't being displayed while you're in presentation mode?

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've modified it.

self.native.setIsZoomed(True)

elif state == WindowState.MINIMIZED:
self.native.setIsMiniaturized(True)

elif state == WindowState.FULLSCREEN:
self.native.toggleFullScreen(self.native)

elif state == WindowState.PRESENTATION:
self.interface.app.enter_presentation_mode(
{self.interface.screen: self.interface}
)
else: # pragma: no cover
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 - you pick a "default" value and make this the else. In this case, you can do this with a single level of if, making the NORMAL case the fallthrough else case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it.

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 you've left the #pragma:no cover in place.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure - but you've left the #pragma:no cover in place.

But, since that else branch would never be touched, so removing #pragma:no cover would give missing coverage.

Copy link
Member

Choose a reason for hiding this comment

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

If the branch isn't being touched, then that's a gap in your coverage. That's something that needs to be fixed.

# pragma: no cover is a last resort - something you only use if there is literally no way to reach a particular line of code (e.g., a scenario that can't be replicated in testbed, like show_actionbar on Android's base Window class). In all other cases, it's an indication of a missing test. This case is "move to presentation mode from normal mode" - I can't see any reason why that wouldn't be testable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But, exit_presentation_mode() is called early in window.state, so if the window was in presentation mode then it would have exited presentation mode by the time set_presentation_mode() would be called. So, current_state will never be PRESENTATION when checked inside _apply_state(). Hence, this branch cannot be reached.

# Marking this as no cover, since the type of the state parameter
# value is checked on the interface.
return

######################################################################
# Window capabilities
Expand Down
9 changes: 4 additions & 5 deletions cocoa/tests_backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rubicon.objc import NSPoint, ObjCClass, objc_id, send_message

import toga
from toga.constants import WindowState
from toga_cocoa.keys import cocoa_key, toga_key
from toga_cocoa.libs import (
NSApplication,
Expand All @@ -14,6 +15,7 @@
)

from .probe import BaseProbe
from .window import WindowProbe

NSPanel = ObjCClass("NSPanel")

Expand Down Expand Up @@ -52,13 +54,10 @@ def is_cursor_visible(self):
return self.app._impl._cursor_visible

def is_full_screen(self, window):
Copy link
Member

Choose a reason for hiding this comment

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

If we're renaming an API, we need to rename it everywhere.

return window.content._impl.native.isInFullScreenMode()
return WindowProbe(self.app, window).is_window_state(WindowState.PRESENTATION)

def content_size(self, window):
return (
window.content._impl.native.frame.size.width,
window.content._impl.native.frame.size.height,
)
return WindowProbe(self.app, window).presentation_content_size
Copy link
Member

Choose a reason for hiding this comment

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

What do we gain from making this change? Either keep the implementation here, or move it to Window. There's no need to preserve both, and make one probe dependent on the other.


def assert_app_icon(self, icon):
# We have no real way to check we've got the right icon; use pixel peeping as a
Expand Down
27 changes: 25 additions & 2 deletions cocoa/tests_backend/window.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from rubicon.objc import objc_id, send_message
from rubicon.objc.collections import ObjCListInstance

from toga.constants import WindowState
from toga_cocoa.libs import (
NSURL,
NSAlertFirstButtonReturn,
Expand Down Expand Up @@ -49,9 +50,31 @@ def content_size(self):
self.native.contentView.frame.size.height,
)

@property
def presentation_content_size(self):
return (
self.window.content._impl.native.frame.size.width,
self.window.content._impl.native.frame.size.height,
)

def is_window_state(self, state):
Copy link
Member

Choose a reason for hiding this comment

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

As with the underlying API - why is_ and not get_?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it.

if self.window.content and bool(
self.window.content._impl.native.isInFullScreenMode()
):
current_state = WindowState.PRESENTATION
elif bool(self.native.styleMask & NSWindowStyleMask.FullScreen):
current_state = WindowState.FULLSCREEN
elif bool(self.native.isZoomed):
current_state = WindowState.MAXIMIZED
elif bool(self.native.isMiniaturized):
current_state = WindowState.MINIMIZED
else:
current_state = WindowState.NORMAL
return bool(current_state == state)

@property
def is_full_screen(self):
return bool(self.native.styleMask & NSWindowStyleMask.FullScreen)
return self.is_window_state(WindowState.FULLSCREEN)

@property
def is_resizable(self):
Expand All @@ -67,7 +90,7 @@ def is_minimizable(self):

@property
def is_minimized(self):
return bool(self.native.isMiniaturized)
return self.is_window_state(WindowState.MINIMIZED)

def minimize(self):
self.native.performMiniaturize(None)
Expand Down
Loading
Loading