Skip to content

x11: report the monitor as the screen frame and the work area beside it - #217

Open
probonopd wants to merge 8 commits into
gnustep:masterfrom
probonopd:fix/screen-frame-not-workarea
Open

probonopd wants to merge 8 commits into
gnustep:masterfrom
probonopd:fix/screen-frame-not-workarea

Conversation

@probonopd

@probonopd probonopd commented Aug 2, 2026 •

Copy link
Copy Markdown
Contributor

Reworked along the lines agreed above, as the backend half of the pair, and rebased on top of #226 so that its flip of the _NET_WORKAREA origin and its count of monitors rather than outputs are not repeated here. The commits of #226 are part of this branch until it is merged; what this PR adds on top of them is one commit.

The frame of a screen was replaced by _NET_WORKAREA whenever there was a single monitor, so NSScreen described what the window manager leaves over rather than the display. An application could not learn the geometry of the monitor, and one that reserves space itself, a menu bar or a dock, could not place itself in the strip it had just reserved, since that strip lies outside every frame it can see.

The frame is the monitor again, the work area is kept beside it, and -workAreaForScreen: answers it. The headless, wayland and win32 servers answer their whole screen, which is what they reserve nothing of.

Measured on an 800x600 screen with a 22 pixel menu bar at the top and a dock at the bottom, _NET_WORKAREA = 0, 22, 800, 450:

                             #226 alone        #226 + this branch
NSScreen -frame              0 128 800 450     0 0 800 600
-workAreaForScreen: 0        (no such method)  0 128 800 450

With the gui half, gnustep/libs-gui#953, on top of each of them:

-[NSScreen visibleFrame]     0 128 800 428     0 128 800 450

The 428 on the left is the menu bar counted twice: the work area already excludes the strip the menu bar reserved, and -visibleFrame subtracts its height again. #953 takes off only as much of the menu bar as the work area has not already been reduced by, which is the "a reservation must only be accounted for once" point from the discussion above.

I could not run Tests/x11 on this machine: it wants libXmu, which is not installed here, and eleven of its tools fail to link for that reason before any of them runs. The backend itself builds clean, and the change on top of #226 is confined to -screenList and the new method.

cc @rfm @fredkiefer @DTW-Thalion @pkgdemon

@probonopd
probonopd requested a review from fredkiefer as a code owner August 2, 2026 20:03
@fredkiefer
fredkiefer requested a review from rfm August 2, 2026 20:19
@fredkiefer

Copy link
Copy Markdown
Member

@rfm added this code few months ago, so he should have the say on whether we drop this again. Either way is fine with me.

@rfm

rfm commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

As I recall, the current code was written to make the tops of menus available so allow them to be moved and the first menu item selected reliably, and achieved that objective. Before the last lot of changes, the top part of our menus would be hidden behind the top bar controlled by many window managers. However, it's hardly surprising if there are bugs: it was a quick/simple fix.

The problem I have here is with this sentence:

A screen frame in the AppKit/OpenStep model is the whole display; the usable area left after panels
and struts is a separate concept applications query on their own.

The current model is precisely because my understanding was that an OpenStep/AppKit display is the usable display, because apps expect to be able to draw anywhere on screen, and that when OpenStep was designed for display postscript, there were no window managers, no struts, and no difference between the physical screen and the usable screen.

I'm happy to be educated otherwise, but what are the AppKit/gnustep-gui methods used by apps to to query panels and struts, and where can I see examples of Apple and GNUstep app source using those methods to position windows/menus?

@probonopd

Copy link
Copy Markdown
Contributor Author

Hi @rfm, thanks for your quick response. Obviously my experience with GNUstep is not as deep as yours, but here are my thoughts:

AppKit distinguishes between the physical display (NSScreen.frame) and the usable display area (NSScreen.visibleFrame). Both Apple and GNUstep implement this - GNUstep's visibleFrame is in NSScreen.m and subtracts the menu-bar height for the relevant interface style. So the "panels and struts" concept does have a dedicated query path (visibleFrame); frame is explicitly the full screen.

