diff --git a/android/tests_backend/screen.py b/android/tests_backend/screen.py index b7de2cd18..fb5b4ab6b 100644 --- a/android/tests_backend/screen.py +++ b/android/tests_backend/screen.py @@ -1,3 +1,4 @@ +import pytest from android.view import Display from toga_android.widgets.base import Scalable @@ -14,14 +15,5 @@ class ScreenProbe(BaseProbe, Scalable): self.init_scale(app._impl.native) assert isinstance(self.native, Display) - def assert_name(self): - assert self.screen.name == self.native.getName() - - def assert_origin(self): - assert self.screen.origin == (0, 0) - - def assert_size(self): - assert self.screen.size == ( - self.scale_out(self.native.getWidth()), - self.scale_out(self.native.getHeight()), - ) + def get_screenshot(self): + pytest.skip("Screen.as_image is not implemented on Android.") diff --git a/cocoa/src/toga_cocoa/libs/foundation.py b/cocoa/src/toga_cocoa/libs/foundation.py index c2bac3a3d..ffbf612f6 100644 --- a/cocoa/src/toga_cocoa/libs/foundation.py +++ b/cocoa/src/toga_cocoa/libs/foundation.py @@ -51,7 +51,3 @@ NSURLRequest = ObjCClass("NSURLRequest") ###################################################################### # NSValue.h NSNumber = ObjCClass("NSNumber") - -###################################################################### -# NSAutoreleasePool.h -NSAutoreleasePool = ObjCClass("NSAutoreleasePool") diff --git a/cocoa/src/toga_cocoa/screen.py b/cocoa/src/toga_cocoa/screen.py index b991551c5..2c5e6fe9b 100644 --- a/cocoa/src/toga_cocoa/screen.py +++ b/cocoa/src/toga_cocoa/screen.py @@ -2,7 +2,6 @@ from toga.screen import Screen as ScreenInterface from toga_cocoa.libs import ( CGImageGetHeight, CGImageGetWidth, - NSAutoreleasePool, NSImage, core_graphics, ) @@ -44,13 +43,9 @@ class Screen: cg_direct_display_id, self.native.frame, ) - # Create an autorelease pool to manage memory - pool = NSAutoreleasePool.alloc().init() # Get the size of the CGImage size = CGImageGetWidth(cg_image), CGImageGetHeight(cg_image) # Create an NSImage from the CGImage ns_image = NSImage.alloc().initWithCGImage(cg_image, size=size) - # Drain the autorelease pool to release memory - pool.release() return ns_image diff --git a/cocoa/tests_backend/screen.py b/cocoa/tests_backend/screen.py index ec665748e..c5a7c4d2d 100644 --- a/cocoa/tests_backend/screen.py +++ b/cocoa/tests_backend/screen.py @@ -11,13 +11,5 @@ class ScreenProbe(BaseProbe): self.native = screen._impl.native assert isinstance(self.native, NSScreen) - def assert_name(self): - assert self.screen.name == self.native.localizedName - - def assert_origin(self): - frame_native = self.native.frame - assert self.screen.origin == (frame_native.origin.x, frame_native.origin.y) - - def assert_size(self): - frame_native = self.native.frame - assert self.screen.size == (frame_native.size.width, frame_native.size.height) + def get_screenshot(self): + return self.screen.as_image() diff --git a/core/tests/test_window.py b/core/tests/test_window.py index f33b70a0e..bd10287bb 100644 --- a/core/tests/test_window.py +++ b/core/tests/test_window.py @@ -368,27 +368,7 @@ def test_screen(window, app): def test_screen_position(window, app): """The window can be relocated using absolute and relative screen positions.""" - # _________________________________________________ - # Display Setup: | - # ________________________________________________| - # |--1366--| | - # (-1366,-768) _________ | - # | | | | - # 768 |Secondary| | - # | | Screen | | - # | |_________|(0,0) | - # _________ | - # | | | | - # 1080 | Primary | | - # | | Screen | | - # | |_________|(1920,1080) | - # |---1920--| | - # ________________________________________________| - # `window.screen` will return `Secondary Screen` | - # as window is on secondary screen to better | - # test out the differences between | - # `window.position` & `window.screen_position`. | - # ________________________________________________| + # Details about screen layout are in toga_dummy=>app.py=>get_screens() initial_position = window.position window.position = (-100, -100) assert window.position != initial_position diff --git a/dummy/src/toga_dummy/app.py b/dummy/src/toga_dummy/app.py index 42872224a..d665b295e 100644 --- a/dummy/src/toga_dummy/app.py +++ b/dummy/src/toga_dummy/app.py @@ -85,6 +85,11 @@ class App(LoggedObject): # | |_________|(1920,1080) | # |---1920--| | # ________________________________________________| + # `window.screen` will return `Secondary Screen` | + # as window is on secondary screen to better | + # test out the differences between | + # `window.position` & `window.screen_position`. | + # ________________________________________________| return [ ScreenImpl(native=("Primary Screen", (0, 0), (1920, 1080))), ScreenImpl(native=("Secondary Screen", (-1366, -768), (1366, 768))), diff --git a/gtk/src/toga_gtk/screen.py b/gtk/src/toga_gtk/screen.py index 9d63e1c91..5c28a9c57 100644 --- a/gtk/src/toga_gtk/screen.py +++ b/gtk/src/toga_gtk/screen.py @@ -30,8 +30,11 @@ class Screen: return geometry.width, geometry.height def get_image_data(self): - if os.environ.get("XDG_SESSION_TYPE", "").lower() == "x11": # pragma: no cover - # Only works for x11 + if "WAYLAND_DISPLAY" in os.environ: + # Not implemented on wayland due to wayland security policies. + self.interface.factory.not_implemented("Screen.get_image_data() on Wayland") + else: + # Only works for Xorg display = self.native.get_display() screen = display.get_default_screen() window = screen.get_root_window() @@ -45,7 +48,3 @@ class Screen: else: print("Failed to save screenshot to buffer.") return None - # CI runs on wayland - else: - # Not implemented on wayland due to wayland security policies. - self.interface.factory.not_implemented("Screen.get_image_data() on Wayland") diff --git a/gtk/tests_backend/screen.py b/gtk/tests_backend/screen.py index 745b0270e..c07ad20ae 100644 --- a/gtk/tests_backend/screen.py +++ b/gtk/tests_backend/screen.py @@ -1,5 +1,6 @@ import os +import pytest from gi.repository import GdkX11 from .probe import BaseProbe @@ -14,16 +15,11 @@ class ScreenProbe(BaseProbe): if os.environ.get("XDG_SESSION_TYPE", "").lower() == "x11": assert isinstance(self.native, GdkX11.X11Monitor) else: - # TODO: Check for the wayland monitor native type + # TODO: Check for the other monitor native types pass - def assert_name(self): - assert self.screen.name == self.native.get_model() - - def assert_origin(self): - geometry = self.native.get_geometry() - assert self.screen.origin == (geometry.x, geometry.y) - - def assert_size(self): - geometry = self.native.get_geometry() - assert self.screen.size == (geometry.width, geometry.height) + def get_screenshot(self): + if "WAYLAND_DISPLAY" in os.environ: + pytest.skip("Screen.as_image() is not implemented on wayland.") + else: + return self.screen.as_image() diff --git a/iOS/tests_backend/screen.py b/iOS/tests_backend/screen.py index af996ad9f..15b199ce7 100644 --- a/iOS/tests_backend/screen.py +++ b/iOS/tests_backend/screen.py @@ -1,3 +1,5 @@ +import pytest + from toga_iOS.libs import UIScreen from .probe import BaseProbe @@ -11,14 +13,5 @@ class ScreenProbe(BaseProbe): self.native = screen._impl.native assert isinstance(self.native, UIScreen) - def assert_name(self): - assert self.screen.name == "iOS Screen" - - def assert_origin(self): - assert self.screen.origin == (0, 0) - - def assert_size(self): - assert self.screen.size == ( - int(self.native.bounds.size.width), - int(self.native.bounds.size.height), - ) + def get_screenshot(self): + pytest.skip("Screen.as_image is not implemented on iOS.") diff --git a/testbed/tests/test_app.py b/testbed/tests/app/test_app.py similarity index 99% rename from testbed/tests/test_app.py rename to testbed/tests/app/test_app.py index 25644ba23..32e40b32c 100644 --- a/testbed/tests/test_app.py +++ b/testbed/tests/app/test_app.py @@ -6,7 +6,7 @@ import toga from toga.colors import CORNFLOWERBLUE, FIREBRICK, REBECCAPURPLE from toga.style.pack import Pack -from .test_window import window_probe +from ..test_window import window_probe @pytest.fixture diff --git a/testbed/tests/app/test_screen.py b/testbed/tests/app/test_screen.py index 35a291b22..42386dff0 100644 --- a/testbed/tests/app/test_screen.py +++ b/testbed/tests/app/test_screen.py @@ -1,4 +1,3 @@ -import os from importlib import import_module import pytest @@ -15,46 +14,39 @@ def screen_probe_list(app): return [getattr(module, "ScreenProbe")(screen) for screen in app.screens] -async def test_name(screen_probe_list): +async def test_name(app): """The name of the screens can be retrieved""" - for screen_probe in screen_probe_list: - assert isinstance(screen_probe.screen.name, str) - screen_probe.assert_name() + for screen in app.screens: + # Just check that it returns a string as the name will be platform specific. + assert isinstance(screen.name, str) -async def test_origin(screen_probe_list): +async def test_origin(app): """The origin of the screens can be retrieved""" - for screen_probe in screen_probe_list: - origin = screen_probe.screen.origin + for screen in app.screens: + origin = screen.origin assert ( isinstance(origin, tuple) and len(origin) == 2 and all(isinstance(val, int) for val in origin) ) - screen_probe.assert_origin() -async def test_size(screen_probe_list): +async def test_size(app): """The size of the screens can be retrieved""" - for screen_probe in screen_probe_list: - size = screen_probe.screen.size + for screen in app.screens: + size = screen.size assert ( isinstance(size, tuple) and len(size) == 2 - and all(isinstance(val, int) for val in size) + # Check that neither the width or height is zero. + and all(isinstance(val, int) and val > 0 for val in size) ) - screen_probe.assert_size() async def test_as_image(screen_probe_list): """A screen can be captured as an image""" for screen_probe in screen_probe_list: - if current_platform in {"android", "iOS", "textual"}: - pytest.xfail("Screen.as_image is not implemented on current platform.") - elif ( - current_platform == "linux" - and os.environ.get("XDG_SESSION_TYPE", "").lower() != "x11" - ): - pytest.xfail("Screen.as_image() is not supported on wayland.") - screenshot = screen_probe.screen.as_image() + # Using a probe for test as feature is not implemented on some platforms. + screenshot = screen_probe.get_screenshot() assert screenshot.size == screen_probe.screen.size diff --git a/testbed/tests/test_window.py b/testbed/tests/test_window.py index 0891e1d8a..284d9bcd9 100644 --- a/testbed/tests/test_window.py +++ b/testbed/tests/test_window.py @@ -152,6 +152,17 @@ if toga.platform.current_platform in {"iOS", "android"}: main_window.full_screen = False await main_window_probe.wait_for_window("Full screen is a no-op") + # Test the `origin`, `position` and `screen_position`. + async def test_screen(main_window, main_window_probe): + """The window can be relocated to another screen, using both absolute and relative screen positions.""" + assert main_window.screen.origin == (0, 0) + initial_size = main_window.size + main_window.position = (150, 50) + await main_window_probe.wait_for_window("Main window can't be moved") + assert main_window.size == initial_size + assert main_window.position == (0, 0) + assert main_window.screen_position == (0, 0) + else: #################################################################################### # Desktop platform tests @@ -479,6 +490,35 @@ else: assert not second_window_probe.is_full_screen assert second_window_probe.content_size == initial_content_size + # Test the `position`, `screen_position` and `screen`. + @pytest.mark.parametrize( + "second_window_kwargs", + [dict(title="Secondary Window", position=(200, 150))], + ) + async def test_screen(second_window, second_window_probe): + """The window can be relocated to another screen, using both absolute and relative screen positions.""" + + initial_position = second_window.position + + # Move the window using absolute position. + second_window.position = (200, 200) + await second_window_probe.wait_for_window("Secondary window has been moved") + assert second_window.position != initial_position + + # `position` and `screen_position` will be same as the window will be in primary screen. + assert second_window.position == (200, 200) + assert second_window.screen_position == (200, 200) + + # Move the window between available screens and assert its `screen_position` + for screen in second_window.app.screens: + second_window.screen = screen + await second_window_probe.wait_for_window("Secondary window has been moved") + assert second_window.screen == screen + assert second_window.screen_position == ( + second_window.position[0] - screen.origin[0], + second_window.position[1] - screen.origin[1], + ) + async def test_as_image(main_window, main_window_probe): """The window can be captured as a screenshot""" @@ -487,21 +527,6 @@ async def test_as_image(main_window, main_window_probe): main_window_probe.assert_image_size(screenshot.size, main_window_probe.content_size) -# Test the `origin`, `position` and `screen_position`. -async def test_screen(main_window, main_window_probe): - """The window can be relocated to another screen, using both absolute and relative screen positions.""" - - if main_window.screen.origin == (0, 0): - if toga.platform.current_platform in {"android", "iOS", "textual"}: - pytest.xfail("Window.position is non functional on current platform.") - initial_position = main_window.position - main_window.position = (200, 200) - assert main_window.position != initial_position - # position and screen_position should be equal on screen with origin (0, 0) - assert main_window.position == (200, 200) - assert main_window.screen_position == (200, 200) - - ######################################################################################## # Dialog tests ######################################################################################## diff --git a/textual/tests_backend/screen.py b/textual/tests_backend/screen.py index b2480eeaa..5951eb515 100644 --- a/textual/tests_backend/screen.py +++ b/textual/tests_backend/screen.py @@ -1,3 +1,5 @@ +import pytest + from textual.screen import Screen as TextualScreen @@ -9,11 +11,5 @@ class ScreenProbe: self.native = screen._impl.native assert isinstance(self.native, TextualScreen) - def assert_name(self): - assert self.screen.name == "Textual Screen" - - def assert_origin(self): - assert self.screen.origin == (0, 0) - - def assert_size(self): - assert self.screen.size == (self.native.size.width, self.native.size.height) + def get_screenshot(self): + pytest.skip("Screen.as_image is not implemented on textual.") diff --git a/winforms/tests_backend/screen.py b/winforms/tests_backend/screen.py index 890d606a2..08d89a6ee 100644 --- a/winforms/tests_backend/screen.py +++ b/winforms/tests_backend/screen.py @@ -11,11 +11,5 @@ class ScreenProbe(BaseProbe): self.native = screen._impl.native assert isinstance(self.native, WinFormsScreen) - def assert_name(self): - assert self.screen.name == self.native.DeviceName - - def assert_origin(self): - assert self.screen.origin == (self.native.Bounds.X, self.native.Bounds.Y) - - def assert_size(self): - assert self.screen.size == (self.native.Bounds.Width, self.native.Bounds.Height) + def get_screenshot(self): + return self.screen.as_image()