Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Arcade [PyPi Release History](https://pypi.org/project/arcade/#history) page.
## Unreleased

### Fixes
- Fixed a window sized with `arcade.get_display_size()` being bigger than the screen with display scaling, such as Windows set to 125% or 150%. Arcade scales windows up by the display scale, but `get_display_size()` returned the screen's size in pixels, so the window was scaled up twice. It now returns the size in window units on Windows and Linux: at 125%, a 1920x1200 screen gives 1536x960, which fills it exactly. On macOS and the web it's unchanged, as they don't scale windows ([#2791](https://github.com/pythonarcade/arcade/issues/2791)).
- Fixed `arcade.future.background.ParallaxGroup` raising `ZeroDivisionError` the first time its offset changed after a layer was given a depth of 0. Setting a depth of 0 now raises a `ValueError` right away, which says to use `float("inf")` for a layer that doesn't scroll ([#1551](https://github.com/pythonarcade/arcade/issues/1551)).
- GUI: Fixed a gap between `UIFlatButton`'s border and the edge of the button, half the border's width, which also showed on `UIDropdown` ([#2868](https://github.com/pythonarcade/arcade/issues/2868)).
- GUI: Passing a single style such as `UIFlatButton.UIStyle()` as a widget's `style` raised a confusing `TypeError` about attribute names. It now raises a `TypeError` saying a dict of styles for each state is needed, and how to start from the widget's `DEFAULT_STYLE` ([#2817](https://github.com/pythonarcade/arcade/issues/2817)).
Expand Down
7 changes: 4 additions & 3 deletions arcade/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from arcade.gl.provider import get_arcade_context, set_provider
from arcade.types import LBWH, Color, Rect, RGBANormalized, RGBOrA255
from arcade.utils import is_raspberry_pi
from arcade.window_commands import get_display_size, set_window
from arcade.window_commands import set_window

if TYPE_CHECKING:
from arcade.camera import Projector
Expand Down Expand Up @@ -534,8 +534,9 @@ def set_fullscreen(

def center_window(self) -> None:
"""Center the window on your desktop."""
# Get the display screen using pyglet
screen_width, screen_height = get_display_size()
# The screen's size in pixels, like the framebuffer's size and the
# location. get_display_size() is in window units instead.
screen_width, screen_height = self.screen.width, self.screen.height

window_width, window_height = self.get_framebuffer_size()
# Center the window
Expand Down
17 changes: 16 additions & 1 deletion arcade/window_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,29 @@ def get_display_size(screen_id: int = 0) -> tuple[int, int]:

The size of the primary monitor is returned by default.

The size is in the same units as a :py:class:`~arcade.Window`'s size, so a
window this size fills the screen. With display scaling, such as Windows set
to 150%, that's smaller than the screen's size in pixels, because Arcade
scales windows up to match.

Args:
screen_id: The screen number
Returns:
Tuple containing the width and height of the screen
"""
display = pyglet.display.Display() # type: ignore # pending: pyglet fixes import tricks
screen = display.get_screens()[screen_id]
return screen.width, screen.height
width, height = screen.width, screen.height
# In stretch mode, pyglet multiplies a window's size by the screen's scale
# on Windows and Linux. Screen sizes on macOS are already in the same units
# as window sizes, and the web doesn't scale windows.
if pyglet.options.dpi_scaling == "stretch" and (
pyglet.compat_platform == "win32" or pyglet.compat_platform.startswith("linux")
):
scale = screen.get_scale()
# Round down, so the scaled window isn't bigger than the screen
width, height = int(width / scale), int(height / scale)
return width, height


def get_window() -> Window:
Expand Down
62 changes: 62 additions & 0 deletions tests/unit/window/test_display_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""get_display_size() is in window units, so a window that size fills the screen (#2791)."""

import pyglet
import pytest

import arcade


class FakeScreen:
def __init__(self, width, height, scale):
self.width = width
self.height = height
self._scale = scale

def get_scale(self):
return self._scale


@pytest.fixture
def fake_screen(monkeypatch):
def use(width, height, scale, dpi_scaling, platform):
screen = FakeScreen(width, height, scale)

class FakeDisplay:
def get_screens(self):
return [screen]

monkeypatch.setattr(pyglet.display, "Display", FakeDisplay)
monkeypatch.setattr(pyglet.options, "dpi_scaling", dpi_scaling)
monkeypatch.setattr(pyglet, "compat_platform", platform)

return use


@pytest.mark.parametrize("platform", ["win32", "linux", "linux-compat"])
@pytest.mark.parametrize(
("width", "height", "scale", "expected"),
[
(1920, 1080, 1.0, (1920, 1080)),
(2560, 1440, 1.25, (2048, 1152)),
(1920, 1080, 1.5, (1280, 720)),
# Rounded down, so the scaled window isn't bigger than the screen
(1366, 768, 1.75, (780, 438)),
],
)
def test_stretch_divides_by_scale(fake_screen, platform, width, height, scale, expected):
fake_screen(width, height, scale, "stretch", platform)
size = arcade.get_display_size()
assert size == expected
assert int(size[0] * scale) <= width
assert int(size[1] * scale) <= height


@pytest.mark.parametrize("platform", ["darwin", "emscripten"])
def test_stretch_on_platforms_that_dont_scale_windows(fake_screen, platform):
fake_screen(1440, 900, 2.0, "stretch", platform)
assert arcade.get_display_size() == (1440, 900)


def test_platform_scaling_returns_the_screen_size(fake_screen):
fake_screen(2560, 1440, 1.25, "platform", "win32")
assert arcade.get_display_size() == (2560, 1440)
Loading