I agree the current work-area code was a reasonable quick fix to keep menus reachable below the WM's top bar. My concern is narrower: it is internally inconsistent. The screen frame (monitors[].frame, what NSScreen reports) is set from _NET_WORKAREA, but the Y-flip when placing windows (_OSFrameToXFrame) converts against xScreenSize.height, the full screen height. When those differ, every window positioned at the top of the (NSScreen) coordinate space is shifted down by the difference - which is why a full-width top bar requested at y = 0 lands below the upper border.

That inconsistency bites either way:

  • With the current code, an app that wants to sit at the true top of the display (a menu bar / panel) cannot reach y = 0 at all; it is pushed down by fullScreen - workArea.
  • With the frame set to the full output (this patch), the coordinate spaces agree, and apps that want to avoid the WM's reserved area use visibleFrame / the workarea themselves - which is the AppKit model.

I'd suggest we fix the consistency (whichever direction) rather than leave the flip and the frame disagreeing. The alternative direction (keep the work-area frame but flip against the same height) has the same side effect of moving top-positioned windows, while keeping NSScreen.frame != the whole display, which diverges from the documented frame/visibleFrame contract.

For the Gershwin Menu.app this matters because it is a full-width top bar that deliberately wants the very top edge; with the work-area frame it could only ever reach fullScreen - workArea pixels down. I'm happy to adjust the patch if you'd rather go another way, e.g. keep the work-area frame and make the Y-flip consistent. Just let me know your preference.

@rfm

rfm commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

I wouldn't claim to be deeply experienced with the gui/backend as I don't write gui apps and hardly ever touch it, and I don't actually know why I'm not seeing any issues if _OSFrameToXFrame if getting things wrong, but I'm perfectly prepared to accept there is a bug there.

I also don't understand why you want to draw at the top of the physical screen when the window manager is going to ensure that its own topbar, another window outside of GNUstep control, will hide anything you draw.

