mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
Fix X11 primary-monitor coordinates without changing fullscreen policy
Adapt the geometry fix from PR #12 to the current relative-mouse implementation. Keep display IDs independent of primary-first screen ordering, translate window and pointer coordinates consistently, and invalidate geometry on both RandR event types. Handle failed RandR snapshots and free EDID data. Add isolated native geometry regression coverage and use the configured SDK when linking the X11 probe. Validated all 30 component patches, the X11 and CoreGraphics builds, six native geometry groups, and the existing relative-mouse checks. The user confirmed the installed fix works on 2026-10-16. Co-authored-by: Maka <[email protected]>
This commit is contained in:
1 parent
70fd5fdebd
commit
d89a303ebe
5 files changed
+705
-43
No files matched your search
@@ -412,3 +412,34 @@ and exercises 100 cancellations with both retained and early-released caller
|
|||||||
references, without launching or inspecting Riot. A failure prints
|
references, without launching or inspecting Riot. A failure prints
|
||||||
`CFHOST_CANCEL_CHECK fail stage=...`; `unexpected-callback` means a completed
|
`CFHOST_CANCEL_CHECK fail stage=...`; `unexpected-callback` means a completed
|
||||||
lookup arrived instead of the cancellation.
|
lookup arrived instead of the cancellation.
|
||||||
|
|
||||||
|
## Primary-monitor geometry regression
|
||||||
|
|
||||||
|
After preparing the sources and configuring/building Darling, run:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
python3 scripts/prepare.py --check-only
|
||||||
|
python3 tools/check-x11-display-geometry.py
|
||||||
|
cc -std=c11 -Wall -Wextra -Werror tools/test-x11-relative-mouse.c -o build/test-x11-relative-mouse
|
||||||
|
build/test-x11-relative-mouse
|
||||||
|
```
|
||||||
|
|
||||||
|
The native probe requires the existing per-user AppKit and CoreGraphics overlays
|
||||||
|
and a running X11/Xwayland display. It rebuilds the changed X11 and CoreGraphics
|
||||||
|
objects and tests them in a temporary framework overlay, without installing them.
|
||||||
|
Six `DISPLAY_GEOMETRY ...=pass` lines are required; full output is saved in
|
||||||
|
`build/pr12-display-check.log`.
|
||||||
|
|
||||||
|
It checks the live primary screen's origin, synthetic single-monitor and offset
|
||||||
|
layouts (including vertically arranged screens and negative Cocoa coordinates),
|
||||||
|
unmapped window creation/resizing, display IDs after primary-first ordering,
|
||||||
|
CoreGraphics bounds and spatial queries, absolute and relative warp translation,
|
||||||
|
relative deltas, both RandR cache-invalidation events, and the root-screen fallback.
|
||||||
|
Warps are intercepted: the probe does not move the desktop pointer or send game
|
||||||
|
input. Synthetic layouts exercise coordinate conversion and display API behavior;
|
||||||
|
they do not simulate physical monitor hotplug or validate League rendering.
|
||||||
|
Fullscreen policy is unchanged. Manually verify game launch, window placement,
|
||||||
|
click alignment and edge panning on the affected monitor layout before rollout.
|
||||||
|
|
||||||
|
After installing the tested X11 and CoreGraphics binaries locally, the user
|
||||||
|
reported that everything was working (2026-10-16). Fullscreen policy was unchanged.
|
||||||
+455
-41
@@ -2107,7 +2107,7 @@ index bdc97bdf..139c91eb 100644
|
|||||||
_cursor = XcursorLibraryLoadCursor(display, "left_ptr");
|
_cursor = XcursorLibraryLoadCursor(display, "left_ptr");
|
||||||
return self;
|
return self;
|
||||||
diff --git a/AppKit/X11.backend/X11Display.h b/AppKit/X11.backend/X11Display.h
|
diff --git a/AppKit/X11.backend/X11Display.h b/AppKit/X11.backend/X11Display.h
|
||||||
index 18189404..0eff2187 100644
|
index 18189404..5b3a34bc 100644
|
||||||
--- a/AppKit/X11.backend/X11Display.h
|
--- a/AppKit/X11.backend/X11Display.h
|
||||||
+++ b/AppKit/X11.backend/X11Display.h
|
+++ b/AppKit/X11.backend/X11Display.h
|
||||||
@@ -10,13 +10,14 @@
|
@@ -10,13 +10,14 @@
|
||||||
@@ -2126,7 +2126,7 @@ index 18189404..0eff2187 100644
|
|||||||
|
|
||||||
@interface X11Display : NSDisplay {
|
@interface X11Display : NSDisplay {
|
||||||
Display *_display;
|
Display *_display;
|
||||||
@@ -36,8 +37,20 @@
|
@@ -36,19 +37,41 @@
|
||||||
NSTimeInterval lastClickTimeStamp;
|
NSTimeInterval lastClickTimeStamp;
|
||||||
int clickCount;
|
int clickCount;
|
||||||
X11Cursor *_blankCursor, *_defaultCursor;
|
X11Cursor *_blankCursor, *_defaultCursor;
|
||||||
@@ -2147,8 +2147,11 @@ index 18189404..0eff2187 100644
|
|||||||
+ unsigned char _modifierKeysDown[256];
|
+ unsigned char _modifierKeysDown[256];
|
||||||
int _rrEventBase;
|
int _rrEventBase;
|
||||||
NSArray* _lastScreens;
|
NSArray* _lastScreens;
|
||||||
|
+ // Root-window rectangle of the primary monitor (macOS's global origin).
|
||||||
|
+ NSRect _primaryRootFrame;
|
||||||
|
+ BOOL _primaryRootFrameValid;
|
||||||
|
|
||||||
@@ -45,7 +58,9 @@
|
@public
|
||||||
XIM _xim;
|
XIM _xim;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2158,8 +2161,16 @@ index 18189404..0eff2187 100644
|
|||||||
|
|
||||||
- (void) setWindow: (id) window forID: (XID) i;
|
- (void) setWindow: (id) window forID: (XID) i;
|
||||||
|
|
||||||
|
- (CGFloat) doubleClickInterval;
|
||||||
|
- (int) handleError: (XErrorEvent *) errorEvent;
|
||||||
|
+
|
||||||
|
+// Conversions between X root coordinates (top-left of the root window, y down)
|
||||||
|
+// and Cocoa global coordinates (bottom-left of the primary screen, y up).
|
||||||
|
+- (NSRect) rootRectForFrame: (NSRect) frame;
|
||||||
|
+- (NSRect) frameForRootRect: (NSRect) rect;
|
||||||
|
@end
|
||||||
diff --git a/AppKit/X11.backend/X11Display.m b/AppKit/X11.backend/X11Display.m
|
diff --git a/AppKit/X11.backend/X11Display.m b/AppKit/X11.backend/X11Display.m
|
||||||
index 5ae29bf4..024d3ec2 100644
|
index 5ae29bf4..86a647ff 100644
|
||||||
--- a/AppKit/X11.backend/X11Display.m
|
--- a/AppKit/X11.backend/X11Display.m
|
||||||
+++ b/AppKit/X11.backend/X11Display.m
|
+++ b/AppKit/X11.backend/X11Display.m
|
||||||
@@ -48,12 +48,271 @@
|
@@ -48,12 +48,271 @@
|
||||||
@@ -2540,7 +2551,183 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
- (void) _enableDetectableAutoRepeat {
|
- (void) _enableDetectableAutoRepeat {
|
||||||
int major = XkbMajorVersion, minor = XkbMinorVersion;
|
int major = XkbMajorVersion, minor = XkbMinorVersion;
|
||||||
XkbStateRec state;
|
XkbStateRec state;
|
||||||
@@ -536,12 +861,52 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -190,6 +515,35 @@ static void socketCallback(CFSocketRef s, CFSocketCallBackType type,
|
||||||
|
[_lastScreens release];
|
||||||
|
_lastScreens = nil;
|
||||||
|
}
|
||||||
|
+ _primaryRootFrameValid = NO;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Cocoa's global origin is the bottom-left corner of the primary screen, with
|
||||||
|
+ * y up; X's is the top-left corner of the root window, with y down. Screen
|
||||||
|
+ * frames and window frames are both expressed relative to the primary
|
||||||
|
+ * monitor's root rectangle. On a single monitor (or any layout whose primary
|
||||||
|
+ * sits at the root origin and is as tall as the root) this is the plain
|
||||||
|
+ * root-height flip with no offset. */
|
||||||
|
+- (NSRect) _primaryRootFrame {
|
||||||
|
+ if (!_primaryRootFrameValid)
|
||||||
|
+ [self screens];
|
||||||
|
+ return _primaryRootFrame;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (NSRect) rootRectForFrame: (NSRect) frame {
|
||||||
|
+ NSRect primary = [self _primaryRootFrame];
|
||||||
|
+ return NSMakeRect(frame.origin.x + NSMinX(primary),
|
||||||
|
+ NSMaxY(primary) - frame.origin.y - frame.size.height,
|
||||||
|
+ fmax(frame.size.width, 1.0),
|
||||||
|
+ fmax(frame.size.height, 1.0));
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (NSRect) frameForRootRect: (NSRect) rect {
|
||||||
|
+ NSRect primary = [self _primaryRootFrame];
|
||||||
|
+ return NSMakeRect(rect.origin.x - NSMinX(primary),
|
||||||
|
+ NSMaxY(primary) - rect.origin.y - rect.size.height,
|
||||||
|
+ fmax(rect.size.width, 1.0),
|
||||||
|
+ fmax(rect.size.height, 1.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray *) screens {
|
||||||
|
@@ -201,25 +555,60 @@ static void socketCallback(CFSocketRef s, CFSocketCallBackType type,
|
||||||
|
|
||||||
|
int eventBase, errorBase;
|
||||||
|
|
||||||
|
- if (XRRQueryExtension(_display, &eventBase, &errorBase)) {
|
||||||
|
- XRRScreenResources *screen;
|
||||||
|
-
|
||||||
|
+ XRRScreenResources *screen = NULL;
|
||||||
|
+ if (XRRQueryExtension(_display, &eventBase, &errorBase))
|
||||||
|
screen = XRRGetScreenResources(_display, DefaultRootWindow(_display));
|
||||||
|
+
|
||||||
|
+ if (screen) {
|
||||||
|
+ RROutput primaryOutput =
|
||||||
|
+ XRRGetOutputPrimary(_display, DefaultRootWindow(_display));
|
||||||
|
+ NSRect *rootFrames = calloc(screen->noutput ? screen->noutput : 1,
|
||||||
|
+ sizeof(NSRect));
|
||||||
|
+ if (!rootFrames) {
|
||||||
|
+ XRRFreeScreenResources(screen);
|
||||||
|
+ return [self _rootScreenFallback];
|
||||||
|
+ }
|
||||||
|
+ int primary = -1;
|
||||||
|
+
|
||||||
|
+ for (int i = 0; i < screen->noutput; i++) {
|
||||||
|
+ XRROutputInfo *oinfo =
|
||||||
|
+ XRRGetOutputInfo(_display, screen, screen->outputs[i]);
|
||||||
|
+ if (oinfo && oinfo->crtc) {
|
||||||
|
+ XRRCrtcInfo *crtc =
|
||||||
|
+ XRRGetCrtcInfo(_display, screen, oinfo->crtc);
|
||||||
|
+ if (crtc) {
|
||||||
|
+ rootFrames[i] =
|
||||||
|
+ NSMakeRect(crtc->x, crtc->y, crtc->width, crtc->height);
|
||||||
|
+ XRRFreeCrtcInfo(crtc);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // The XRandR primary, otherwise the first active output.
|
||||||
|
+ if (!NSIsEmptyRect(rootFrames[i]) &&
|
||||||
|
+ (primary < 0 || screen->outputs[i] == primaryOutput))
|
||||||
|
+ primary = i;
|
||||||
|
+ if (oinfo) XRRFreeOutputInfo(oinfo);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // Without any active output, keep the root-height flip.
|
||||||
|
+ _primaryRootFrame = primary >= 0
|
||||||
|
+ ? rootFrames[primary]
|
||||||
|
+ : NSMakeRect(0, 0, DisplayWidth(_display, DefaultScreen(_display)),
|
||||||
|
+ DisplayHeight(_display, DefaultScreen(_display)));
|
||||||
|
+ _primaryRootFrameValid = YES;
|
||||||
|
+
|
||||||
|
+ // [NSScreen screens] starts with the primary screen, as on macOS.
|
||||||
|
+ // Display IDs stay tied to the XRandR output index.
|
||||||
|
NSMutableArray<NSScreen *> *retval =
|
||||||
|
[NSMutableArray arrayWithCapacity: screen->noutput];
|
||||||
|
+ NSMutableArray<NSScreen *> *inactive = [NSMutableArray array];
|
||||||
|
|
||||||
|
Atom edidAtom = XInternAtom(_display, "EDID", FALSE);
|
||||||
|
|
||||||
|
for (int i = 0; i < screen->noutput; i++) {
|
||||||
|
- XRROutputInfo *oinfo =
|
||||||
|
- XRRGetOutputInfo(_display, screen, screen->outputs[i]);
|
||||||
|
NSScreen *nsscreen;
|
||||||
|
|
||||||
|
- if (oinfo->crtc) {
|
||||||
|
- XRRCrtcInfo *crtc =
|
||||||
|
- XRRGetCrtcInfo(_display, screen, oinfo->crtc);
|
||||||
|
- NSRect frame =
|
||||||
|
- NSMakeRect(crtc->x, crtc->y, crtc->width, crtc->height);
|
||||||
|
+ if (!NSIsEmptyRect(rootFrames[i])) {
|
||||||
|
+ NSRect frame = [self frameForRootRect: rootFrames[i]];
|
||||||
|
|
||||||
|
nsscreen =
|
||||||
|
[[[NSScreen alloc] initWithFrame: frame
|
||||||
|
@@ -228,18 +617,17 @@ static void socketCallback(CFSocketRef s, CFSocketCallBackType type,
|
||||||
|
Atom actualType;
|
||||||
|
unsigned long nitems, bytesAfter;
|
||||||
|
int actualFormat;
|
||||||
|
- unsigned char *prop;
|
||||||
|
+ unsigned char *prop = NULL;
|
||||||
|
|
||||||
|
if (XRRGetOutputProperty(_display, screen->outputs[i], edidAtom,
|
||||||
|
0, 100, FALSE, FALSE, AnyPropertyType,
|
||||||
|
&actualType, &actualFormat, &nitems,
|
||||||
|
&bytesAfter, &prop) == Success) {
|
||||||
|
- if (prop && nitems > 0)
|
||||||
|
+ if (prop && actualFormat == 8 && nitems > 0)
|
||||||
|
[nsscreen setEdid: [NSData dataWithBytes: prop
|
||||||
|
length: nitems]];
|
||||||
|
}
|
||||||
|
-
|
||||||
|
- XRRFreeCrtcInfo(crtc);
|
||||||
|
+ if (prop) XFree(prop);
|
||||||
|
} else {
|
||||||
|
nsscreen = [[[NSScreen alloc] initWithFrame: NSZeroRect
|
||||||
|
visibleFrame: NSZeroRect]
|
||||||
|
@@ -247,25 +635,35 @@ static void socketCallback(CFSocketRef s, CFSocketCallBackType type,
|
||||||
|
}
|
||||||
|
[nsscreen setCgDirectDisplayID: (i + 1)];
|
||||||
|
|
||||||
|
- [retval addObject: nsscreen];
|
||||||
|
-
|
||||||
|
- XRRFreeOutputInfo(oinfo);
|
||||||
|
+ if (i == primary)
|
||||||
|
+ [retval insertObject: nsscreen atIndex: 0];
|
||||||
|
+ else if (!NSIsEmptyRect(rootFrames[i]))
|
||||||
|
+ [retval addObject: nsscreen];
|
||||||
|
+ else
|
||||||
|
+ [inactive addObject: nsscreen];
|
||||||
|
}
|
||||||
|
+ [retval addObjectsFromArray: inactive];
|
||||||
|
|
||||||
|
+ free(rootFrames);
|
||||||
|
XRRFreeScreenResources(screen);
|
||||||
|
|
||||||
|
NSArray* array = [NSArray arrayWithArray: retval];
|
||||||
|
_lastScreens = [array retain];
|
||||||
|
return array;
|
||||||
|
- } else {
|
||||||
|
- NSRect frame = NSMakeRect(
|
||||||
|
- 0, 0, DisplayWidth(_display, DefaultScreen(_display)),
|
||||||
|
- DisplayHeight(_display, DefaultScreen(_display)));
|
||||||
|
- return [NSArray
|
||||||
|
- arrayWithObject: [[[NSScreen alloc] initWithFrame: frame
|
||||||
|
- visibleFrame: frame]
|
||||||
|
- autorelease]];
|
||||||
|
}
|
||||||
|
+ return [self _rootScreenFallback];
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+- (NSArray *) _rootScreenFallback {
|
||||||
|
+ NSRect frame = NSMakeRect(
|
||||||
|
+ 0, 0, DisplayWidth(_display, DefaultScreen(_display)),
|
||||||
|
+ DisplayHeight(_display, DefaultScreen(_display)));
|
||||||
|
+ _primaryRootFrame = frame;
|
||||||
|
+ _primaryRootFrameValid = YES;
|
||||||
|
+ NSScreen *nsscreen = [[[NSScreen alloc] initWithFrame: frame
|
||||||
|
+ visibleFrame: frame] autorelease];
|
||||||
|
+ [nsscreen setCgDirectDisplayID: 1];
|
||||||
|
+ return [NSArray arrayWithObject: nsscreen];
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
|
@@ -536,12 +934,52 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
return &layout->layout;
|
return &layout->layout;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2595,7 +2782,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSPasteboard *) pasteboardWithName: (NSString *) name {
|
- (NSPasteboard *) pasteboardWithName: (NSString *) name {
|
||||||
@@ -675,6 +1040,15 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -675,6 +1113,15 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
blue: 0.60f
|
blue: 0.60f
|
||||||
alpha: 1.0f];
|
alpha: 1.0f];
|
||||||
|
|
||||||
@@ -2611,7 +2798,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
NSLog(@"missing color for %@", colorName);
|
NSLog(@"missing color for %@", colorName);
|
||||||
return [NSColor redColor];
|
return [NSColor redColor];
|
||||||
}
|
}
|
||||||
@@ -688,6 +1062,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -688,6 +1135,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) hideCursor {
|
- (void) hideCursor {
|
||||||
@@ -2622,7 +2809,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
if (!_blankCursor)
|
if (!_blankCursor)
|
||||||
_blankCursor = [[X11Cursor alloc] initBlank];
|
_blankCursor = [[X11Cursor alloc] initBlank];
|
||||||
[self setCursor: _blankCursor];
|
[self setCursor: _blankCursor];
|
||||||
@@ -695,6 +1073,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -695,6 +1146,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
|
|
||||||
- (void) unhideCursor {
|
- (void) unhideCursor {
|
||||||
NSCursor *current = [NSCursor currentCursor];
|
NSCursor *current = [NSCursor currentCursor];
|
||||||
@@ -2633,7 +2820,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
if (current != nil) {
|
if (current != nil) {
|
||||||
[current push];
|
[current push];
|
||||||
[current pop];
|
[current pop];
|
||||||
@@ -747,12 +1129,28 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -747,12 +1202,28 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
|
|
||||||
- (void) setCursor: (id) cursor {
|
- (void) setCursor: (id) cursor {
|
||||||
CGWindow *window = [[NSApp keyWindow] platformWindow];
|
CGWindow *window = [[NSApp keyWindow] platformWindow];
|
||||||
@@ -2667,7 +2854,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,15 +1319,22 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -921,15 +1392,22 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSPoint) mouseLocation {
|
- (NSPoint) mouseLocation {
|
||||||
@@ -2678,19 +2865,20 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
-
|
-
|
||||||
- XQueryPointer(_display, root, &root, &child, &root_x, &root_y, &win_x,
|
- XQueryPointer(_display, root, &root, &child, &root_x, &root_y, &win_x,
|
||||||
- &win_y, &mask);
|
- &win_y, &mask);
|
||||||
|
- int height = DisplayHeight(_display, DefaultScreen(_display));
|
||||||
|
- return NSMakePoint(root_x, height - root_y);
|
||||||
|
+ NSRect primary = [self _primaryRootFrame];
|
||||||
+ if (_relativeMouse.active) {
|
+ if (_relativeMouse.active) {
|
||||||
+ /* The cursor is disassociated: report the frozen (virtual) position, as macOS does. */
|
+ /* The cursor is disassociated: report the frozen (virtual) position, as macOS does. */
|
||||||
+ NSPoint result = NSMakePoint(_relativeMouse.virtualX,
|
+ NSPoint result = NSMakePoint(_relativeMouse.virtualX - NSMinX(primary),
|
||||||
+ DisplayHeight(_display, DefaultScreen(_display)) - _relativeMouse.virtualY);
|
+ NSMaxY(primary) - _relativeMouse.virtualY);
|
||||||
+ if (rclolTraceOn())
|
+ if (rclolTraceOn())
|
||||||
+ rclolTraceMouseLocation(result, YES, YES, (int) _relativeMouse.virtualX, (int) _relativeMouse.virtualY, YES);
|
+ rclolTraceMouseLocation(result, YES, YES, (int) _relativeMouse.virtualX, (int) _relativeMouse.virtualY, YES);
|
||||||
+ return result;
|
+ return result;
|
||||||
+ }
|
+ }
|
||||||
+ uint64_t rclolStampBefore = rclolPointerStamp;
|
+ uint64_t rclolStampBefore = rclolPointerStamp;
|
||||||
+ BOOL rclolQueried = rclolQueryPointer(_display);
|
+ BOOL rclolQueried = rclolQueryPointer(_display);
|
||||||
int height = DisplayHeight(_display, DefaultScreen(_display));
|
+ NSPoint result = NSMakePoint(rclolRootX - NSMinX(primary), NSMaxY(primary) - rclolRootY);
|
||||||
- return NSMakePoint(root_x, height - root_y);
|
|
||||||
+ NSPoint result = NSMakePoint(rclolRootX, height - rclolRootY);
|
|
||||||
+ if (rclolTraceOn())
|
+ if (rclolTraceOn())
|
||||||
+ rclolTraceMouseLocation(result, rclolQueried, rclolStampBefore != 0 && rclolPointerStamp == rclolStampBefore,
|
+ rclolTraceMouseLocation(result, rclolQueried, rclolStampBefore != 0 && rclolPointerStamp == rclolStampBefore,
|
||||||
+ rclolRootX, rclolRootY, NO);
|
+ rclolRootX, rclolRootY, NO);
|
||||||
@@ -2698,7 +2886,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) setWindow: (id) window forID: (XID) i {
|
- (void) setWindow: (id) window forID: (XID) i {
|
||||||
@@ -948,6 +1353,16 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -948,6 +1426,16 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
// retaining the window causes it to keep popping back up endlessly even after dismissing it
|
// retaining the window causes it to keep popping back up endlessly even after dismissing it
|
||||||
if (lastFocusedWindow && [[lastFocusedWindow platformWindow] windowHandle] == i)
|
if (lastFocusedWindow && [[lastFocusedWindow platformWindow] windowHandle] == i)
|
||||||
lastFocusedWindow = nil;
|
lastFocusedWindow = nil;
|
||||||
@@ -2715,7 +2903,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,20 +1377,82 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -962,20 +1450,82 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
{
|
{
|
||||||
#ifndef DARLING
|
#ifndef DARLING
|
||||||
[[NSRunLoop currentRunLoop] addInputSource: _inputSource forMode: mode];
|
[[NSRunLoop currentRunLoop] addInputSource: _inputSource forMode: mode];
|
||||||
@@ -2803,7 +2991,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSEventModifierFlags) modifierFlagsForState: (unsigned int) state {
|
- (NSEventModifierFlags) modifierFlagsForState: (unsigned int) state {
|
||||||
@@ -1010,17 +1487,96 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1010,17 +1560,96 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2900,7 +3088,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
NSEventModifierFlags modifierFlags = [self modifierFlagsForState: ev->xkey.state];
|
NSEventModifierFlags modifierFlags = [self modifierFlagsForState: ev->xkey.state];
|
||||||
char buf[20] = {0};
|
char buf[20] = {0};
|
||||||
KeySym keySym;
|
KeySym keySym;
|
||||||
@@ -1038,6 +1594,18 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1038,6 +1667,18 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
buf[strLen] = 0;
|
buf[strLen] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2919,7 +3107,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
id str = [[NSString alloc] initWithCString: buf
|
id str = [[NSString alloc] initWithCString: buf
|
||||||
encoding: NSUTF8StringEncoding];
|
encoding: NSUTF8StringEncoding];
|
||||||
NSPoint pos =
|
NSPoint pos =
|
||||||
@@ -1077,6 +1645,30 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1077,6 +1718,30 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ButtonPress:;
|
case ButtonPress:;
|
||||||
@@ -2950,7 +3138,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
|
NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
|
||||||
|
|
||||||
if (now - lastClickTimeStamp < [self doubleClickInterval]) {
|
if (now - lastClickTimeStamp < [self doubleClickInterval]) {
|
||||||
@@ -1086,8 +1678,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1086,8 +1751,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
}
|
}
|
||||||
lastClickTimeStamp = now;
|
lastClickTimeStamp = now;
|
||||||
|
|
||||||
@@ -2961,7 +3149,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
|
|
||||||
switch (ev->xbutton.button) {
|
switch (ev->xbutton.button) {
|
||||||
case Button1:
|
case Button1:
|
||||||
@@ -1096,10 +1688,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1096,10 +1761,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
case Button3:
|
case Button3:
|
||||||
type = NSRightMouseDown;
|
type = NSRightMouseDown;
|
||||||
break;
|
break;
|
||||||
@@ -2972,7 +3160,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
default:
|
default:
|
||||||
type = NSOtherMouseDown;
|
type = NSOtherMouseDown;
|
||||||
}
|
}
|
||||||
@@ -1113,14 +1701,22 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1113,14 +1774,22 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
clickCount: clickCount
|
clickCount: clickCount
|
||||||
deltaX: 0.0
|
deltaX: 0.0
|
||||||
deltaY: 0.0];
|
deltaY: 0.0];
|
||||||
@@ -2999,7 +3187,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
CGFloat deltaY = 0.0;
|
CGFloat deltaY = 0.0;
|
||||||
|
|
||||||
switch (ev->xbutton.button) {
|
switch (ev->xbutton.button) {
|
||||||
@@ -1130,14 +1726,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1130,14 +1799,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
case Button3:
|
case Button3:
|
||||||
type = NSRightMouseUp;
|
type = NSRightMouseUp;
|
||||||
break;
|
break;
|
||||||
@@ -3014,7 +3202,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
default:
|
default:
|
||||||
type = NSOtherMouseUp;
|
type = NSOtherMouseUp;
|
||||||
}
|
}
|
||||||
@@ -1151,7 +1739,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1151,7 +1812,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
clickCount: clickCount
|
clickCount: clickCount
|
||||||
deltaX: 0.0
|
deltaX: 0.0
|
||||||
deltaY: deltaY];
|
deltaY: deltaY];
|
||||||
@@ -3025,7 +3213,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
[self postEvent: event atStart: NO];
|
[self postEvent: event atStart: NO];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1164,45 +1754,82 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1164,45 +1827,82 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
pos = [window
|
pos = [window
|
||||||
transformPoint: NSMakePoint(ev->xmotion.x, ev->xmotion.y)];
|
transformPoint: NSMakePoint(ev->xmotion.x, ev->xmotion.y)];
|
||||||
|
|
||||||
@@ -3134,7 +3322,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
mouseEventWithType: type
|
mouseEventWithType: type
|
||||||
location: pos
|
location: pos
|
||||||
modifierFlags:
|
modifierFlags:
|
||||||
@@ -1211,28 +1838,49 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1211,28 +1911,49 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
clickCount: 1
|
clickCount: 1
|
||||||
deltaX: deltaX
|
deltaX: deltaX
|
||||||
deltaY: deltaY];
|
deltaY: deltaY];
|
||||||
@@ -3186,7 +3374,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
NSLog(@"FocusIn");
|
NSLog(@"FocusIn");
|
||||||
if ([delegate attachedSheet]) {
|
if ([delegate attachedSheet]) {
|
||||||
[[delegate attachedSheet] makeKeyAndOrderFront: delegate];
|
[[delegate attachedSheet] makeKeyAndOrderFront: delegate];
|
||||||
@@ -1243,28 +1891,55 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1243,28 +1964,55 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
checkForAppDeactivation: NO];
|
checkForAppDeactivation: NO];
|
||||||
lastFocusedWindow = nil;
|
lastFocusedWindow = nil;
|
||||||
}
|
}
|
||||||
@@ -3244,7 +3432,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
O2Rect rect = NSMakeRect(ev->xexpose.x, ev->xexpose.y,
|
O2Rect rect = NSMakeRect(ev->xexpose.x, ev->xexpose.y,
|
||||||
ev->xexpose.width, ev->xexpose.height);
|
ev->xexpose.width, ev->xexpose.height);
|
||||||
|
|
||||||
@@ -1301,11 +1976,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1301,11 +2049,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UnmapNotify:
|
case UnmapNotify:
|
||||||
@@ -3272,7 +3460,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MapRequest:
|
case MapRequest:
|
||||||
@@ -1321,6 +2008,7 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1321,6 +2081,7 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
[delegate platformWindow: window
|
[delegate platformWindow: window
|
||||||
frameChanged: [window frame]
|
frameChanged: [window frame]
|
||||||
didSize: YES];
|
didSize: YES];
|
||||||
@@ -3280,7 +3468,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ConfigureRequest:
|
case ConfigureRequest:
|
||||||
@@ -1344,6 +2032,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1344,6 +2105,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PropertyNotify:
|
case PropertyNotify:
|
||||||
@@ -3289,7 +3477,18 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
if ([window respondsToSelector: @selector(propertyNotify:)]) {
|
if ([window respondsToSelector: @selector(propertyNotify:)]) {
|
||||||
[window propertyNotify: &ev->xproperty];
|
[window propertyNotify: &ev->xproperty];
|
||||||
}
|
}
|
||||||
@@ -1433,6 +2123,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
@@ -1399,7 +2162,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
- if (ev->type == _rrEventBase + RRNotify) {
|
||||||
|
+ if (_rrEventBase && (ev->type == _rrEventBase + RRNotify ||
|
||||||
|
+ ev->type == _rrEventBase + RRScreenChangeNotify)) {
|
||||||
|
+ XRRUpdateConfiguration(ev);
|
||||||
|
[self _invalidateRRCache];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -1433,6 +2198,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||||
NSLog(@"Request code: %d:%d", errorEvent->request_code,
|
NSLog(@"Request code: %d:%d", errorEvent->request_code,
|
||||||
errorEvent->minor_code);
|
errorEvent->minor_code);
|
||||||
NSLog(@"Error code: %d", errorEvent->error_code);
|
NSLog(@"Error code: %d", errorEvent->error_code);
|
||||||
@@ -3300,7 +3499,7 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1476,54 +2170,214 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
|
@@ -1476,54 +2245,218 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3322,7 +3521,11 @@ index 5ae29bf4..024d3ec2 100644
|
|||||||
+ return [window transformPoint: NSMakePoint(x, y)];
|
+ return [window transformPoint: NSMakePoint(x, y)];
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
+// CGWarpMouseCursorPosition uses the primary screen's top-left, with y down.
|
||||||
- (void) warpMouse: (NSPoint) position {
|
- (void) warpMouse: (NSPoint) position {
|
||||||
|
+ NSRect primary = [self _primaryRootFrame];
|
||||||
|
+ position.x += NSMinX(primary);
|
||||||
|
+ position.y += NSMinY(primary);
|
||||||
+ if (rclolTraceOn())
|
+ if (rclolTraceOn())
|
||||||
+ rclolTraceRated(&rclolWarpAppChannel, "target=%.1f,%.1f relative=%d/%d virtual=%.1f,%.1f physical=%d,%d "
|
+ rclolTraceRated(&rclolWarpAppChannel, "target=%.1f,%.1f relative=%d/%d virtual=%.1f,%.1f physical=%d,%d "
|
||||||
+ "honoured=%d confined=%lu cachedRoot=%d,%d appActive=%d",
|
+ "honoured=%d confined=%lu cachedRoot=%d,%d appActive=%d",
|
||||||
@@ -3747,7 +3950,7 @@ index 0e91a5d1..1e4cec1b 100644
|
|||||||
|
|
||||||
- (void) selectionNotify: (XSelectionEvent *) event {
|
- (void) selectionNotify: (XSelectionEvent *) event {
|
||||||
diff --git a/AppKit/X11.backend/X11Window.h b/AppKit/X11.backend/X11Window.h
|
diff --git a/AppKit/X11.backend/X11Window.h b/AppKit/X11.backend/X11Window.h
|
||||||
index bfe3839a..2521ffd5 100644
|
index bfe3839a..dbc974a0 100644
|
||||||
--- a/AppKit/X11.backend/X11Window.h
|
--- a/AppKit/X11.backend/X11Window.h
|
||||||
+++ b/AppKit/X11.backend/X11Window.h
|
+++ b/AppKit/X11.backend/X11Window.h
|
||||||
@@ -26,7 +26,7 @@
|
@@ -26,7 +26,7 @@
|
||||||
@@ -3786,8 +3989,11 @@ index bfe3839a..2521ffd5 100644
|
|||||||
|
|
||||||
@public
|
@public
|
||||||
XIC _xic;
|
XIC _xic;
|
||||||
@@ -63,6 +83,7 @@
|
@@ -60,9 +80,9 @@
|
||||||
- (O2Rect) transformFrame: (O2Rect) frame;
|
- (Visual *) visual;
|
||||||
|
- (Drawable) drawable;
|
||||||
|
- (NSPoint) transformPoint: (NSPoint) pos;
|
||||||
|
-- (O2Rect) transformFrame: (O2Rect) frame;
|
||||||
|
|
||||||
- (Window) windowHandle;
|
- (Window) windowHandle;
|
||||||
+- (BOOL) handleRemoteFrameExpose: (Window) window;
|
+- (BOOL) handleRemoteFrameExpose: (Window) window;
|
||||||
@@ -3795,7 +4001,7 @@ index bfe3839a..2521ffd5 100644
|
|||||||
- (void) frameChanged;
|
- (void) frameChanged;
|
||||||
- (void) setLastKnownCursorPosition: (CGPoint) point;
|
- (void) setLastKnownCursorPosition: (CGPoint) point;
|
||||||
diff --git a/AppKit/X11.backend/X11Window.m b/AppKit/X11.backend/X11Window.m
|
diff --git a/AppKit/X11.backend/X11Window.m b/AppKit/X11.backend/X11Window.m
|
||||||
index f4925b66..5ad2d1f7 100644
|
index f4925b66..6f653f6d 100644
|
||||||
--- a/AppKit/X11.backend/X11Window.m
|
--- a/AppKit/X11.backend/X11Window.m
|
||||||
+++ b/AppKit/X11.backend/X11Window.m
|
+++ b/AppKit/X11.backend/X11Window.m
|
||||||
@@ -38,6 +38,34 @@
|
@@ -38,6 +38,34 @@
|
||||||
@@ -3833,6 +4039,15 @@ index f4925b66..5ad2d1f7 100644
|
|||||||
|
|
||||||
@implementation X11Window
|
@implementation X11Window
|
||||||
|
|
||||||
|
@@ -158,7 +186,7 @@ static NSData *makeWindowIcon() {
|
||||||
|
X11Display* x11disp = (X11Display *) [NSDisplay currentDisplay];
|
||||||
|
_display = [x11disp display];
|
||||||
|
|
||||||
|
- _frame = [self transformFrame: [delegate frame]];
|
||||||
|
+ _frame = [x11disp rootRectForFrame: [delegate frame]];
|
||||||
|
BOOL isPanel = [delegate isKindOfClass: [NSPanel class]];
|
||||||
|
if (isPanel && _styleMask & NSDocModalWindowMask)
|
||||||
|
_styleMask = NSBorderlessWindowMask;
|
||||||
@@ -193,8 +221,13 @@ static NSData *makeWindowIcon() {
|
@@ -193,8 +221,13 @@ static NSData *makeWindowIcon() {
|
||||||
|
|
||||||
XSetWindowAttributes xattr;
|
XSetWindowAttributes xattr;
|
||||||
@@ -4341,7 +4556,13 @@ index f4925b66..5ad2d1f7 100644
|
|||||||
- (Window) windowHandle {
|
- (Window) windowHandle {
|
||||||
return _window;
|
return _window;
|
||||||
}
|
}
|
||||||
@@ -478,6 +938,15 @@ static NSData *makeWindowIcon() {
|
@@ -473,11 +933,20 @@ static NSData *makeWindowIcon() {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) setFrame: (O2Rect) frame {
|
||||||
|
- frame = [self transformFrame: frame];
|
||||||
|
+ frame = [(X11Display *) [NSDisplay currentDisplay] rootRectForFrame: frame];
|
||||||
|
XMoveResizeWindow(_display, _window, frame.origin.x, frame.origin.y,
|
||||||
frame.size.width, frame.size.height);
|
frame.size.width, frame.size.height);
|
||||||
[self invalidateContextWithNewSize: frame.size];
|
[self invalidateContextWithNewSize: frame.size];
|
||||||
_frame = frame;
|
_frame = frame;
|
||||||
@@ -4426,6 +4647,15 @@ index f4925b66..5ad2d1f7 100644
|
|||||||
CGLError error;
|
CGLError error;
|
||||||
|
|
||||||
CGLContextObj prevContext = CGLGetCurrentContext();
|
CGLContextObj prevContext = CGLGetCurrentContext();
|
||||||
|
@@ -652,7 +1168,7 @@ static NSData *makeWindowIcon() {
|
||||||
|
}
|
||||||
|
|
||||||
|
- (O2Rect) frame {
|
||||||
|
- return [self transformFrame: _frame];
|
||||||
|
+ return [(X11Display *) [NSDisplay currentDisplay] frameForRootRect: _frame];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
|
||||||
@@ -666,6 +1182,7 @@ static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
|
@@ -666,6 +1182,7 @@ static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4434,6 +4664,21 @@ index f4925b66..5ad2d1f7 100644
|
|||||||
XErrorHandler previousHandler = XSetErrorHandler(ignoreBadWindow);
|
XErrorHandler previousHandler = XSetErrorHandler(ignoreBadWindow);
|
||||||
@try {
|
@try {
|
||||||
Window root, parent;
|
Window root, parent;
|
||||||
|
@@ -710,14 +1227,6 @@ static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
|
||||||
|
[_deviceDictionary addEntriesFromDictionary: entries];
|
||||||
|
}
|
||||||
|
|
||||||
|
-- (O2Rect) transformFrame: (O2Rect) frame {
|
||||||
|
- return NSMakeRect(frame.origin.x,
|
||||||
|
- DisplayHeight(_display, DefaultScreen(_display)) -
|
||||||
|
- frame.origin.y - frame.size.height,
|
||||||
|
- fmax(frame.size.width, 1.0),
|
||||||
|
- fmax(frame.size.height, 1.0));
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
- (NSPoint) transformPoint: (NSPoint) pos; {
|
||||||
|
return NSMakePoint(pos.x, _frame.size.height - pos.y);
|
||||||
|
}
|
||||||
diff --git a/AppKit/include/AppKit/NSAccessibilityConstants.h b/AppKit/include/AppKit/NSAccessibilityConstants.h
|
diff --git a/AppKit/include/AppKit/NSAccessibilityConstants.h b/AppKit/include/AppKit/NSAccessibilityConstants.h
|
||||||
index 282312de..03c75b2b 100644
|
index 282312de..03c75b2b 100644
|
||||||
--- a/AppKit/include/AppKit/NSAccessibilityConstants.h
|
--- a/AppKit/include/AppKit/NSAccessibilityConstants.h
|
||||||
@@ -5016,10 +5261,179 @@ index db8869c8..6fea5107 100644
|
|||||||
+ CGContextSetTextPosition(c, savedPosition.x, savedPosition.y);
|
+ CGContextSetTextPosition(c, savedPosition.x, savedPosition.y);
|
||||||
}
|
}
|
||||||
diff --git a/CoreGraphics/CGDirectDisplay.m b/CoreGraphics/CGDirectDisplay.m
|
diff --git a/CoreGraphics/CGDirectDisplay.m b/CoreGraphics/CGDirectDisplay.m
|
||||||
index e213b066..94d5c7bb 100644
|
index e213b066..569d77f2 100644
|
||||||
--- a/CoreGraphics/CGDirectDisplay.m
|
--- a/CoreGraphics/CGDirectDisplay.m
|
||||||
+++ b/CoreGraphics/CGDirectDisplay.m
|
+++ b/CoreGraphics/CGDirectDisplay.m
|
||||||
@@ -474,7 +474,9 @@ CGError CGAssociateMouseAndMouseCursorPosition(boolean_t connected) {
|
@@ -53,6 +53,29 @@ static NSDisplay *currentDisplay(void) {
|
||||||
|
return [cls currentDisplay];
|
||||||
|
}
|
||||||
|
|
||||||
|
+/* Display IDs belong to the screens themselves; [NSScreen screens] lists the
|
||||||
|
+ * primary screen first, so array positions are not IDs. */
|
||||||
|
+static NSScreen *screenForDisplayID(NSArray<NSScreen *> *screens,
|
||||||
|
+ CGDirectDisplayID displayID)
|
||||||
|
+{
|
||||||
|
+ for (NSScreen *screen in screens) {
|
||||||
|
+ if ([screen cgDirectDisplayID] == displayID)
|
||||||
|
+ return screen;
|
||||||
|
+ }
|
||||||
|
+ return nil;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* NSScreen frames have y up from the primary's bottom edge; CoreGraphics
|
||||||
|
+ * global coordinates have y down from the primary's top edge. */
|
||||||
|
+static CGRect globalRectForFrame(NSArray<NSScreen *> *screens, NSRect frame) {
|
||||||
|
+ if (NSIsEmptyRect(frame) || [screens count] == 0)
|
||||||
|
+ return frame;
|
||||||
|
+ CGFloat primaryHeight = NSHeight([[screens objectAtIndex: 0] frame]);
|
||||||
|
+ return CGRectMake(frame.origin.x,
|
||||||
|
+ primaryHeight - frame.origin.y - frame.size.height,
|
||||||
|
+ frame.size.width, frame.size.height);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
CGDirectDisplayID CGMainDisplayID(void) {
|
||||||
|
NSDisplay *display = currentDisplay();
|
||||||
|
if (!display)
|
||||||
|
@@ -60,9 +83,9 @@ CGDirectDisplayID CGMainDisplayID(void) {
|
||||||
|
|
||||||
|
NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
|
||||||
|
- for (int i = 0; i < [screens count]; i++) {
|
||||||
|
- if (!NSIsEmptyRect([[screens objectAtIndex: i] frame])) {
|
||||||
|
- return i + 1;
|
||||||
|
+ for (NSScreen *screen in screens) {
|
||||||
|
+ if (!NSIsEmptyRect([screen frame])) {
|
||||||
|
+ return [screen cgDirectDisplayID];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -89,10 +112,11 @@ CGError CGGetOnlineDisplayList(uint32_t maxDisplays,
|
||||||
|
onlineDisplays[0] = mainDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
- for (int i = 0; i < [screens count]; i++) {
|
||||||
|
- if ((i + 1) != mainDisplay) {
|
||||||
|
+ for (NSScreen *screen in screens) {
|
||||||
|
+ CGDirectDisplayID displayID = [screen cgDirectDisplayID];
|
||||||
|
+ if (displayID != mainDisplay) {
|
||||||
|
if (*displayCount < maxDisplays)
|
||||||
|
- onlineDisplays[*displayCount] = i + 1;
|
||||||
|
+ onlineDisplays[*displayCount] = displayID;
|
||||||
|
(*displayCount)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -105,11 +129,11 @@ size_t CGDisplayPixelsHigh(CGDirectDisplayID displayIndex) {
|
||||||
|
if (!display)
|
||||||
|
return kCGErrorInvalidConnection;
|
||||||
|
|
||||||
|
- NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
- if (displayIndex > [screens count] || displayIndex <= 0)
|
||||||
|
+ NSScreen *screen = screenForDisplayID([display screens], displayIndex);
|
||||||
|
+ if (!screen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- return NSHeight([[screens objectAtIndex: displayIndex - 1] frame]);
|
||||||
|
+ return NSHeight([screen frame]);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CGDisplayPixelsWide(CGDirectDisplayID displayIndex) {
|
||||||
|
@@ -117,11 +141,11 @@ size_t CGDisplayPixelsWide(CGDirectDisplayID displayIndex) {
|
||||||
|
if (!display)
|
||||||
|
return kCGErrorInvalidConnection;
|
||||||
|
|
||||||
|
- NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
- if (displayIndex > [screens count] || displayIndex <= 0)
|
||||||
|
+ NSScreen *screen = screenForDisplayID([display screens], displayIndex);
|
||||||
|
+ if (!screen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- return NSWidth([[screens objectAtIndex: displayIndex - 1] frame]);
|
||||||
|
+ return NSWidth([screen frame]);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGError CGGetActiveDisplayList(uint32_t maxDisplays,
|
||||||
|
@@ -135,10 +159,10 @@ CGError CGGetActiveDisplayList(uint32_t maxDisplays,
|
||||||
|
NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
|
||||||
|
*displayCount = 0;
|
||||||
|
- for (int i = 0; i < [screens count]; i++) {
|
||||||
|
- if (!NSIsEmptyRect([[screens objectAtIndex: i] frame])) {
|
||||||
|
+ for (NSScreen *screen in screens) {
|
||||||
|
+ if (!NSIsEmptyRect([screen frame])) {
|
||||||
|
if (*displayCount < maxDisplays)
|
||||||
|
- activeDisplays[*displayCount] = i + 1;
|
||||||
|
+ activeDisplays[*displayCount] = [screen cgDirectDisplayID];
|
||||||
|
(*displayCount)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -169,11 +193,11 @@ CGError CGGetDisplaysWithPoint(CGPoint point, uint32_t maxDisplays,
|
||||||
|
NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
*matchingDisplayCount = 0;
|
||||||
|
|
||||||
|
- for (int i = 0; i < [screens count]; i++) {
|
||||||
|
- NSRect rect = [[screens objectAtIndex: i] frame];
|
||||||
|
+ for (NSScreen *screen in screens) {
|
||||||
|
+ NSRect rect = globalRectForFrame(screens, [screen frame]);
|
||||||
|
if (NSPointInRect(point, rect)) {
|
||||||
|
if (*matchingDisplayCount < maxDisplays)
|
||||||
|
- displays[*matchingDisplayCount] = i + 1;
|
||||||
|
+ displays[*matchingDisplayCount] = [screen cgDirectDisplayID];
|
||||||
|
(*matchingDisplayCount)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -192,11 +216,11 @@ CGError CGGetDisplaysWithRect(CGRect rect, uint32_t maxDisplays,
|
||||||
|
NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
*matchingDisplayCount = 0;
|
||||||
|
|
||||||
|
- for (int i = 0; i < [screens count]; i++) {
|
||||||
|
- NSRect screenRect = [[screens objectAtIndex: i] frame];
|
||||||
|
+ for (NSScreen *screen in screens) {
|
||||||
|
+ NSRect screenRect = globalRectForFrame(screens, [screen frame]);
|
||||||
|
if (NSIntersectsRect(rect, screenRect)) {
|
||||||
|
if (*matchingDisplayCount < maxDisplays)
|
||||||
|
- displays[*matchingDisplayCount] = i + 1;
|
||||||
|
+ displays[*matchingDisplayCount] = [screen cgDirectDisplayID];
|
||||||
|
(*matchingDisplayCount)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -218,10 +242,11 @@ CGRect CGDisplayBounds(CGDirectDisplayID displayIndex) {
|
||||||
|
return NSZeroRect;
|
||||||
|
|
||||||
|
NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
- if (displayIndex > [screens count] || displayIndex <= 0)
|
||||||
|
+ NSScreen *screen = screenForDisplayID(screens, displayIndex);
|
||||||
|
+ if (!screen)
|
||||||
|
return NSZeroRect;
|
||||||
|
|
||||||
|
- return [[screens objectAtIndex: displayIndex - 1] frame];
|
||||||
|
+ return globalRectForFrame(screens, [screen frame]);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGError CGDisplayHideCursor(CGDirectDisplayID displayIndex) {
|
||||||
|
@@ -256,7 +281,7 @@ boolean_t CGDisplayIsInMirrorSet(CGDirectDisplayID display) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Boolean CGDisplayIsMain(CGDirectDisplayID display) {
|
||||||
|
- return display == 1;
|
||||||
|
+ return display != kCGNullDirectDisplay && display == CGMainDisplayID();
|
||||||
|
}
|
||||||
|
|
||||||
|
CGDirectDisplayID CGDisplayMirrorsDisplay(CGDirectDisplayID display) {
|
||||||
|
@@ -341,11 +366,10 @@ static NSData *edidForDisplay(CGDirectDisplayID displayId) {
|
||||||
|
if (!display)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
- NSArray<NSScreen *> *screens = [display screens];
|
||||||
|
- if (displayId <= 0 || displayId > [screens count])
|
||||||
|
+ NSScreen *screen = screenForDisplayID([display screens], displayId);
|
||||||
|
+ if (!screen)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
- NSScreen *screen = [screens objectAtIndex: displayId - 1];
|
||||||
|
NSData *edid = [screen edid];
|
||||||
|
if (edid && [edid length] >= 16)
|
||||||
|
return edid;
|
||||||
|
@@ -474,7 +498,9 @@ CGError CGAssociateMouseAndMouseCursorPosition(boolean_t connected) {
|
||||||
if (!display)
|
if (!display)
|
||||||
return kCGErrorInvalidConnection;
|
return kCGErrorInvalidConnection;
|
||||||
|
|
||||||
@@ -5030,7 +5444,7 @@ index e213b066..94d5c7bb 100644
|
|||||||
return kCGErrorSuccess;
|
return kCGErrorSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,3 +502,38 @@ CFDictionaryRef CGDisplayCurrentMode(CGDirectDisplayID display) {
|
@@ -500,3 +526,38 @@ CFDictionaryRef CGDisplayCurrentMode(CGDirectDisplayID display) {
|
||||||
size_t CGDisplayModeGetPixelWidth(CGDisplayModeRef mode) {
|
size_t CGDisplayModeGetPixelWidth(CGDisplayModeRef mode) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""Compile the changed X11 event handler and relink the existing backend."""
|
"""Compile the changed X11 event handler and relink the existing backend."""
|
||||||
|
import json
|
||||||
import shlex
|
import shlex
|
||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
project = Path(__file__).resolve().parent.parent
|
project = Path(__file__).resolve().parent.parent
|
||||||
framework = project / 'build/darling-src/build/src/external/cocotron/AppKit'
|
framework = project / 'build/darling-src/build/src/external/cocotron/AppKit'
|
||||||
|
config_path = project / 'build/config.json'
|
||||||
|
sdk = json.loads(config_path.read_text())['sdk'] if config_path.exists() else '/usr/local/libexec/darling'
|
||||||
flags = {}
|
flags = {}
|
||||||
for line in (framework / 'CMakeFiles/X11_backend.dir/flags.make').read_text().splitlines():
|
for line in (framework / 'CMakeFiles/X11_backend.dir/flags.make').read_text().splitlines():
|
||||||
if line.startswith('C_') and ' = ' in line:
|
if line.startswith('C_') and ' = ' in line:
|
||||||
@@ -17,7 +20,7 @@ for name in ('X11Display', 'X11Window'):
|
|||||||
link[link.index(f'CMakeFiles/X11_backend.dir/X11.backend/{name}.m.o')] = str(obj)
|
link[link.index(f'CMakeFiles/X11_backend.dir/X11.backend/{name}.m.o')] = str(obj)
|
||||||
link[link.index('-o') + 1] = str(project / 'build/riot-X11')
|
link[link.index('-o') + 1] = str(project / 'build/riot-X11')
|
||||||
subprocess.run(link, cwd=framework, check=True)
|
subprocess.run(link, cwd=framework, check=True)
|
||||||
print('Built isolated X11 backend with native visibility events')
|
print('Built isolated X11 backend')
|
||||||
|
|
||||||
# Exercise actual backend modifier transitions without compositor shortcuts.
|
# Exercise actual backend modifier transitions without compositor shortcuts.
|
||||||
probe = project / 'build/riot-modifier-check.o'
|
probe = project / 'build/riot-modifier-check.o'
|
||||||
@@ -25,6 +28,6 @@ subprocess.run(['clang', *flags['C_DEFINES'], *flags['C_INCLUDES'], *flags['C_FL
|
|||||||
'-O2', '-Wno-macro-redefined', '-c', str(project / 'tools/riot-modifier-check.m'),
|
'-O2', '-Wno-macro-redefined', '-c', str(project / 'tools/riot-modifier-check.m'),
|
||||||
'-o', str(probe)], check=True)
|
'-o', str(probe)], check=True)
|
||||||
subprocess.run(['clang', '-target', 'x86_64-apple-macosx11.0', '-fuse-ld=lld',
|
subprocess.run(['clang', '-target', 'x86_64-apple-macosx11.0', '-fuse-ld=lld',
|
||||||
'-nostdlib', '-isysroot', '@DARLING_SDK@', str(probe),
|
'-nostdlib', '-isysroot', sdk, str(probe),
|
||||||
'-lSystem', '-framework', 'AppKit', '-framework', 'Foundation', '-lobjc',
|
'-lSystem', '-framework', 'AppKit', '-framework', 'Foundation', '-lobjc',
|
||||||
'-o', str(project / 'build/riot-modifier-check')], check=True)
|
'-o', str(project / 'build/riot-modifier-check')], check=True)
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build changed display code and run a native probe in an isolated overlay.
|
||||||
|
|
||||||
|
Requires prepared sources, an existing CMake build, Darling, and the per-user
|
||||||
|
AppKit/CoreGraphics runtime overlays. Does not install binaries or send input.
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shlex
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
root = Path(__file__).resolve().parent.parent
|
||||||
|
config = json.loads((root / 'build/config.json').read_text())
|
||||||
|
frameworks = root / 'build/darling-src/build/src/external/cocotron'
|
||||||
|
subprocess.run(['python3', str(root / 'tools/build-riot-x11-runtime.py')], check=True)
|
||||||
|
|
||||||
|
def flags_for(framework, target):
|
||||||
|
flags = {}
|
||||||
|
for line in (framework / f'CMakeFiles/{target}.dir/flags.make').read_text().splitlines():
|
||||||
|
if line.startswith('C_') and ' = ' in line:
|
||||||
|
key, value = line.split(' = ', 1)
|
||||||
|
flags[key] = shlex.split(value)
|
||||||
|
return flags['C_DEFINES'] + flags['C_INCLUDES'] + flags['C_FLAGS']
|
||||||
|
|
||||||
|
cg = frameworks / 'CoreGraphics'
|
||||||
|
obj = root / 'build/pr12-CGDirectDisplay.o'
|
||||||
|
subprocess.run(['clang', *flags_for(cg, 'CoreGraphics'), '-O2', '-c',
|
||||||
|
str(root / 'build/darling-src/src/external/cocotron/CoreGraphics/CGDirectDisplay.m'),
|
||||||
|
'-o', str(obj)], check=True)
|
||||||
|
link = shlex.split((cg / 'CMakeFiles/CoreGraphics.dir/link.txt').read_text())
|
||||||
|
link[link.index('CMakeFiles/CoreGraphics.dir/CGDirectDisplay.m.o')] = str(obj)
|
||||||
|
link[link.index('-o') + 1] = str(root / 'build/pr12-CoreGraphics')
|
||||||
|
subprocess.run(link, cwd=cg, check=True)
|
||||||
|
probe = root / 'build/riot-display-geometry-check'
|
||||||
|
subprocess.run(['clang', *flags_for(frameworks / 'AppKit', 'X11_backend'),
|
||||||
|
'-O2', '-UNDEBUG', '-Wno-macro-redefined', '-c', str(root / 'tools/riot-display-geometry-check.m'),
|
||||||
|
'-o', str(probe) + '.o'], check=True)
|
||||||
|
subprocess.run(['clang', '-target', 'x86_64-apple-macosx11.0', '-fuse-ld=lld',
|
||||||
|
'-nostdlib', '-isysroot', config['sdk'], str(probe) + '.o',
|
||||||
|
'-lSystem', '-framework', 'AppKit', '-framework', 'Foundation',
|
||||||
|
'-framework', 'CoreGraphics', '-lobjc', '-o', str(probe)], check=True)
|
||||||
|
|
||||||
|
original = Path(config['prefix']) / config['guest_home'].lstrip('/') / 'RuntimeFrameworks'
|
||||||
|
with tempfile.TemporaryDirectory(prefix='pr12-display-frameworks-', dir=root / 'build') as directory:
|
||||||
|
overlay = Path(directory)
|
||||||
|
for name in ('AppKit', 'CoreGraphics'):
|
||||||
|
shutil.copytree(original / f'{name}.framework', overlay / f'{name}.framework',
|
||||||
|
symlinks=True, dirs_exist_ok=True,
|
||||||
|
ignore=shutil.ignore_patterns('*.before-*'))
|
||||||
|
shutil.copy2(root / 'build/riot-X11', overlay / 'AppKit.framework/Versions/C/Resources/Backends/X11.backend/Contents/MacOS/X11')
|
||||||
|
shutil.copy2(root / 'build/pr12-CoreGraphics', overlay / 'CoreGraphics.framework/Versions/A/CoreGraphics')
|
||||||
|
env = dict(os.environ, EGL_PLATFORM='x11',
|
||||||
|
DYLD_FRAMEWORK_PATH='/Volumes/SystemRoot' + str(overlay) + ':' + config['guest_home'] + '/RuntimeFrameworks',
|
||||||
|
DYLD_LIBRARY_PATH=config['guest_home'] + '/RuntimeLibraries')
|
||||||
|
# File capture bounds the wait even if a guest service inherits the output fd.
|
||||||
|
log = root / 'build/pr12-display-check.log'
|
||||||
|
with log.open('w+') as output:
|
||||||
|
try:
|
||||||
|
result = subprocess.run(['darling', 'shell', '/Volumes/SystemRoot' + str(probe)],
|
||||||
|
env=env, stdout=output, stderr=subprocess.STDOUT, timeout=45)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
raise SystemExit(f'Display probe timed out; inspect {log}')
|
||||||
|
output.seek(0)
|
||||||
|
lines = [line.rstrip() for line in output if line.startswith('DISPLAY_GEOMETRY')]
|
||||||
|
print('\n'.join(lines))
|
||||||
|
if result.returncode or len(lines) != 6:
|
||||||
|
raise SystemExit(f'Display probe failed ({result.returncode}); inspect {log}')
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
/* Exercise the real X11/CG methods with synthetic cached monitor layouts.
|
||||||
|
* No input is sent: pointer warps are captured by a temporary method override. */
|
||||||
|
#import <AppKit/AppKit.h>
|
||||||
|
#import <AppKit/NSDisplay.h>
|
||||||
|
#import <AppKit/NSScreen.h>
|
||||||
|
#import <CoreGraphics/CGDirectDisplay.h>
|
||||||
|
#import <objc/runtime.h>
|
||||||
|
#import "../build/darling-src/src/external/cocotron/AppKit/X11.backend/X11Display.h"
|
||||||
|
#import "../build/darling-src/src/external/cocotron/AppKit/X11.backend/X11Window.h"
|
||||||
|
#include <X11/extensions/Xrandr.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// Implemented by Cocotron but absent from its public headers.
|
||||||
|
extern CGRect CGDisplayBounds(CGDirectDisplayID display);
|
||||||
|
extern CGError CGWarpMouseCursorPosition(CGPoint position);
|
||||||
|
|
||||||
|
@interface X11Display (GeometryProbe)
|
||||||
|
- (NSArray *)_rootScreenFallback;
|
||||||
|
- (void)postXEvent:(XEvent *)event;
|
||||||
|
@end
|
||||||
|
|
||||||
|
static void *slot(id obj, const char *name) {
|
||||||
|
Ivar ivar = class_getInstanceVariable([obj class], name);
|
||||||
|
assert(ivar);
|
||||||
|
return (char *)obj + ivar_getOffset(ivar);
|
||||||
|
}
|
||||||
|
static void rectEqual(NSRect actual, NSRect expected) {
|
||||||
|
assert(NSEqualRects(actual, expected));
|
||||||
|
}
|
||||||
|
static unsigned captureWarp(id obj, SEL sel, int x, int y) {
|
||||||
|
assert(x == 3940 && y == 1010);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
static NSScreen *screen(NSRect frame, unsigned displayID) {
|
||||||
|
NSScreen *s = [[[NSScreen alloc] initWithFrame:frame visibleFrame:frame] autorelease];
|
||||||
|
[s setCgDirectDisplayID:displayID];
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
int main(void) {
|
||||||
|
setbuf(stdout,NULL);
|
||||||
|
@autoreleasepool {
|
||||||
|
[NSApplication sharedApplication];
|
||||||
|
X11Display *d = (id)[NSDisplay currentDisplay];
|
||||||
|
assert([d respondsToSelector:@selector(rootRectForFrame:)]);
|
||||||
|
NSArray *actualScreens = [d screens];
|
||||||
|
assert([actualScreens count] > 0);
|
||||||
|
NSScreen *first = [actualScreens objectAtIndex:0];
|
||||||
|
if (!NSIsEmptyRect([first frame])) {
|
||||||
|
assert(NSMinX([first frame]) == 0 && NSMinY([first frame]) == 0);
|
||||||
|
assert(CGMainDisplayID() == [first cgDirectDisplayID]);
|
||||||
|
}
|
||||||
|
puts("DISPLAY_GEOMETRY live_screen_origin=pass");
|
||||||
|
|
||||||
|
NSRect layouts[] = { NSMakeRect(0,0,1920,1080), NSMakeRect(3840,810,3840,2160),
|
||||||
|
NSMakeRect(0,1200,1920,1080), NSMakeRect(1920,0,1920,1080) };
|
||||||
|
for (unsigned i = 0; i < sizeof layouts / sizeof *layouts; i++) {
|
||||||
|
*(NSRect *)slot(d,"_primaryRootFrame") = layouts[i];
|
||||||
|
*(BOOL *)slot(d,"_primaryRootFrameValid") = YES;
|
||||||
|
NSRect frame = NSMakeRect(-320,140,800,600);
|
||||||
|
NSRect root = [d rootRectForFrame:frame];
|
||||||
|
rectEqual(root, NSMakeRect(NSMinX(layouts[i])-320,NSMaxY(layouts[i])-740,800,600));
|
||||||
|
rectEqual([d frameForRootRect:root],frame);
|
||||||
|
// Test X11Window's inverse as well, using an unmapped object.
|
||||||
|
X11Window *w = [NSClassFromString(@"X11Window") alloc];
|
||||||
|
*(NSRect *)slot(w,"_frame") = root;
|
||||||
|
rectEqual([w frame],frame);
|
||||||
|
[w release];
|
||||||
|
}
|
||||||
|
puts("DISPLAY_GEOMETRY single_offset_vertical_negative_roundtrip=pass");
|
||||||
|
NSWindow *window = [[NSWindow alloc] initWithContentRect:NSMakeRect(100,100,800,600)
|
||||||
|
styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
|
||||||
|
X11Window *native = (id)[window platformWindow];
|
||||||
|
rectEqual(*(NSRect *)slot(native,"_frame"),NSMakeRect(2020,380,800,600));
|
||||||
|
[native setFrame:NSMakeRect(-100,200,640,480)];
|
||||||
|
rectEqual(*(NSRect *)slot(native,"_frame"),NSMakeRect(1820,400,640,480));
|
||||||
|
rectEqual([native frame],NSMakeRect(-100,200,640,480));
|
||||||
|
[window release];
|
||||||
|
puts("DISPLAY_GEOMETRY unmapped_window_create_resize=pass");
|
||||||
|
|
||||||
|
NSRect primary = NSMakeRect(3840,810,3840,2160);
|
||||||
|
*(NSRect *)slot(d,"_primaryRootFrame") = primary;
|
||||||
|
NSArray **cache = slot(d,"_lastScreens");
|
||||||
|
[*cache release];
|
||||||
|
*cache = [@[
|
||||||
|
screen(NSMakeRect(0,0,3840,2160),2),
|
||||||
|
screen(NSMakeRect(-3840,102,3840,2160),1),
|
||||||
|
screen(NSMakeRect(3840,-230,1800,3200),3),
|
||||||
|
screen(NSZeroRect,4)
|
||||||
|
] retain];
|
||||||
|
assert(CGMainDisplayID() == 2 && CGDisplayIsMain(2) && !CGDisplayIsMain(1));
|
||||||
|
assert(CGDisplayPixelsWide(3) == 1800 && CGDisplayPixelsHigh(3) == 3200);
|
||||||
|
assert(CGDisplayPixelsWide(99) == 0);
|
||||||
|
rectEqual(CGDisplayBounds(1),NSMakeRect(-3840,-102,3840,2160));
|
||||||
|
rectEqual(CGDisplayBounds(3),NSMakeRect(3840,-810,1800,3200));
|
||||||
|
rectEqual(CGDisplayBounds(4),NSZeroRect);
|
||||||
|
CGDirectDisplayID ids[4] = {0}; uint32_t count;
|
||||||
|
assert(CGGetActiveDisplayList(4,ids,&count) == 0 && count == 3 && ids[0] == 2 && ids[1] == 1);
|
||||||
|
assert(CGGetOnlineDisplayList(1,ids,&count) == 0 && count == 4 && ids[0] == 2);
|
||||||
|
assert(CGGetActiveDisplayList(0,NULL,&count) == 0 && count == 3);
|
||||||
|
assert(CGGetDisplaysWithPoint(CGPointMake(-100,-50),4,ids,&count) == 0 && count == 1 && ids[0] == 1);
|
||||||
|
assert(CGGetDisplaysWithRect(CGRectMake(3900,-800,10,10),4,ids,&count) == 0 && count == 1 && ids[0] == 3);
|
||||||
|
puts("DISPLAY_GEOMETRY reordered_ids_bounds_enumeration_queries=pass");
|
||||||
|
|
||||||
|
Method method = class_getInstanceMethod([d class],@selector(warpPointerToRootX:y:));
|
||||||
|
assert(method);
|
||||||
|
IMP original = method_setImplementation(method,(IMP)captureWarp);
|
||||||
|
X11RelativeMouse *relative = slot(d,"_relativeMouse");
|
||||||
|
X11RelativeMouseBegin(relative,3900,1000);
|
||||||
|
assert(CGWarpMouseCursorPosition(CGPointMake(100,200)) == 0);
|
||||||
|
assert(relative->virtualX == 3940 && relative->virtualY == 1010);
|
||||||
|
NSPoint location = [d mouseLocation];
|
||||||
|
assert(location.x == 100 && location.y == 1960);
|
||||||
|
X11RelativeMouseMotion motion = X11RelativeMouseHandleMotion(relative,3907,1009,false);
|
||||||
|
assert(motion.deltaX == 7 && motion.deltaY == 9);
|
||||||
|
X11RelativeMouseEnd(relative);
|
||||||
|
assert(CGWarpMouseCursorPosition(CGPointMake(100,200)) == 0);
|
||||||
|
method_setImplementation(method,original);
|
||||||
|
puts("DISPLAY_GEOMETRY absolute_relative_warp_and_delta=pass");
|
||||||
|
int eventBase = *(int *)slot(d,"_rrEventBase");
|
||||||
|
assert(eventBase);
|
||||||
|
XEvent notify = {0}; notify.type = eventBase + RRNotify;
|
||||||
|
notify.xany.display = [d display];
|
||||||
|
[d postXEvent:¬ify];
|
||||||
|
assert(!*(BOOL *)slot(d,"_primaryRootFrameValid") && !*cache);
|
||||||
|
assert([[d screens] count] > 0 && *(BOOL *)slot(d,"_primaryRootFrameValid"));
|
||||||
|
XRRScreenChangeNotifyEvent change = {0};
|
||||||
|
Display *xdisplay = [d display];
|
||||||
|
change.type = eventBase + RRScreenChangeNotify;
|
||||||
|
change.display = xdisplay; change.root = DefaultRootWindow(xdisplay);
|
||||||
|
change.width = DisplayWidth(xdisplay,DefaultScreen(xdisplay));
|
||||||
|
change.height = DisplayHeight(xdisplay,DefaultScreen(xdisplay));
|
||||||
|
change.mwidth = DisplayWidthMM(xdisplay,DefaultScreen(xdisplay));
|
||||||
|
change.mheight = DisplayHeightMM(xdisplay,DefaultScreen(xdisplay));
|
||||||
|
change.rotation = RR_Rotate_0;
|
||||||
|
[d postXEvent:(XEvent *)&change];
|
||||||
|
assert(!*(BOOL *)slot(d,"_primaryRootFrameValid") && !*cache);
|
||||||
|
NSArray *fallback = [d _rootScreenFallback];
|
||||||
|
assert([fallback count] == 1 && [[fallback objectAtIndex:0] cgDirectDisplayID] == 1);
|
||||||
|
rectEqual(*(NSRect *)slot(d,"_primaryRootFrame"),NSMakeRect(0,0,change.width,change.height));
|
||||||
|
puts("DISPLAY_GEOMETRY cache_events_and_fallback=pass");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user