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

Added APIs for detecting multiple displays and setting windows on them. #1930

Merged
merged 138 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from 137 commits
Commits
Show all changes
138 commits
Select commit Hold shift + click to select a range
43dd2fe
Updated codebase to base on the latest main branch.
proneon267 Aug 2, 2023
5ea2021
Added the changelog file.
proneon267 Aug 2, 2023
62407ff
Merge branch 'beeware:main' into patch-11
proneon267 Aug 2, 2023
775ed13
Modified code to align to desired API behaviour.
proneon267 Aug 4, 2023
b54fc35
Modified dummy core code.
proneon267 Aug 5, 2023
f8a3a10
Merge branch 'beeware:main' into patch-11
proneon267 Aug 7, 2023
ba232fd
Modified GTK backend to address reported error.
proneon267 Aug 7, 2023
ea1f820
Merge branch 'beeware:main' into patch-11
proneon267 Aug 8, 2023
1cf9412
Modified cocoa backend to address reported errors.
proneon267 Aug 8, 2023
26f6f1c
Correct cocoa implementation.
freakboy3742 Aug 8, 2023
56aabe1
Modified codebase to address reported issues.
proneon267 Aug 9, 2023
8e219b1
Update examples/window/window/app.py
proneon267 Aug 9, 2023
a18a9d5
Added `screen_position` tests in window example app.
proneon267 Aug 9, 2023
cefe190
Modified DocString
proneon267 Aug 9, 2023
56a915f
Added screen code to web backend.
proneon267 Aug 9, 2023
264a9af
Added screen code to Android backend.
proneon267 Aug 9, 2023
b28a492
Added screen code to ios backend.
proneon267 Aug 9, 2023
aff7fc0
Added screen capture API in core and in winforms.
proneon267 Aug 9, 2023
397e064
Added test of `Screen.as_image()` in WindowExample
proneon267 Aug 9, 2023
b64d361
Update iOS/src/toga_iOS/screen.py
proneon267 Aug 10, 2023
c32a0ce
Modified codebase to address some reported issues.
proneon267 Aug 11, 2023
5f4ef8c
Modified android codebase as per recommendation.
proneon267 Aug 11, 2023
bede871
Resolving file conflict
proneon267 Aug 11, 2023
3a3c82d
Re: Resolving file conflict
proneon267 Aug 11, 2023
221ca6b
Merge branch 'beeware:main' into patch-11
proneon267 Aug 11, 2023
2b453f6
Re: Conflict resolve and updating to main codebase
proneon267 Aug 11, 2023
1725874
Added `as_image()` support for gtk screen backend.
proneon267 Aug 14, 2023
98bb5ef
Added `as_image()` support for cocoa screen.
proneon267 Aug 15, 2023
63af787
Corrected reported gtk `as_image()` behaviour.
proneon267 Aug 17, 2023
6537635
Merge branch 'beeware:main' into patch-11
proneon267 Aug 17, 2023
7508b5c
Corrected example app as per recommendation.
proneon267 Aug 17, 2023
03f55af
Corrected cocoa quartz API importing.
proneon267 Aug 18, 2023
8dd92ab
Merge branch 'beeware:main' into patch-11
proneon267 Aug 18, 2023
4da8cd6
Correct core_graphics usage.
freakboy3742 Aug 21, 2023
7d0ba46
Tweaks to screen aspects of window demo.
freakboy3742 Aug 21, 2023
0f23940
Remove the explicit quartz wrapper.
freakboy3742 Aug 21, 2023
983dd74
Resolving file conflicts
proneon267 Aug 23, 2023
5165069
Merge branch 'beeware:main' into patch-11
proneon267 Aug 23, 2023
8e0aa0c
Re: Resolving file conflict.
proneon267 Aug 23, 2023
5af21b7
Resolving file conflicts.
proneon267 Aug 30, 2023
5a12f3b
Re: Resolving file conflicts
proneon267 Aug 30, 2023
57d9cfb
Re: Resolving file conflicts.
proneon267 Aug 30, 2023
256bd0a
Merge branch 'beeware:main' into patch-11
proneon267 Aug 30, 2023
72384d3
Re: Resolving file conflicts.
proneon267 Aug 30, 2023
7fa7ad8
Merge branch 'patch-11' of https://github.com/proneon267/toga into pa…
proneon267 Aug 30, 2023
32b7ab2
Merge branch 'beeware:main' into patch-11
proneon267 Sep 4, 2023
7f384da
Merge branch 'beeware:main' into patch-11
proneon267 Sep 11, 2023
0c43323
Merge branch 'beeware:main' into patch-11
proneon267 Sep 12, 2023
1e0faa2
Merge branch 'beeware:main' into patch-11
proneon267 Sep 14, 2023
6cf2b2c
Modifying to base on the latest main branch.
proneon267 Oct 14, 2023
3d008f6
Re: Modifying to base on latest main branch.
proneon267 Oct 14, 2023
894bbc5
Merge branch 'beeware:main' into patch-11
proneon267 Oct 14, 2023
1cefcc0
Re: Modifying to base on latest main branch.
proneon267 Oct 14, 2023
072aed4
Merge branch 'patch-11' of https://github.com/proneon267/toga into pa…
proneon267 Oct 14, 2023
6414d2f
Merge branch 'main' into patch-11
proneon267 Oct 18, 2023
c98d979
Merge branch 'beeware:main' into patch-11
proneon267 Oct 21, 2023
2aa85ff
Merge branch 'beeware:main' into patch-11
proneon267 Oct 23, 2023
9481573
Merge branch 'main' into patch-11
proneon267 Nov 1, 2023
dea6d77
Merge Fixes
proneon267 Nov 1, 2023
8e42170
Merge branch 'main' into patch-11
proneon267 Nov 9, 2023
84b1bfd
Updating to latest main branch
proneon267 Nov 9, 2023
68edb63
Merge branch 'beeware:main' into patch-11
proneon267 Nov 15, 2023
f7072a9
Merge branch 'main' into patch-11
proneon267 Dec 2, 2023
617d5cd
Merge branch 'beeware:main' into patch-11
proneon267 Dec 10, 2023
0085849
Merge branch 'beeware:main' into patch-11
proneon267 Dec 17, 2023
c1d10c5
Merge branch 'beeware:main' into patch-11
proneon267 Dec 19, 2023
826b381
Merge branch 'beeware:main' into patch-11
proneon267 Dec 22, 2023
d01ffeb
Merge branch 'beeware:main' into patch-11
proneon267 Jan 13, 2024
333f282
Modified dummy backend
proneon267 Jan 14, 2024
ddbe033
Added some tests
proneon267 Jan 14, 2024
de331cd
Merge branch 'beeware:main' into patch-11
proneon267 Jan 14, 2024
7e3d29a
Merge branch 'beeware:main' into patch-11
proneon267 Jan 15, 2024
ae66c37
Added some tests
proneon267 Jan 15, 2024
dc67e97
Modified some tests
proneon267 Jan 15, 2024
3259573
Modified some tests
proneon267 Jan 15, 2024
b9b448e
Added tests for other platforms.
proneon267 Jan 15, 2024
045404a
Modified some tests
proneon267 Jan 17, 2024
8634eea
Fixed tests
proneon267 Jan 17, 2024
175a5c0
Corrected tests
proneon267 Jan 17, 2024
0d01153
Fixed tests
proneon267 Jan 17, 2024
efe2b69
Added tests for core
proneon267 Jan 17, 2024
6a6ad00
Merge branch 'beeware:main' into patch-11
proneon267 Jan 17, 2024
3fb01b2
Fixed core tests
proneon267 Jan 19, 2024
133048e
Fixed Tests
proneon267 Jan 20, 2024
7e5bf6d
Merge branch 'beeware:main' into patch-11
proneon267 Jan 20, 2024
4247276
Fixed `as_image()` and `toga.Image` on cocoa
proneon267 Jan 21, 2024
94f368e
Added implementation and tests for `textual`
proneon267 Jan 21, 2024
1cf64f3
Fixed textual tests
proneon267 Jan 21, 2024
6fd9fa8
Added an explanatory comment
proneon267 Jan 21, 2024
1aa4b13
Added an explanatory comment
proneon267 Jan 21, 2024
a1b626e
Added explanatory comments to tests
proneon267 Jan 21, 2024
d5d1572
Miscellaneous fixes
proneon267 Jan 21, 2024
1b8a52d
Corrected tests
proneon267 Jan 21, 2024
1b89c95
Removed type annotations and other fixes
proneon267 Jan 25, 2024
ba35e2a
Merge branch 'beeware:main' into patch-11
proneon267 Jan 25, 2024
d015c2c
Empty commit for CI
proneon267 Jan 25, 2024
f0b242f
Merge branch 'main' into patch-11
proneon267 Jan 31, 2024
6406d57
Update cocoa/src/toga_cocoa/screen.py
proneon267 Jan 31, 2024
eb84c07
Update core/tests/test_window.py
proneon267 Jan 31, 2024
6747b3b
Update testbed/tests/test_app.py
proneon267 Jan 31, 2024
2d00224
Fixed tests as per recommendation
proneon267 Jan 31, 2024
00af21b
Miscellaneous Fix
proneon267 Jan 31, 2024
c460833
Update changes/1930.feature.rst
proneon267 Feb 1, 2024
d2a266d
Misc commit
proneon267 Feb 1, 2024
2361fdf
Misc commit
proneon267 Feb 1, 2024
4ed3ed3
Empty commit for CI
proneon267 Feb 1, 2024
be8fa67
Various fixes
proneon267 Feb 1, 2024
bab0a43
Merge branch 'patch-11' of https://github.com/proneon267/toga into pa…
proneon267 Feb 1, 2024
c78d2d4
Added s_image() implementation for Android
proneon267 Feb 1, 2024
1867bbe
Added s_image() implementation for iOS
proneon267 Feb 1, 2024
616e2e2
Fixed iOS implementation
proneon267 Feb 1, 2024
a2a72d2
Fixed iOS implementation
proneon267 Feb 1, 2024
5cea9af
Minor cleanups and renames.
freakboy3742 Feb 2, 2024
858a9da
Add docs for Screen class.
freakboy3742 Feb 2, 2024
95c28cf
Use probe mechanism for inspecting image size.
freakboy3742 Feb 2, 2024
d69488f
Merge branch 'main' into patch-11
freakboy3742 Feb 2, 2024
b320ba9
Fixed tests
proneon267 Feb 3, 2024
f16ba4f
Fixed cocoa implementation
proneon267 Feb 3, 2024
04e0e63
Fixed cocoa implementation
proneon267 Feb 4, 2024
8847d4e
Empty commit for CI
proneon267 Feb 4, 2024
52cd9d2
Fixed cocoa implementation
proneon267 Feb 4, 2024
9aaeddd
Misc Fixes
proneon267 Feb 4, 2024
1537b95
Minor cleanups making screen non-optional.
freakboy3742 Feb 4, 2024
1012549
Misc Fix
proneon267 Feb 8, 2024
e24462d
Tweak CoreGraphics usage.
freakboy3742 Feb 8, 2024
209457e
Fixed `canvas.as_image()`
proneon267 Feb 9, 2024
e10ca33
Corrected cocoa as_image() implementations
proneon267 Feb 9, 2024
f2c0bf7
Merge branch 'beeware:main' into patch-11
proneon267 Feb 9, 2024
d12c7fa
Misc Fix
proneon267 Feb 9, 2024
b2a47a1
Misc Fix
proneon267 Feb 9, 2024
b15eb9f
Clarified macOS core_graphics declarations.
freakboy3742 Feb 11, 2024
656efb5
Removed image size debugging.
freakboy3742 Feb 11, 2024
4d36cd6
Add backwards compatibility note about macOS image capture changes.
freakboy3742 Feb 11, 2024
5eecd21
Tweak docstrings for position.
freakboy3742 Feb 11, 2024
35f0847
Clean up test docstrings.
freakboy3742 Feb 11, 2024
777f272
Ensure textual backend does scaling on screen sizes.
freakboy3742 Feb 11, 2024
16b33ae
Simplify android scaling calculation.
freakboy3742 Feb 11, 2024
b025d21
Corrected windows screen name
proneon267 Feb 11, 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
8 changes: 8 additions & 0 deletions android/src/toga_android/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import sys
import warnings

