From a7be054a47e0501c74da11af47184b8df6ce326a Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Tue, 16 Dec 2025 15:09:22 +0000 Subject: [PATCH 1/4] Use _NET_WORKAREA (if available) to adjust our visible/usable screen. --- Source/x11/XGServerWindow.m | 76 +++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/Source/x11/XGServerWindow.m b/Source/x11/XGServerWindow.m index 1add4321..35260950 100644 --- a/Source/x11/XGServerWindow.m +++ b/Source/x11/XGServerWindow.m @@ -4465,6 +4465,68 @@ - (void) freecursor: (void*) cid return scrSize; } +static NSArray * +_workAreas(Display *dpy, Window root) +{ + Atom workarea_atom; + Atom type; + int format; + int status; + unsigned long *items; + unsigned long nitems; + unsigned long bytes_after; + unsigned char *data = NULL; + unsigned count; + unsigned index; + NSMutableArray *array; + + workarea_atom = XInternAtom(dpy, "_NET_WORKAREA", False); + status = XGetWindowProperty(dpy, root, workarea_atom, + 0, /* offset */ + (~0L), /* read all items */ + False, + XA_CARDINAL, + &type, + &format, + &nitems, + &bytes_after, + &data + ); + + if (status != Success || !data) + { + NSLog(@"Failed to get _NET_WORKAREA\n"); + return nil; + } + if (format != 32) + { + XFree(data); + return nil; + } + + items = (unsigned long *)data; + count = nitems / 4; + array = [NSMutableArray arrayWithCapacity: count]; + for (index = 0; index < count; index++) + { + NSRect frame; + + frame.origin.x = (uint32_t)*items++; + frame.origin.y = (uint32_t)*items++; + frame.size.width = (uint32_t)*items++; + frame.size.height = (uint32_t)*items++; + // X coordinates need to be flipped to OpenStep coordinates + if (frame.origin.y > 0.0) + { + frame.size.height -= frame.origin.y; + frame.origin.y = 0.0; + } + [array addObject: [NSValue valueWithRect: frame]]; + } + XFree(data); + return array; +} + /* This method assumes that we deal with one X11 screen - `defScreen`. Basically it means that we have DISPLAY variable set to `:0.0`. @@ -4478,6 +4540,7 @@ - (void) freecursor: (void*) cid We map XRandR monitors (outputs) to NSScreen. */ - (NSArray *)screenList { + NSArray *workAreas; xScreenSize = _screenSize(dpy, defScreen); monitorsCount = 0; @@ -4565,6 +4628,19 @@ - (NSArray *)screenList monitors[0].depth = [self windowDepthForScreen: 0]; monitors[0].resolution = [self resolutionForScreen: defScreen]; monitors[0].frame = NSMakeRect(0, 0, xScreenSize.width, xScreenSize.height); + + workAreas = _workAreas(dpy, [self xDisplayRootWindow]); + if ([workAreas count] > 0) + { + NSRect first = [[workAreas firstObject] rectValue]; + +/* + NSLog(@"Replace %@ with %@", + NSStringFromRect(monitors[0].frame), + NSStringFromRect(first)); + */ + monitors[0].frame = first; + } return [NSArray arrayWithObject: [NSNumber numberWithInt: defScreen]]; } From 36c35e205db7685dd0a17ff8c58ce70cba5031bb Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Wed, 17 Dec 2025 11:23:26 +0000 Subject: [PATCH 2/4] Update workarea for multiple screens --- Source/x11/XGServerWindow.m | 86 ++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/Source/x11/XGServerWindow.m b/Source/x11/XGServerWindow.m index 35260950..b228e04e 100644 --- a/Source/x11/XGServerWindow.m +++ b/Source/x11/XGServerWindow.m @@ -4464,7 +4464,12 @@ - (void) freecursor: (void*) cid return scrSize; } - + +/* Gets the work areas (if the window manager supports _NET_WORKAREA) of the + * monitors/screens for the display. These are supposed to be the extents of + * the screen that we can use without trspassing on areas reservced for the + * window manager. + */ static NSArray * _workAreas(Display *dpy, Window root) { @@ -4540,17 +4545,18 @@ - (void) freecursor: (void*) cid We map XRandR monitors (outputs) to NSScreen. */ - (NSArray *)screenList { - NSArray *workAreas; + Window root = [self xDisplayRootWindow]; + NSArray *workAreas = _workAreas(dpy, root); xScreenSize = _screenSize(dpy, defScreen); monitorsCount = 0; - if (monitors != NULL) { - NSZoneFree([self zone], monitors); - monitors = NULL; - } + if (monitors != NULL) + { + NSZoneFree([self zone], monitors); + monitors = NULL; + } #ifdef HAVE_XRANDR - Window root = [self xDisplayRootWindow]; XRRScreenResources *screen_res = XRRGetScreenResources(dpy, root); if (screen_res != NULL) @@ -4560,38 +4566,58 @@ - (NSArray *)screenList { int i; int mi; - NSMutableArray *tmpScreens = [NSMutableArray arrayWithCapacity: monitorsCount]; + NSMutableArray *tmpScreens; RROutput primary_output = XRRGetOutputPrimary(dpy, root); - monitors = NSZoneMalloc([self zone], monitorsCount * sizeof(MonitorDevice)); + tmpScreens = [NSMutableArray arrayWithCapacity: monitorsCount]; + + monitors = NSZoneMalloc([self zone], + monitorsCount * sizeof(MonitorDevice)); for (i = 0, mi = 0; i < screen_res->noutput; i++) { XRROutputInfo *output_info; - output_info = XRRGetOutputInfo(dpy, screen_res, screen_res->outputs[i]); + output_info = XRRGetOutputInfo(dpy, + screen_res, screen_res->outputs[i]); if (output_info->crtc) { XRRCrtcInfo *crtc_info; - crtc_info = XRRGetCrtcInfo(dpy, screen_res, output_info->crtc); + crtc_info = XRRGetCrtcInfo(dpy, + screen_res, output_info->crtc); monitors[mi].screen_id = defScreen; monitors[mi].depth = [self windowDepthForScreen: mi]; - monitors[mi].resolution = [self resolutionForScreen: defScreen]; - /* Transform coordinates from Xlib (flipped) to OpenStep (unflippped). - Windows and screens should have the same coordinate system. */ - monitors[mi].frame = - NSMakeRect(crtc_info->x, - xScreenSize.height - crtc_info->height - crtc_info->y, - crtc_info->width, - crtc_info->height); + monitors[mi].resolution + = [self resolutionForScreen: defScreen]; + if ([workAreas count] > mi) + { + monitors[mi].frame = + [[workAreas objectAtIndex: mi] rectValue]; + } + else + { + /* Transform coordinates from Xlib (flipped) + * to OpenStep (unflipped). + * Windows and screens should have the same + * coordinate system. + */ + monitors[mi].frame = + NSMakeRect(crtc_info->x, + xScreenSize.height - crtc_info->height - crtc_info->y, + crtc_info->width, + crtc_info->height); + } /* Add monitor ID (index in monitors array). - Put primary monitor ID at index 0 since NSScreen get this as main - screen if application has no key window. */ + * Put primary monitor ID at index 0 since + * NSScreen gets this as main screen if application + * has no key window. + */ if (screen_res->outputs[i] == primary_output) { - [tmpScreens insertObject: [NSNumber numberWithInt: mi] atIndex: 0]; + [tmpScreens insertObject: [NSNumber numberWithInt: mi] + atIndex: 0]; } else { @@ -4629,17 +4655,9 @@ - (NSArray *)screenList monitors[0].resolution = [self resolutionForScreen: defScreen]; monitors[0].frame = NSMakeRect(0, 0, xScreenSize.width, xScreenSize.height); - workAreas = _workAreas(dpy, [self xDisplayRootWindow]); if ([workAreas count] > 0) { - NSRect first = [[workAreas firstObject] rectValue]; - -/* - NSLog(@"Replace %@ with %@", - NSStringFromRect(monitors[0].frame), - NSStringFromRect(first)); - */ - monitors[0].frame = first; + monitors[0].frame = [[workAreas firstObject] rectValue]; } return [NSArray arrayWithObject: [NSNumber numberWithInt: defScreen]]; } @@ -4891,8 +4909,7 @@ - (unsigned int) desktopNumberForScreen: (int)screen unsigned int number = 0; num = (unsigned int*)PropGetCheckProperty(dpy, RootWindow(dpy, screen), - generic._NET_CURRENT_DESKTOP_ATOM, XA_CARDINAL, - 32, 1, &c); + generic._NET_CURRENT_DESKTOP_ATOM, XA_CARDINAL, 32, 1, &c); if (num) { @@ -4927,8 +4944,7 @@ - (unsigned int) desktopNumberForWindow: (int)win return 0; num = (unsigned int*)PropGetCheckProperty(dpy, window->ident, - generic._NET_WM_DESKTOP_ATOM, XA_CARDINAL, - 32, 1, &c); + generic._NET_WM_DESKTOP_ATOM, XA_CARDINAL, 32, 1, &c); if (num) { From dc6ec70a6716aa7ae3975876ac978b84bec415ec Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Wed, 17 Dec 2025 11:34:44 +0000 Subject: [PATCH 3/4] Update ChangeLog --- ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index 35551b1b..6c9dfd49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2025-12-17 Richard Frith-Macdonald + + * Source/x11/XGServerWindow.m: + Implement support for _NET)WORKAREA as suggested by Fred + 2025-05-21 Fred Kiefer * Source/x11/scale.c, From c2040e93c3999ca265d8c2ed3a6540268cf66fb7 Mon Sep 17 00:00:00 2001 From: Richard Frith-Macdonald Date: Tue, 23 Dec 2025 09:05:23 +0000 Subject: [PATCH 4/4] fix typo --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 6c9dfd49..eadcffce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ 2025-12-17 Richard Frith-Macdonald * Source/x11/XGServerWindow.m: - Implement support for _NET)WORKAREA as suggested by Fred + Implement support for _NET_WORKAREA as suggested by Fred 2025-05-21 Fred Kiefer