mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-26 19:47:42 +00:00
AppKit/X11: Robust multi-monitor mouse boundary confinement and clean stale Darling/Riot state
This commit is contained in:
1 parent
6084371a67
commit
30383d6462
2 files changed
+94
-16
No files matched your search
+71
-16
@@ -2305,7 +2305,7 @@ index 18189404..5b3a34bc 100644
|
||||
+- (NSRect) frameForRootRect: (NSRect) rect;
|
||||
@end
|
||||
diff --git a/AppKit/X11.backend/X11Display.m b/AppKit/X11.backend/X11Display.m
|
||||
index 5ae29bf4..5105e7d8 100644
|
||||
index 5ae29bf4..5403cfa3 100644
|
||||
--- a/AppKit/X11.backend/X11Display.m
|
||||
+++ b/AppKit/X11.backend/X11Display.m
|
||||
@@ -48,12 +48,271 @@
|
||||
@@ -3355,7 +3355,38 @@ index 5ae29bf4..5105e7d8 100644
|
||||
[self postEvent: event atStart: NO];
|
||||
break;
|
||||
|
||||
@@ -1164,45 +1834,82 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1160,49 +1830,113 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
// ev->xmotion.x, ev->xmotion.y, ev->xmotion.x_root,
|
||||
// ev->xmotion.y_root);
|
||||
|
||||
+ /* darling-lol: Coalesce pending MotionNotify events in the X11 queue to eliminate input lag. */
|
||||
+ XEvent nextEv;
|
||||
+ while (XCheckTypedWindowEvent(_display, ev->xmotion.window, MotionNotify, &nextEv)) {
|
||||
+ *ev = nextEv;
|
||||
+ }
|
||||
+
|
||||
+ if (_confinedWindow == [window windowHandle]) {
|
||||
+ XWindowAttributes attrs;
|
||||
+ if (XGetWindowAttributes(_display, _confinedWindow, &attrs)) {
|
||||
+ int clampedX = ev->xmotion.x;
|
||||
+ int clampedY = ev->xmotion.y;
|
||||
+ BOOL needWarp = NO;
|
||||
+ if (clampedX < 0) { clampedX = 0; needWarp = YES; }
|
||||
+ if (clampedX >= attrs.width) { clampedX = attrs.width - 1; needWarp = YES; }
|
||||
+ if (clampedY < 0) { clampedY = 0; needWarp = YES; }
|
||||
+ if (clampedY >= attrs.height) { clampedY = attrs.height - 1; needWarp = YES; }
|
||||
+ if (needWarp) {
|
||||
+ XWarpPointer(_display, None, _confinedWindow, 0, 0, 0, 0, clampedX, clampedY);
|
||||
+ XFlush(_display);
|
||||
+ ev->xmotion.x = clampedX;
|
||||
+ ev->xmotion.y = clampedY;
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (!_relativeMouse.active && window != nil) {
|
||||
+ [self updateMouseConfinementForWindow: window];
|
||||
+ }
|
||||
+
|
||||
CGPoint lastMotionPos = [window mouseLocationOutsideOfEventStream];
|
||||
pos = [window
|
||||
transformPoint: NSMakePoint(ev->xmotion.x, ev->xmotion.y)];
|
||||
|
||||
@@ -3464,7 +3495,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
mouseEventWithType: type
|
||||
location: pos
|
||||
modifierFlags:
|
||||
@@ -1211,28 +1918,49 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1211,28 +1945,61 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
clickCount: 1
|
||||
deltaX: deltaX
|
||||
deltaY: deltaY];
|
||||
@@ -3499,6 +3530,18 @@ index 5ae29bf4..5105e7d8 100644
|
||||
|
||||
case LeaveNotify:
|
||||
NSLog(@"LeaveNotify");
|
||||
+ if (_confinedWindow == [window windowHandle]) {
|
||||
+ Window win = [window windowHandle];
|
||||
+ XWindowAttributes attrs;
|
||||
+ if (XGetWindowAttributes(_display, win, &attrs)) {
|
||||
+ int cx = ev->xcrossing.x < 0 ? 0 : (ev->xcrossing.x >= attrs.width ? attrs.width - 1 : ev->xcrossing.x);
|
||||
+ int cy = ev->xcrossing.y < 0 ? 0 : (ev->xcrossing.y >= attrs.height ? attrs.height - 1 : ev->xcrossing.y);
|
||||
+ XWarpPointer(_display, None, win, 0, 0, 0, 0, cx, cy);
|
||||
+ XFlush(_display);
|
||||
+ }
|
||||
+ [self updateMouseConfinementForWindow: window];
|
||||
+ break;
|
||||
+ }
|
||||
+ if (!_relativeMouse.active && ev->xcrossing.detail != NotifyInferior) {
|
||||
+ [window setLastKnownCursorPosition:
|
||||
+ [window transformPoint: NSMakePoint(ev->xcrossing.x, ev->xcrossing.y)]];
|
||||
@@ -3516,7 +3559,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
NSLog(@"FocusIn");
|
||||
if ([delegate attachedSheet]) {
|
||||
[[delegate attachedSheet] makeKeyAndOrderFront: delegate];
|
||||
@@ -1243,28 +1971,55 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1243,28 +2010,67 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
checkForAppDeactivation: NO];
|
||||
lastFocusedWindow = nil;
|
||||
}
|
||||
@@ -3544,6 +3587,18 @@ index 5ae29bf4..5105e7d8 100644
|
||||
+ rclolFocusDetailName(ev->xfocus.detail), _relativeRequested, _relativeMouse.active,
|
||||
+ (unsigned long) _confinedWindow,
|
||||
+ [NSApp isActive]);
|
||||
+ if (ev->xfocus.detail == NotifyPointer || ev->xfocus.mode == NotifyGrab || ev->xfocus.mode == NotifyUngrab) {
|
||||
+ /* Pointer boundary crossing or grab transition in XWayland: do NOT release confinement or deactivate window */
|
||||
+ break;
|
||||
+ }
|
||||
+ {
|
||||
+ NSString *procName = [[NSProcessInfo processInfo] processName];
|
||||
+ BOOL isGame = (procName && [procName rangeOfString:@"League" options:NSCaseInsensitiveSearch].location != NSNotFound);
|
||||
+ if (isGame && [NSApp isActive]) {
|
||||
+ /* While League is the active app, do not drop confinement on transient XWayland focus events */
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
NSLog(@"FocusOut");
|
||||
+ [self reconcileModifierKeys:NULL window:delegate];
|
||||
+ _lastKeySym = 0;
|
||||
@@ -3574,7 +3629,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
O2Rect rect = NSMakeRect(ev->xexpose.x, ev->xexpose.y,
|
||||
ev->xexpose.width, ev->xexpose.height);
|
||||
|
||||
@@ -1301,11 +2056,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1301,11 +2107,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
break;
|
||||
|
||||
case UnmapNotify:
|
||||
@@ -3602,7 +3657,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
break;
|
||||
|
||||
case MapRequest:
|
||||
@@ -1321,6 +2088,7 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1321,6 +2139,7 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
[delegate platformWindow: window
|
||||
frameChanged: [window frame]
|
||||
didSize: YES];
|
||||
@@ -3610,7 +3665,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
break;
|
||||
|
||||
case ConfigureRequest:
|
||||
@@ -1344,6 +2112,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1344,6 +2163,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
break;
|
||||
|
||||
case PropertyNotify:
|
||||
@@ -3619,7 +3674,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
if ([window respondsToSelector: @selector(propertyNotify:)]) {
|
||||
[window propertyNotify: &ev->xproperty];
|
||||
}
|
||||
@@ -1399,7 +2169,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1399,7 +2220,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -3630,7 +3685,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
[self _invalidateRRCache];
|
||||
break;
|
||||
}
|
||||
@@ -1433,6 +2205,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
@@ -1433,6 +2256,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
|
||||
NSLog(@"Request code: %d:%d", errorEvent->request_code,
|
||||
errorEvent->minor_code);
|
||||
NSLog(@"Error code: %d", errorEvent->error_code);
|
||||
@@ -3641,7 +3696,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1476,54 +2252,271 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
|
||||
@@ -1476,54 +2303,271 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
|
||||
return frame;
|
||||
}
|
||||
|
||||
@@ -3687,8 +3742,8 @@ index 5ae29bf4..5105e7d8 100644
|
||||
- position.x, position.y);
|
||||
- XSync(_display, False);
|
||||
+ [self warpPointerToRootX: x y: y];
|
||||
+}
|
||||
+
|
||||
}
|
||||
|
||||
+/* Confinement preserves absolute motion and edge panning. Relative mode holds
|
||||
+ * its own grab and is left alone while requested. */
|
||||
+- (void) updateMouseConfinementForWindow:(X11Window *)window {
|
||||
@@ -3803,7 +3858,7 @@ index 5ae29bf4..5105e7d8 100644
|
||||
+ }
|
||||
+ if (getenv("RCLOL_INPUT_TRACE")) fprintf(stderr,"CONFINEMENT focus=%lu target=%lu ancestor=%lu fullscreen=%d\n",focus,win,ancestor,fullscreen);
|
||||
+
|
||||
+ BOOL isFocused = (ancestor == win || focus == win || (isGame && (focus == PointerRoot || focus == None || focus == DefaultRootWindow(_display))));
|
||||
+ BOOL isFocused = (ancestor == win || focus == win || (isGame && ([NSApp isActive] || focus == PointerRoot || focus == None || focus == DefaultRootWindow(_display))));
|
||||
+ if ((!fullscreen && !isGame) || attrs.map_state != IsViewable || !isFocused) {
|
||||
+ if (rclolTraceOn())
|
||||
+ rclolTraceRated(&rclolConfineChannel, "no confinement window=%lu fullscreen=%d ewmh=%d titled=%d size=%dx%d map_state=%d %s",
|
||||
@@ -3826,9 +3881,9 @@ index 5ae29bf4..5105e7d8 100644
|
||||
+ rclolTraceRated(&rclolConfineChannel, "confine window=%lu fullscreen=%d ewmh=%d size=%dx%d XGrabPointer=%d(%s)",
|
||||
+ (unsigned long) win, fullscreen, rclolEwmhFullscreen, attrs.width, attrs.height, status,
|
||||
+ rclolGrabResultName(status));
|
||||
+ if (status == GrabSuccess) _confinedWindow=win;
|
||||
}
|
||||
|
||||
+ if (status == GrabSuccess || status == AlreadyGrabbed) _confinedWindow=win;
|
||||
+}
|
||||
+
|
||||
+/* Takes the relative-mode pointer grab on the key (else main) window, starting with the virtual cursor at the
|
||||
+ * current pointer position. Returns the XGrabPointer result, or -1 without a window. */
|
||||
+- (int) beginRelativeMouseWithWindow: (NSWindow **) outWindow pick: (const char **) outPick {
|
||||
|
||||
@@ -22,3 +22,26 @@ except (OSError, StopIteration):
|
||||
if dead:
|
||||
os.replace(marker, prefix / f'.init.pid.stale-{pid}-{time.time_ns()}')
|
||||
print(f'Recovered stale Darling server marker for PID {pid}', flush=True)
|
||||
|
||||
# Clean up stale Riot temporary files and shared memory frames from previous crashes
|
||||
try:
|
||||
tmp_dir = prefix / 'private/tmp'
|
||||
if tmp_dir.is_dir():
|
||||
for f in tmp_dir.glob('.com.riotgames.*'):
|
||||
try:
|
||||
f.unlink(missing_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
try:
|
||||
shm_dir = Path('/dev/shm')
|
||||
if shm_dir.is_dir():
|
||||
for f in shm_dir.glob('darling-*'):
|
||||
try:
|
||||
f.unlink(missing_ok=True)
|
||||
except OSError:
|
||||
pass
|
||||
except OSError:
|
||||
pass
|
||||
Reference in new issue
Block a user