Skip to content

Add pygame.display.get_desktop_usable_bounds#3530

Open
damusss wants to merge 10 commits intopygame-community:mainfrom
damusss:display-usable-bounds
Open

Add pygame.display.get_desktop_usable_bounds#3530
damusss wants to merge 10 commits intopygame-community:mainfrom
damusss:display-usable-bounds

Conversation

@damusss
Copy link
Member

@damusss damusss commented Jul 13, 2025

As I said on discord, pygame.display.get_desktop_sizes exist but doesn't take in consideration the taskbar or any other OS reserved space. The SDL function for it exists, so it makes sense to me to add it to display. It would be very tedious to do this in python cross platform without it. It's a differnt function from the sizes because it returns rects, but the return list uses the same logic so with the same index you get the full size and usable area for the same desktop. Also, it's alredy SDL3 compatible, so there will be no problems when display is ported. There is no conflict with window because this is one of the features that make sense for display, and doesn't concert any windows (display should only hold this functions)

@damusss damusss requested a review from a team as a code owner July 13, 2025 07:49
@damusss damusss added New API This pull request may need extra debate as it adds a new class or function to pygame display pygame.display labels Jul 13, 2025
@ankith26
Copy link
Member

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 13, 2025

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 13, 2025

📝 Walkthrough

Walkthrough

Adds pygame.display.get_desktop_usable_bounds(), a new C-implemented function that returns a list of pygame.Rect representing usable desktop areas (excluding OS-occupied regions) per virtual desktop; updates stub typing, adds a docs macro, and includes a unit test validating types and size constraints.

Changes

Cohort / File(s) Summary
Stub typings
buildconfig/stubs/pygame/display.pyi
Declares get_desktop_usable_bounds() -> list[Rect], imports Rect from pygame.rect, and documents the new API (versionadded 2.5.6).
C display module
src_c/display.c
Adds pg_get_desktop_usable_bounds (exposed as get_desktop_usable_bounds) which queries SDL (SDL3 or pre‑SDL3) for per‑display usable bounds, converts each to Rect objects, returns list[Rect], and registers the method with DOC_DISPLAY_GETDESKTOPUSABLEBOUNDS.
Docs macro
src_c/doc/display_doc.h
Adds DOC_DISPLAY_GETDESKTOPUSABLEBOUNDS documenting the function signature and purpose.
Tests
test/display_test.py
Adds test_get_desktop_usable_bounds asserting the function returns a list of pygame.Rect, that its length corresponds to get_desktop_sizes(), and each rect’s width/height do not exceed corresponding desktop sizes.

Sequence Diagram(s)

sequenceDiagram
    participant Py as Python caller
    participant Display as pygame.display
    participant C as pg_get_desktop_usable_bounds (C)
    participant SDL as SDL Video API

    Py->>Display: get_desktop_usable_bounds()
    Display->>C: call (no args)
    alt SDL3
        C->>SDL: SDL_GetDisplays()\nSDL_GetDisplayUsableBounds(display)
    else pre-SDL3
        C->>SDL: SDL_GetNumVideoDisplays()\nSDL_GetDisplayUsableBounds(index)
    end
    SDL-->>C: usable bounds per display
    C-->>Display: list[Rect]
    Display-->>Py: list[Rect]
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title directly and concisely describes the main change: adding a new pygame.display function called get_desktop_usable_bounds.
Description check ✅ Passed The PR description clearly explains the purpose, implementation details, and rationale for the new function, relating directly to the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
test/display_test.py (1)

700-709: Avoid potential IndexError and assert list alignment

If, for any reason, the two lists differ in length, this loop will raise IndexError. Assert the lengths match and iterate with zip to keep the test robust.

Apply this diff:

 def test_get_desktop_usable_bounds(self):
     bounds = pygame.display.get_desktop_usable_bounds()
     sizes = pygame.display.get_desktop_sizes()
     self.assertIsInstance(bounds, list)
-    for i, bound in enumerate(bounds):
-        self.assertIsInstance(bound, pygame.Rect)
-        size = sizes[i]
-        self.assertLessEqual(bound.w, size[0])
-        self.assertLessEqual(bound.h, size[1])
+    self.assertEqual(len(bounds), len(sizes))
+    for bound, size in zip(bounds, sizes):
+        self.assertIsInstance(bound, pygame.Rect)
+        self.assertLessEqual(bound.w, size[0])
+        self.assertLessEqual(bound.h, size[1])
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6db5c7 and f1f8177.