from android.content import Context
from android.graphics.drawable import BitmapDrawable
from android.media import RingtoneManager
from android.view import Menu, MenuItem
Expand All @@ -11,6 +12,7 @@
from toga.command import Command, Group, Separator

from .libs import events
from .screens import Screen as ScreenImpl
from .window import Window


Expand Down Expand Up @@ -325,3 +327,9 @@ def hide_cursor(self):

def show_cursor(self):
pass

def get_screens(self):
context = self.native.getApplicationContext()
display_manager = context.getSystemService(Context.DISPLAY_SERVICE)
screen_list = display_manager.getDisplays()
return [ScreenImpl(self, screen) for screen in screen_list]
48 changes: 48 additions & 0 deletions android/src/toga_android/screens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from android.graphics import (
Bitmap,
Canvas as A_Canvas,
)

from toga.screens import Screen as ScreenInterface

from .widgets.base import Scalable


class Screen(Scalable):
_instances = {}

def __new__(cls, app, native):
if native in cls._instances:
return cls._instances[native]
else:
instance = super().__new__(cls)
instance.interface = ScreenInterface(_impl=instance)
instance.native = native
cls._instances[native] = instance
cls.app = app
instance.init_scale(instance.app.native)
return instance

def get_name(self):
return self.native.getName()