My understanding is that there are at least three areas to consider:
The physical display size
The usable display size (a GNUstep app can't display anything in a region where the WM puts its windows behind other windows) that GNUstep wants to draw its main menu (and perhaps a dock) into
The 'visibleRect' that an app will want to position its windows in, in order to avoid them being hidden by menu/dock.

Now, what I did with _NET_WORKAREA was to try to conflate the physical area with the usable area, on the theory that if the GNUstep app can never display outside the usable area, then the usable area corresponds to the NSScreen rect as far as the GNUstep app is concerned.

Maybe that's wrong, and the NSScreen rect should correspond to the physical display, but if so, the GUI drawing code needs to understand the distinction between the physical screen rectangle and the usable screen rectangle somehow, so that it doesn't try to position the main menu, menubar etc outside of the usable part of the display (which is what was previously happening).

So unless I'm missing something, I think we can either:

Drop the workarea adjustment so that the screen rectangle is the physical size as reported by X, but at the same time keep the workarea code to find the usable screen rectangle, pass the usable rectangle back to the GUI. Add a new internal method to find the usable rectangle, adjust the -visibleFrame method to incorporate the usable rectangle, and adjust the menu code to use the usable rectangle information to ensure that main menus/menubars are appropriately constrained to be within the usable area of the screen.

or

We can have the NSScreen rectangle report the usable (to the GNUstep app) area of the physical screen, and fix any errors in the OpenStep<->X coordinate mapping resulting from that.

Does that make sense?

@rfm

rfm commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

I think this is a design/policy thing that Fred should decide on: I can see arguments either for both ways (I was lazy and chose the option that looked like least work). However, as far as I can see this PR on its own just breaks placement of menus and windows when used with the current main window managers: it would need to be coupled with all the changes to get menu placement and the -visibleFrame calculation correct.

@probonopd

Copy link
Copy Markdown
Contributor Author

Hi @rfm, @fredkiefer,

As I understand it, the underlying issue is that NSScreen.frame and the OpenStep <-> X coordinate conversion currently use different heights (_NET_WORKAREA vs. the full X screen). Because they disagree, a window positioned at the top of frame no longer maps to the physical top of the display.

There seem to be two consistent ways to fix this:

Option (a): NSScreen.frame is the physical display

  • Drop the _NET_WORKAREA adjustment so NSScreen.frame always reports the full monitor size (this patch).
  • Keep reading _NET_WORKAREA, but expose it separately as the usable area (for example via NSScreen.visibleFrame or an equivalent internal API).
  • Applications that need to avoid reserved areas such as panels or docks use visibleFrame, while frame continues to represent the entire display.

With this approach, a window positioned at the top of frame maps to the physical top of the display because both frame and the existing OpenStep <-> X coordinate conversion use the full screen height.

This also matches the AppKit/OpenStep model, where frame describes the physical display and visibleFrame describes the usable portion.

Option (b): NSScreen.frame is the usable area

  • Keep applying _NET_WORKAREA, so NSScreen.frame already represents the usable rectangle.
  • Change the OpenStep <-> X coordinate conversion so it uses the workarea height instead of the full X screen height.
  • Applications continue using frame as they do today.

With this approach, a window positioned at the top of frame also maps to the physical top of the display because the coordinate conversion now uses the same height as frame.

Personally, I slightly prefer option (a). It cleanly separates the physical screen geometry from the window manager's usable work area, matches the existing AppKit semantics, and avoids making the meaning of NSScreen.frame depend on _NET_WORKAREA. Ideally, it should be paired with exposing the workarea separately (for example through visibleFrame), so applications that need the usable rectangle do not lose that information.

Both approaches resolve the inconsistency. The main difference is whether we want NSScreen.frame to represent the physical display or the usable area going forward.

@rfm

rfm commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

I think to do this we would need to:

  1. Change the backend code back to reporting the full display size.
  2. Add backend method to report usable rect
  3. Change NSScreen visibleRect to use the new method to get the usable rect. If the theme has no menu bar,vthis would be the visibleFrame.
    If the theme has a menu bar, the visibleFrame code could ask the main menu for it's height, and return the visible frame calculated by subtracting the menu bar height from the usable rect

The main menu in turn could ask NSScreen for visibleFrame, and position itself by its own height above it, because it knows that vusibleFrame has already taken it's height into account.

When changing themes we would need to be careful to change main menu height first, then get NSScreen to update, then reposition menus if necessary.

_NET_WORKAREA holds the area a window manager leaves usable, in X
coordinates, where y grows downwards from the top of the screen.  A screen
frame is in OpenStep coordinates, where y grows upwards, so the rectangle has
to be flipped.  The origin was set to zero instead.

The origin says which end of the screen the reserved rows are at.  A panel at
the top and a panel at the bottom reserve the same number of rows and report
the same height, so zeroing the origin gives both the same frame.  That frame
is right for a panel at the top and wrong by the height of the panel for one
at the bottom, where a window placed at the bottom of the screen was drawn
under the panel and the rows at the top could not be reached.

Measured on a 1920x1080 screen with 40 rows reserved at the bottom: a 50
pixel bar placed at the bottom of the screen was mapped at X row 1030, over a
panel occupying rows 1040 to 1079, and is now mapped at row 990.  A bar
placed at the top was mapped at row 40 and is now at row 0.
_NET_WORKAREA refers to the composite display formed by all the monitors, so
it is only used as a screen frame when there is a single monitor.  That test
read monitorsCount while it still held screen_res->noutput, the number of
RandR outputs.  monitorsCount holds the number of monitors only after the
outputs have been walked, since an output the display is not using has no
CRTC and is not a monitor.

A driver reports an output for every connector it supports, so the count
matched only on a server that reports exactly one.  Measured with the Xorg
dummy driver, which reports 16 outputs: with a single monitor and a work area
40 rows shorter than the screen, the screen frame was the full 1920x1080 and
is now 1920x1040 at y 40, which is the frame Xvfb already gave through its
single output.
A panel at the top of the screen and a panel at the bottom reserve the same
number of rows, so they report the same work area height and differ only in
the origin.  They have to give different screen frames.

The test publishes _NET_WORKAREA on the root window and reads the frame back
through boundsForScreen:.  It creates the display server directly, since
nothing here draws, and skips when there is no display or when more than one
monitor is present, which is the case the property is not used for.

Tests/x11 now links the gui library, which is where GSDisplayServer lives.
@DTW-Thalion

Copy link
Copy Markdown
Contributor

Some measurements on this, all with a single monitor.

The work area is only applied when the server reports exactly one RandR
output, because monitorsCount still holds screen_res->noutput when that test
runs. On the Xorg dummy driver, which reports 16 outputs, a work area 40 rows
shorter than the screen was ignored and the frame stayed 1920x1080. On Xvfb,
which reports one output, the same property gave 1920x1040. So whether
NSScreen.frame is the full screen or the work area depends on how many
connectors the driver lists, which would account for a machine showing no
problem while another shows a top bar out of place.

Where the override does apply, the shift is real. With 40 rows reserved, a 60
pixel bar placed at the top of NSScreen.frame was mapped at X row 40 rather
than row 0.

Separately, _workAreas sets origin.y to zero instead of flipping it, so a
panel at the bottom of the screen gives the same frame as one at the top.
Measured with a bottom panel: a bar placed at the bottom of NSScreen.frame was
mapped at X rows 1030 to 1079, over a panel occupying rows 1040 to 1079, and
the top 40 rows could not be reached at all.

#226 corrects both of those inside the current model. It does not settle
whether frame should be the physical display or the usable area.

…igin

# Conflicts:
#	Tests/x11/GNUmakefile.preamble
XGServerWindow.m keeps the two comments master already had.  The header of
Tests/x11/workarea.m states what the test covers and no more.
@probonopd

Copy link
Copy Markdown
Contributor Author

Hi @rfm, I would like to address your concerns fully. In order to do so. I need to reproduce the issue you see with my proposal. Can you give me step-by-step instructions that highlight the issue? Thanks!

@rfm

rfm commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Can you give me step-by-step instructions that highlight the issue?

  1. Checkout this PR and rebuild/install (a vanilla install on Ubuntu or Debian will definitely do)
  2. Build/Install any app (I use Ink.app) if you don't already have it.
  3. Ensure it uses default menu locations by deleting any defaults (eg. 'defaults delete org.gnustep.Ink')
  4. Launch the app: you will see the app menu top left on the screen, partly hidden behind the topbar so that it can't be dragged.

Switch back to master and rebuild back. re-launch the app. You will see the menu correctly positioned immediately below the topbar.

@probonopd

Copy link
Copy Markdown
Contributor Author

@rfm, I think the reproduction is useful because it exposes an important distinction that the current code is mixing together. I would separate four things rather than treating _NET_WORKAREA as an alternative definition of NSScreen.frame.

1. NSScreen.frame is the monitor geometry

NSScreen.frame should describe the monitor itself, not the part left over after desktop UI has been reserved. GNUstep's NSScreen documentation describes -frame as the full frame of the screen.

On X11, the backend gets monitor geometry from RandR. On Windows, the corresponding per-monitor distinction is MONITORINFO.rcMonitor versus MONITORINFO.rcWork. On macOS, AppKit supplies NSScreen.frame.

That distinction matters because the monitor geometry is also part of the coordinate-system definition.

2. _NET_WORKAREA is a work-area result, not monitor geometry

The X11 WM may reserve space for panels/docks using _NET_WM_STRUT / _NET_WM_STRUT_PARTIAL, and EWMH exposes the resulting _NET_WORKAREA to clients.

So _NET_WORKAREA answers a different question:

“Where should ordinary application windows normally be placed?”

It does not answer:

“What is the geometry of this monitor?”

There is an important multi-monitor qualification here too. _NET_WORKAREA is defined per desktop, not as an independent work rectangle for every RandR monitor. _NET_WORKAREA alone is therefore not enough to reconstruct arbitrary per-monitor usable rectangles. _NET_WM_STRUT_PARTIAL contains the edge-specific reservation information from which a WM can take monitor/output geometry into account.

So the backend should not simply replace every monitor's frame with _NET_WORKAREA.

3. The current X11 bug is the mixing of those coordinate spaces

The problematic operation in the backend is effectively:

monitors[0].frame = workArea;

That makes NSScreen.frame represent the WM work area.

But the X/OpenStep coordinate conversion still performs its Y inversion against the full X screen height.

The resulting problem can be made concrete. Suppose the monitor is 1920×1080 and the WM reserves a 40-pixel panel at the top. The X11 work area is then:

_NET_WORKAREA = (0, 40, 1920, 1040)

If that rectangle is used as NSScreen.frame, the top of the OpenStep frame is at the work-area origin. An OpenStep point at the top of that frame therefore corresponds to X11 y=40 before the Y inversion.

But _OSFrameToXFrame: performs the inversion using the full height 1080. Thus:

X11 y = 1080 - 40 = 1040

So the point which was supposed to represent the top of the reported screen frame ends up at X11 y=1040 — i.e. 40 pixels below the physical top of the monitor.

The problem is therefore not that the work area itself has the wrong origin. The problem is that NSScreen.frame has been given the work area's geometry while the coordinate conversion still treats it as though it described the full monitor geometry.

That is the frame/coordinate-conversion mismatch which produces the observed displacement.

4. visibleFrame should be the final application-usable rectangle

This is where I think the GUI side needs to be explicit about the different reservations.

The desired model is not simply:

frame - WM reservation - menu reservation = visibleFrame

because the menu reservation must not be subtracted twice if it is already represented by the WM work area.

Instead:

monitor geometry
      │
      ├── WM/desktop reservations
      │
      └── GNUstep-owned menu/dock reservation
                    │
                    ▼
             final visibleFrame

visibleFrame should be the final rectangle that GNUstep presents as safe for ordinary application placement, after accounting for the applicable external and GNUstep-owned reservations.

The menu bar itself is a separate placement question. We should place the menu bar in the strip reserved by GNUstep at the top of the monitor — or at the top of the WM work area when the WM has already reserved the area above it — and then make visibleFrame exclude exactly the GNUstep menu strip that remains reserved.

That keeps the menu placement and visibleFrame related without treating them as the same rectangle.

So I think the clean division for this change would be:

  1. libs-back: report the complete monitor geometry as NSScreen.frame, and keep the coordinate conversion consistent with that geometry.
  2. libs-back: expose the WM-provided work-area/reservation information separately where the backend can provide it.
  3. libs-gui: combine the applicable WM reservation information with GNUstep's own menu/dock reservation when determining the final visibleFrame, without double-counting.
  4. libs-gui: place the menu bar in the appropriate top strip — below an externally reserved panel where necessary — and exclude the GNUstep-reserved menu strip from the resulting application-visible area.
  5. Define the multi-monitor mapping explicitly rather than assuming that one global X11 _NET_WORKAREA rectangle is itself the work area of every NSScreen.

That also explains the Ink.app reproduction.

If PR #217 changes frame back to the monitor geometry, but does not simultaneously teach the GUI layer about the WM-reserved area, then the menu can indeed move to the monitor's physical top and end up behind the WM panel.

I therefore agree with the conclusion that PR #217 should not be considered complete on its own. But I don't think the example is evidence that _NET_WORKAREA belongs in NSScreen.frame. I think it demonstrates that the two pieces need to be fixed together: restore frame to its proper meaning, then propagate the work-area/reservation information through the appropriate GUI-side path to determine the final usable area and menu placement.

That gives us a consistent model:

NSScreen.frame
    = complete monitor geometry

WM work area / reservations
    = information supplied by the desktop environment

GNUstep menu/dock reservation
    = information owned by GNUstep

NSScreen.visibleFrame
    = final application-usable geometry

with the important proviso that a reservation must only be accounted for once.

I'd be happy to hear your thoughts.

@rfm

rfm commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

I think that matches the conclusion I reached a few weeks ago, but with a bit more detail.
I hadn't particularly noticed that the area reserved would be different for different screens, which makes the work needed for the backend to determine and communicate that information to the GUI a little more complicated, but doesn't change the basic design.

@rfm

rfm commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

To be clear, I do agree with that latest analysis but I don't think it moves us any further on.
We are agreed that this patch is not acceptable on its iwn because, while it is a step towards the solution, it makes the system less usable. So we need to include it in a bigger change.

The way to progress is to actually make that whole change, which requires changing both back and guí together, a PR for each which can be merged at the same time.

The two PRs connect using a new method for gui to ask back which part of each screen is available for menus and which part for normal windows.

@rfm

rfm commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

NB. In the common case where gnustep menus are not integrated with the window manager, screen availability for menus and normal windows would be the same. I guess this would depend on the interface style selected, which is known to the GUI, so perhaps two separate methods would make sense, one to let the GUI ask about where it can place normal windows, and one to ask where the window manager allows the app main menu to be placed.

@probonopd

probonopd commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor Author

We are agreed that this patch is not acceptable on its iwn because, while it is a step towards the solution, it makes the system less usable. So we need to include it in a bigger change.

So we agree conceptually. It's just that the "second part" of the solution is missing. I will see what I can do.

@fredkiefer
fredkiefer removed their request for review September 6, 2026 15:31
@probonopd

Copy link
Copy Markdown
Contributor Author

Another data point for the output count issue @DTW-Thalion measured on the Xorg dummy driver: it also happens on ordinary laptops.

On a laptop with a single built-in panel, xrandr lists 6 outputs: eDP-1 (connected, 1920x1080) plus HDMI-1, DP-1, DP-2, DP-3 and DP-4 (all disconnected, no CRTC). The window manager sets _NET_WORKAREA = 0, 24, 1920, 986 (a panel at the top and a dock at the bottom). Because the single monitor test runs while monitorsCount still holds screen_res->noutput (6), the work area is never applied there, and NSScreen reports the full 1920x1080. On Xvfb on the same machine (one output) the work area is applied.

So today whether the work area is used depends on how many connectors the graphics hardware exposes, not on how many monitors are attached. Counting only outputs that have a CRTC before the single monitor test (as #226 does) makes the laptop behave like Xvfb.

@probonopd

Copy link
Copy Markdown
Contributor Author

Thinking about where #226 leaves this PR.

#226 fixes the two concrete defects in the current model: the work area origin is now flipped against the full screen height instead of being zeroed, and the single monitor test counts monitors instead of outputs. With the origin flipped, NSScreen.frame and _OSFrameToXFrame are in the same coordinate space again. The main technical argument in this PR's description (the frame and the Y-flip disagreeing, so a window at the top of the frame lands too low) is therefore largely resolved by #226 without changing what frame means.

What #226 does not address is the design question discussed above: frame still is the usable area, not the monitor. That leaves a few things open:

  • A client that itself reserves a strut (a desktop menu bar or dock written with GNUstep) cannot place itself in the area it reserved, since that area is outside every NSScreen.frame it can see. Before Fix: flip the _NET_WORKAREA origin and count monitors, not outputs #226 this only happened on machines with exactly one RandR output; with Fix: flip the _NET_WORKAREA origin and count monitors, not outputs #226 it also happens on laptops and other machines that expose disconnected connectors, so it becomes more common.
  • Apps have no way to learn the physical monitor geometry.
  • -visibleFrame subtracts the menu height from a frame that may already exclude the menu bar's strut, so the menu can be counted twice when the menu bar is a strut owning window.

So I don't think this PR is redundant, but it should not be merged as it is. I see two ways forward:

  1. Close this PR and let Fix: flip the _NET_WORKAREA origin and count monitors, not outputs #226 go in on its own as the fix for the current model. The frame versus usable area redesign would then come later as the paired libs-back and libs-gui change @rfm described, with a new backend method for the usable area of each screen and -visibleFrame built from it, taking care to count the menu reservation only once.
  2. Rework this PR into the libs-back half of that paired change, on top of Fix: flip the _NET_WORKAREA origin and count monitors, not outputs #226: keep Fix: flip the _NET_WORKAREA origin and count monitors, not outputs #226's flip and monitor count, but store the work area separately instead of in frame, and expose it to the GUI. The libs-gui half would be a companion PR to be merged together with it.

I lean towards 2 on top of #226, so that #226 can be merged first and the redesign stays a separate, reviewable step. Opinions welcome, @rfm @fredkiefer @DTW-Thalion.

@rfm

rfm commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

I agree: you have convinced me that the screen frame is meant to reflect the physical display

probonopd added a commit to gershwin-desktop/gershwin-developer that referenced this pull request Sep 20, 2026
The X11 backend had no way to pass on the area a window manager leaves to
application windows, and it used that area as the screen frame instead
whenever there was a single monitor.  A frame that is not the whole screen
disagrees with the coordinate flip the backend does for windows, so a
window asked for at the top of the screen landed lower down by whatever
the panels reserve, while an application that wanted to avoid the Dock had
nothing to ask.

The screen frame is now always the whole monitor, the work area is read
from _NET_WORKAREA with its origin flipped into screen coordinates rather
than clamped to zero, and -workAreaForScreen: answers it; the other
backends answer their full screen, which changes nothing for them.
Together with the libs-gui side this is what -[NSScreen visibleFrame]
returns.

This replaces screen-frame-not-workarea.patch, which took the work area
out of the frame but stopped there, and which cannot be applied beside
this one.  Upstream has the first half open as gnustep/libs-back#217 and
the origin flip as #226; the accessor itself is not upstream yet.
The frame of a screen was replaced by _NET_WORKAREA whenever there was a
single monitor, so NSScreen described what the window manager leaves over
rather than the display.  An application could not learn the geometry of
the monitor, and one that reserves space itself, a menu bar or a dock,
could not place itself in the strip it had just reserved, since that strip
lies outside every frame it can see.

The frame is the monitor again, the work area is kept beside it, and
-workAreaForScreen: answers it.  The other servers answer their whole
screen, which is what they reserve nothing of.

This is the backend half of the pair discussed in gnustep#217; the gui half,
which builds -[NSScreen visibleFrame] from the new method, is
gnustep/libs-gui#953.  It sits on top of gnustep#226, whose flip of the
_NET_WORKAREA origin and count of monitors rather than outputs it needs
and does not repeat.
@probonopd
probonopd force-pushed the fix/screen-frame-not-workarea branch from 613826f to a238924 Compare September 20, 2026 23:34
@probonopd probonopd changed the title x11: use the full screen size for the screen frame, not _NET_WORKAREA x11: report the monitor as the screen frame and the work area beside it Sep 20, 2026
The work area test asserted that _NET_WORKAREA shortens the screen frame,
which is what this branch stops it from doing.  It now publishes the same
two work areas and checks that the backend reports them, origin and all,
while the frame stays the whole screen whichever edge is reserved.
@probonopd
probonopd force-pushed the fix/screen-frame-not-workarea branch from 2037b0f to 08236d7 Compare September 21, 2026 00:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

4 participants