📒 Files selected for processing (4)
  • buildconfig/stubs/pygame/display.pyi (2 hunks)
  • src_c/display.c (2 hunks)
  • src_c/doc/display_doc.h (1 hunks)
  • test/display_test.py (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
test/display_test.py (2)
buildconfig/stubs/pygame/display.pyi (2)
  • get_desktop_usable_bounds (425-441)
  • get_desktop_sizes (406-423)
buildconfig/stubs/pygame/rect.pyi (1)
  • Rect (303-303)
buildconfig/stubs/pygame/display.pyi (4)
buildconfig/stubs/pygame/typing.pyi (1)
  • rect (57-57)
src_py/typing.py (1)
  • rect (57-57)
buildconfig/stubs/typing_sample_app.py (1)
  • rect (100-101)
buildconfig/stubs/pygame/rect.pyi (1)
  • Rect (303-303)
🔇 Additional comments (4)
src_c/doc/display_doc.h (1)

14-14: Doc macro addition LGTM

The new macro name and summary align with existing patterns and the API behavior.

buildconfig/stubs/pygame/display.pyi (2)

425-442: Stub signature and docstring LGTM

Return type list[Rect] matches runtime objects. The docstring mirrors the new API semantics and version tag is present.


55-55: No Union usage detected – import removal is safe

  • buildconfig/stubs/pygame/display.pyi: scanned for “Union” with ripgrep; no occurrences found.
src_c/display.c (1)

3179-3181: Method registration LGTM

Correctly registered with METH_NOARGS and linked to the doc macro.

@robertpfeiffer
Copy link
Contributor

This could be used to implement "Do what I mean" window sizing when passing in (0,0) for windowed mode. I always hated how windowed mode overlaps with the task bar in that case!

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
Member

@MyreMylar MyreMylar left a comment

Choose a reason for hiding this comment

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

OK, LGTM 👍 Seems like it could be useful for application positioning especially with things like no frame windows.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
test/display_test.py (1)

700-710: LGTM! Consider optional enhancements for more comprehensive coverage.

The test correctly validates the return type, length consistency with get_desktop_sizes(), and basic dimension constraints.

For enhanced test coverage, you may optionally consider:

  • Validating that bounds have non-negative coordinates (x, y >= 0)
  • Checking that bounds have positive dimensions (w > 0, h > 0)
  • Verifying bounds are positioned within desktop boundaries (x+w <= size[0], y+h <= size[1])

Example enhancement:

     def test_get_desktop_usable_bounds(self):
         bounds = pygame.display.get_desktop_usable_bounds()
         sizes = pygame.display.get_desktop_sizes()
         self.assertIsInstance(bounds, list)
         self.assertEqual(len(bounds), len(sizes))
         for i, bound in enumerate(bounds):
             self.assertIsInstance(bound, pygame.Rect)
             size = sizes[i]
             self.assertLessEqual(bound.w, size[0])
             self.assertLessEqual(bound.h, size[1])
+            # Optional: validate coordinates and dimensions
+            self.assertGreaterEqual(bound.x, 0)
+            self.assertGreaterEqual(bound.y, 0)
+            self.assertGreater(bound.w, 0)
+            self.assertGreater(bound.h, 0)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0cc2c49 and 4831155.

📒 Files selected for processing (1)
  • test/display_test.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
test/display_test.py (2)
buildconfig/stubs/pygame/display.pyi (2)
  • get_desktop_usable_bounds (425-441)
  • get_desktop_sizes (406-423)
buildconfig/stubs/pygame/rect.pyi (1)
  • Rect (303-303)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: AMD64
  • GitHub Check: x86
  • GitHub Check: aarch64
  • GitHub Check: x86_64
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.9.23)
  • GitHub Check: i686
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.14.0rc1)
  • GitHub Check: debug_coverage (ubuntu-24.04, 3.13.5)
  • GitHub Check: Debian (Bookworm - 12) [ppc64le]
  • GitHub Check: msys2 (clang64, clang-x86_64)
  • GitHub Check: Debian (Bookworm - 12) [armv7]
  • GitHub Check: msys2 (ucrt64, ucrt-x86_64)
  • GitHub Check: Debian (Bookworm - 12) [armv6]
  • GitHub Check: Debian (Bookworm - 12) [s390x]
  • GitHub Check: build (windows-latest)
  • GitHub Check: msys2 (mingw64, x86_64)
  • GitHub Check: build (ubuntu-24.04)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-22.04)
  • GitHub Check: dev-check

@damusss
Copy link
Member Author

damusss commented Oct 1, 2025

This could be used to implement "Do what I mean" window sizing when passing in (0,0) for windowed mode. I always hated how windowed mode overlaps with the task bar in that case!

Yeah I agree, useful to manually maximize a window with it being aware of the taskbar or other things occupying space.

Also thanks myre for pushing the memory fixes, have been out of the contributing loop during summer (github even signed me out...)

@damusss damusss requested a review from a team October 8, 2025 07:13
Copy link
Member

@ankith26 ankith26 left a comment

Choose a reason for hiding this comment

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

left a few minor reviews

@Matiiss
Copy link
Member

Matiiss commented Feb 17, 2026

This is more so coming from @Starbuck5, but pretend it's not so... or don't... anyway

Here's the idea, pygame.Monitor or pygame.Display (would work better with SDL names), a class and it would have attributes like .usable_bounds (at least for the purposes of this PR, so as to not have to implement all of the potential attributes that could go with such a class (and there are many))

So the API would look more like this (if, for example, you wanted a list of usable bounds)

displays = pygame.display.get_displays()
desktop_usable_bounds = [d.usable_bounds for d in displays]

.usable_bounds in this case would simply be a property getter for the Display class

What all of this means for this PR:

  • Create a Display type (full qualified name would likely be pygame.display.Display)
  • Add .id property to said type (for SDL2 purposes it could be something like 0 (which in SDL 3 is considered an invalid ID btw, but anyway, maybe keep a counter and increment it to ensure uniqueness or something)
  • Add .usable_bounds property to said type that will basically query the SDL APIs you are already querying in this PR right now (to get those bounds)
  • Add pygame.display.get_displays() with return type list[pygame.Display] (that also actually returns a list of pygame.Displays)

These are required changes by the way 😁

@damusss
Copy link
Member Author

damusss commented Feb 18, 2026

@Matiiss so you think the backbone of the API should be implemented in this specific pull request?
(has starbuck ever talked about this?)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

display pygame.display New API This pull request may need extra debate as it adds a new class or function to pygame

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add pygame.display.get_desktop_workarea() to retrieve usable display bounds (excluding taskbar / Dock)

5 participants