def get_origin(self):
return (0, 0)

def get_size(self):
return (
self.scale_out(self.native.getWidth()),
self.scale_out(self.native.getHeight()),
)

def get_image_data(self):
# Get the root view of the current activity
root_view = self.app.native.getWindow().getDecorView().getRootView()
bitmap = Bitmap.createBitmap(
*map(self.scale_in, self.get_size()),
Bitmap.Config.ARGB_8888,
)
canvas = A_Canvas(bitmap)
root_view.draw(canvas)

return bitmap
7 changes: 7 additions & 0 deletions android/src/toga_android/window.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from decimal import ROUND_UP

from android import R
from android.content import Context
from android.graphics import (
Bitmap,
Canvas as A_Canvas,
Expand All @@ -10,6 +11,7 @@
from java.io import ByteArrayOutputStream

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


class LayoutListener(dynamic_proxy(ViewTreeObserver.OnGlobalLayoutListener)):
Expand Down Expand Up @@ -103,6 +105,11 @@ def close(self):
def set_full_screen(self, is_full_screen):
self.interface.factory.not_implemented("Window.set_full_screen()")

def get_current_screen(self):
context = self.app.native.getApplicationContext()
window_manager = context.getSystemService(Context.WINDOW_SERVICE)
return ScreenImpl(self.app, window_manager.getDefaultDisplay())

def get_image_data(self):
bitmap = Bitmap.createBitmap(
self.native_content.getWidth(),
Expand Down
2 changes: 1 addition & 1 deletion android/tests_backend/probe.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ async def redraw(self, message=None, delay=0):
print("Waiting for redraw" if message is None else message)
await asyncio.sleep(delay)

def assert_image_size(self, image_size, size):
def assert_image_size(self, image_size, size, screen):
# Sizes are approximate because of scaling inconsistencies.
assert image_size == (
approx(size[0] * self.scale_factor, abs=2),
Expand Down
21 changes: 21 additions & 0 deletions android/tests_backend/screens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from android.view import Display

import toga
from toga.images import Image as TogaImage
from toga_android.widgets.base import Scalable

from .probe import BaseProbe


class ScreenProbe(BaseProbe, Scalable):
def __init__(self, screen):
app = toga.App.app
super().__init__(app)
self.screen = screen
self._impl = screen._impl
self.native = screen._impl.native
self.init_scale(app._impl.native)
assert isinstance(self.native, Display)

def get_screenshot(self, format=TogaImage):
return self.screen.as_image(format=format)
1 change: 1 addition & 0 deletions changes/1930.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Toga apps can now access details about the screens attached to the computer. Window position APIs have been extended to allow for placement on a specific screen, and positioning relative to a specific screen.
1 change: 1 addition & 0 deletions changes/1930.removal.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The macOS implementations of ``Window.as_image()`` and ``Canvas.as_image()`` APIs now return images in native device resolution, not CSS pixel resolution. This will result in images that are double the previous size on Retina displays.
4 changes: 4 additions & 0 deletions cocoa/src/toga_cocoa/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
objc_method,
objc_property,
)
from .screens import Screen as ScreenImpl
from .window import Window


Expand Down Expand Up @@ -402,6 +403,9 @@ def _submenu(self, group, menubar):
def main_loop(self):
self.loop.run_forever(lifecycle=CocoaLifecycle(self.native))

def get_screens(self):
return [ScreenImpl(native=screen) for screen in NSScreen.screens]

def set_main_window(self, window):
pass

Expand Down
23 changes: 23 additions & 0 deletions cocoa/src/toga_cocoa/libs/core_graphics.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,16 @@ class CGEventRef(c_void_p):

######################################################################
# CGImage.h

CGImageRef = c_void_p
register_preferred_encoding(b"^{CGImage=}", CGImageRef)

core_graphics.CGImageGetWidth.argtypes = [CGImageRef]
core_graphics.CGImageGetWidth.restype = c_size_t

core_graphics.CGImageGetHeight.argtypes = [CGImageRef]
core_graphics.CGImageGetHeight.restype = c_size_t

kCGImageAlphaNone = 0
kCGImageAlphaPremultipliedLast = 1
kCGImageAlphaPremultipliedFirst = 2
Expand All @@ -220,3 +230,16 @@ class CGEventRef(c_void_p):
kCGBitmapByteOrder32Little = 2 << 12
kCGBitmapByteOrder16Big = 3 << 12
kCGBitmapByteOrder32Big = 4 << 12

######################################################################
# CGDirectDisplay.h

CGDirectDisplayID = c_uint32

# CGDirectDisplayID CGMainDisplayID(void);
core_graphics.CGMainDisplayID.restype = CGDirectDisplayID
core_graphics.CGMainDisplayID.argtypes = None

# CGImageRef CGDisplayCreateImage(CGDirectDisplayID displayID, CGRect rect);
core_graphics.CGDisplayCreateImage.restype = CGImageRef
core_graphics.CGDisplayCreateImage.argtypes = [CGDirectDisplayID, CGRect]
53 changes: 53 additions & 0 deletions cocoa/src/toga_cocoa/screens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from rubicon.objc import CGSize

from toga.screens import Screen as ScreenInterface
from toga_cocoa.libs import (
NSImage,
core_graphics,
)


class Screen:
_instances = {}

def __new__(cls, native):
if native in cls._instances:
return cls._instances[native]
else:
instance = super().__new__(cls)
instance.interface = ScreenInterface(_impl=instance)
instance.native = native
cls._instances[native] = instance
return instance

def get_name(self):
return str(self.native.localizedName)

def get_origin(self):
frame_native = self.native.frame
return (int(frame_native.origin.x), int(frame_native.origin.y))

def get_size(self):
frame_native = self.native.frame
return (int(frame_native.size.width), int(frame_native.size.height))

def get_image_data(self):
# Retrieve the device description dictionary for the NSScreen
device_description = self.native.deviceDescription
# Extract the CGDirectDisplayID from the device description
cg_direct_display_id = device_description.objectForKey_(
"NSScreenNumber"
).unsignedIntValue

cg_image = core_graphics.CGDisplayCreateImage(
cg_direct_display_id,
self.native.frame,
)
# Get the size of the CGImage
target_size = CGSize(
core_graphics.CGImageGetWidth(cg_image),
core_graphics.CGImageGetHeight(cg_image),
)
# Create an NSImage from the CGImage
ns_image = NSImage.alloc().initWithCGImage(cg_image, size=target_size)
return ns_image
20 changes: 11 additions & 9 deletions cocoa/src/toga_cocoa/widgets/canvas.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
from math import ceil

from rubicon.objc import objc_method, objc_property
from rubicon.objc import CGSize, objc_method, objc_property
from travertino.size import at_least

from toga.colors import BLACK, TRANSPARENT, color
from toga.widgets.canvas import Baseline, FillRule
from toga_cocoa.colors import native_color
from toga_cocoa.images import nsdata_to_bytes
from toga_cocoa.libs import (
CGFloat,
CGPathDrawingMode,
CGRectMake,
NSAttributedString,
NSBitmapImageFileType,
NSFontAttributeName,
NSForegroundColorAttributeName,
NSGraphicsContext,
NSImage,
NSMutableDictionary,
NSPoint,
NSRect,
Expand Down Expand Up @@ -321,16 +320,19 @@ def write_text(self, text, x, y, font, baseline, **kwargs):
)

def get_image_data(self):

bitmap = self.native.bitmapImageRepForCachingDisplayInRect(self.native.bounds)
bitmap.setSize(self.native.bounds.size)
self.native.cacheDisplayInRect(self.native.bounds, toBitmapImageRep=bitmap)

return nsdata_to_bytes(
bitmap.representationUsingType(
NSBitmapImageFileType.PNG,
properties=None,
)
# Get a reference to the CGImage from the bitmap
cg_image = bitmap.CGImage

target_size = CGSize(
core_graphics.CGImageGetWidth(cg_image),
core_graphics.CGImageGetHeight(cg_image),
)
ns_image = NSImage.alloc().initWithCGImage(cg_image, size=target_size)
return ns_image

# Rehint
def rehint(self):
Expand Down
25 changes: 18 additions & 7 deletions cocoa/src/toga_cocoa/window.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from rubicon.objc import CGSize

from toga.command import Command, Separator
from toga_cocoa.container import Container
from toga_cocoa.images import nsdata_to_bytes
from toga_cocoa.libs import (
SEL,
NSBackingStoreBuffered,
NSBitmapImageFileType,
NSImage,
NSMakeRect,
NSMutableArray,
NSPoint,
Expand All @@ -14,10 +15,13 @@
NSToolbarItem,
NSWindow,
NSWindowStyleMask,
core_graphics,
objc_method,
objc_property,
)

from .screens import Screen as ScreenImpl


def toolbar_identifier(cmd):
return f"Toolbar-{type(cmd).__name__}-{id(cmd)}"
Expand Down Expand Up @@ -305,16 +309,23 @@ def cocoa_windowShouldClose(self):
def close(self):
self.native.close()

def get_current_screen(self):
return ScreenImpl(self.native.screen)

def get_image_data(self):
bitmap = self.container.native.bitmapImageRepForCachingDisplayInRect(
self.container.native.bounds
)
bitmap.setSize(self.container.native.bounds.size)
self.container.native.cacheDisplayInRect(
self.container.native.bounds, toBitmapImageRep=bitmap
)
data = bitmap.representationUsingType(
NSBitmapImageFileType.PNG,
properties=None,

# Get a reference to the CGImage from the bitmap
cg_image = bitmap.CGImage

target_size = CGSize(
core_graphics.CGImageGetWidth(cg_image),
core_graphics.CGImageGetHeight(cg_image),
)
return nsdata_to_bytes(data)
ns_image = NSImage.alloc().initWithCGImage(cg_image, size=target_size)
return ns_image
11 changes: 6 additions & 5 deletions cocoa/tests_backend/probe.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from rubicon.objc import SEL, NSArray, NSObject, ObjCClass, objc_method
from rubicon.objc.api import NSString

import toga
from toga_cocoa.libs.appkit import appkit

NSRunLoop = ObjCClass("NSRunLoop")
Expand Down Expand Up @@ -48,7 +49,7 @@ async def post_event(self, event, delay=None):

async def redraw(self, message=None, delay=None):
"""Request a redraw of the app, waiting until that redraw has completed."""
if self.app.run_slow:
if toga.App.app.run_slow:
# If we're running slow, wait for a second
print("Waiting for redraw" if message is None else message)
delay = 1
Expand All @@ -60,7 +61,7 @@ async def redraw(self, message=None, delay=None):
# for at least one iteration. `runUntilDate:None` does this.
NSRunLoop.currentRunLoop.runUntilDate(None)

def assert_image_size(self, image_size, size):
# Cocoa reports image sizing in the natural screen coordinates, not the size of
# the backing store.
assert image_size == size
def assert_image_size(self, image_size, size, screen):
# Screenshots are captured in native device resolution, not in CSS pixels.
scale = int(screen._impl.native.backingScaleFactor)
assert image_size == (size[0] * scale, size[1] * scale)
16 changes: 16 additions & 0 deletions cocoa/tests_backend/screens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from toga.images import Image as TogaImage
from toga_cocoa.libs import NSScreen

from .probe import BaseProbe


class ScreenProbe(BaseProbe):
def __init__(self, screen):
super().__init__()
self.screen = screen
self._impl = screen._impl
self.native = screen._impl.native
assert isinstance(self.native, NSScreen)

def get_screenshot(self, format=TogaImage):
return self.screen.as_image(format=format)
Loading