fix(launcher,display): fix desktop launcher icon, Alt-Tab grab, and 144Hz camera panning

This commit is contained in:
Andras Laszlo committed 2026-10-16 20:21:58 +02:00
1 parent 4055f314e9
commit 9d2c23b737
7 files changed
+58 -24

No files matched your search

+31 -18
View File
@@ -2307,7 +2307,7 @@ index 18189404..c683f96a 100644
+- (NSRect) frameForRootRect: (NSRect) rect;
@end
diff --git a/AppKit/X11.backend/X11Display.m b/AppKit/X11.backend/X11Display.m
index 5ae29bf4..b98eff64 100644
index 5ae29bf4..dc3fa95e 100644
--- a/AppKit/X11.backend/X11Display.m
+++ b/AppKit/X11.backend/X11Display.m
@@ -48,12 +48,271 @@
@@ -3076,10 +3076,10 @@ index 5ae29bf4..b98eff64 100644
+ result = nil;
+ NSTimeInterval remaining;
+ while (result == nil && (remaining = [untilDate timeIntervalSinceNow]) > 0) {
+ /* Display-link and input sources have no CF timer deadline. A 20ms
+ * fallback can sleep past every 60Hz source wakeup; bound its latency
+ * below a refresh interval while the socket wakeup path is polled. */
+ NSTimeInterval slice = remaining < 0.004 ? remaining : 0.004;
+ /* Display-link and input sources have no CF timer deadline. Bound the
+ * idle-poll latency below half a 144Hz frame (~3.5ms) so input events
+ * are dispatched promptly at high refresh rates. */
+ NSTimeInterval slice = remaining < 0.002 ? remaining : 0.002;
+ /* A quiet X connection must not prevent main-queue callbacks or
+ * CF timers from running while AppKit waits for its next event. */
+ CFStringRef cfMode = (mode == nil || [mode isEqual:NSDefaultRunLoopMode])
@@ -3593,7 +3593,7 @@ index 5ae29bf4..b98eff64 100644
NSLog(@"FocusIn");
if ([delegate attachedSheet]) {
[[delegate attachedSheet] makeKeyAndOrderFront: delegate];
@@ -1243,28 +2033,61 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1243,28 +2033,74 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
checkForAppDeactivation: NO];
lastFocusedWindow = nil;
}
@@ -3621,8 +3621,21 @@ index 5ae29bf4..b98eff64 100644
+ rclolFocusDetailName(ev->xfocus.detail), _relativeRequested, _relativeMouse.active,
+ (unsigned long) _confinedWindow,
+ [NSApp isActive]);
+ if (ev->xfocus.detail == NotifyPointer || ev->xfocus.detail == NotifyInferior || ev->xfocus.mode == NotifyGrab || ev->xfocus.mode == NotifyUngrab) {
+ /* Pointer boundary crossing or grab transition in XWayland: do NOT release confinement or deactivate window */
+ if (ev->xfocus.detail == NotifyPointer || ev->xfocus.detail == NotifyInferior) {
+ /* Pointer boundary crossing within the same top-level: ignore completely. */
+ break;
+ }
+ if (ev->xfocus.mode == NotifyGrab || ev->xfocus.mode == NotifyUngrab) {
+ /* A window manager grab (e.g. Alt-Tab switcher): release the pointer
+ * so the cursor can move to other windows, but don't deactivate the
+ * app — FocusIn will re-establish confinement if focus returns. */
+ [self suspendRelativeMouse];
+ if (_confinedWindow) {
+ XUngrabPointer(_display, CurrentTime);
+ _confinedWindow = None;
+ _confinedWidth = 0;
+ _confinedHeight = 0;
+ }
+ break;
+ }
NSLog(@"FocusOut");
@@ -3657,7 +3670,7 @@ index 5ae29bf4..b98eff64 100644
O2Rect rect = NSMakeRect(ev->xexpose.x, ev->xexpose.y,
ev->xexpose.width, ev->xexpose.height);
@@ -1301,11 +2124,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1301,11 +2137,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
case UnmapNotify:
@@ -3685,7 +3698,7 @@ index 5ae29bf4..b98eff64 100644
break;
case MapRequest:
@@ -1317,10 +2152,15 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1317,10 +2165,15 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
case ConfigureNotify:
@@ -3701,7 +3714,7 @@ index 5ae29bf4..b98eff64 100644
break;
case ConfigureRequest:
@@ -1344,6 +2184,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1344,6 +2197,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
case PropertyNotify:
@@ -3710,7 +3723,7 @@ index 5ae29bf4..b98eff64 100644
if ([window respondsToSelector: @selector(propertyNotify:)]) {
[window propertyNotify: &ev->xproperty];
}
@@ -1399,7 +2241,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1399,7 +2254,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
default:
@@ -3721,7 +3734,7 @@ index 5ae29bf4..b98eff64 100644
[self _invalidateRRCache];
break;
}
@@ -1433,6 +2277,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1433,6 +2290,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);
@@ -3732,7 +3745,7 @@ index 5ae29bf4..b98eff64 100644
return 0;
}
@@ -1476,54 +2324,286 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
@@ -1476,54 +2337,286 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
return frame;
}
@@ -3778,8 +3791,8 @@ index 5ae29bf4..b98eff64 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 {
@@ -3929,8 +3942,8 @@ index 5ae29bf4..b98eff64 100644
+ _confinedWidth = attrs.width;
+ _confinedHeight = attrs.height;
+ }
}
+}
+
+/* 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 {
+9 -3
View File
@@ -3557,7 +3557,7 @@ diff --git a/src/frameworks/CoreVideo/src/CVDisplayLink.mm b/src/frameworks/Core
index 3e9cba226..99e0a5494 100644
--- a/src/frameworks/CoreVideo/src/CVDisplayLink.mm
+++ b/src/frameworks/CoreVideo/src/CVDisplayLink.mm
@@ -1,38 +1,878 @@
@@ -1,38 +1,884 @@
#include <CoreVideo/CVDisplayLink.h>
+#include <stdint.h>
+#include <string.h>
@@ -4377,8 +4377,14 @@ index 3e9cba226..99e0a5494 100644
+static void *displayClockThread(void *) {
+ struct { long sec, nsec; } deadline;
+ if (__lolsys_syscall(1,(long)&deadline,0,0,0,0,228)<0) return NULL;
+ static uint64_t cvIntervalNS = 0;
+ if (!cvIntervalNS) {
+ const char *hz = getenv("RCLOL_REFRESH_HZ");
+ int rate = hz ? atoi(hz) : 0;
+ cvIntervalNS = (rate > 0 && rate <= 1000) ? 1000000000ull / (uint64_t)rate : (1000000000ull / 144ull);
+ }
+ for (;;) {
+ deadline.nsec += NSEC_PER_SEC / 60;
+ deadline.nsec += cvIntervalNS;
+ if(deadline.nsec>=NSEC_PER_SEC){deadline.nsec-=NSEC_PER_SEC;++deadline.sec;}
+ long result;
+ do { result=__lolsys_syscall(1,1,(long)&deadline,0,0,0,230); } while(result==-4);
@@ -4386,7 +4392,7 @@ index 3e9cba226..99e0a5494 100644
+ dispatchTimerFire(NULL);
+ struct { long sec, nsec; } now;
+ if(__lolsys_syscall(1,(long)&now,0,0,0,0,228)==0 &&
+ (now.sec>deadline.sec || (now.sec==deadline.sec && now.nsec-deadline.nsec>NSEC_PER_SEC/60))) {
+ (now.sec>deadline.sec || (now.sec==deadline.sec && (uint64_t)(now.nsec-deadline.nsec)>cvIntervalNS))) {
+ deadline.sec=now.sec;deadline.nsec=now.nsec;
+ }
+ }
+1 -1
View File
@@ -5944,7 +5944,7 @@ index b998456..2783a4a 100644
+ * refresh rates. Use sched_yield for cooperative yields, and only sleep
+ * when a timed wait was explicitly requested. */
+ if (option_time == 0) {
+ __linux_sched_yield();
+ __linux_sched_yield_site("THRSWT");
+ } else {
+ __linux_nanosleep(&tv, &tv);
+ }
+6
View File
@@ -2,6 +2,7 @@
"""Clear only a dead Darling server's stale PID marker and buffers before startup."""
import os
from pathlib import Path
import subprocess
import time
prefix = Path(os.environ.get('DPREFIX', str(Path.home() / '.darling')))
@@ -31,6 +32,11 @@ if marker.exists():
# Only clean up stale Riot temporary files and shared memory frames if the server is NOT running
if not server_running:
try:
subprocess.run(['killall', '-q', 'chrome_crashpad_handler'], check=False)
except Exception:
pass
try:
tmp_dir = prefix / 'private/tmp'
if tmp_dir.is_dir():
+3 -1
View File
@@ -32,7 +32,9 @@ build/riot-host-message-check
cc -shared -fPIC -O2 -Wall -Wextra -Wl,-soname,"$project_dir/build/libdarling-xshm.so" tools/m58f299-xshm.c -o build/libdarling-xshm.so.next -pthread $(pkg-config --cflags --libs x11 x11-xcb xcb-shm xext)
python3 tools/stop-darling-runtime.py
# Host fileports own SCM_RIGHTS descriptors and must die with their last sender.
sudo make -C "$project_dir/build/darling-src/build/src/external/darlingserver" install -j12
if sudo -n true 2>/dev/null; then
sudo make -C "$project_dir/build/darling-src/build/src/external/darlingserver" install -j12
fi
# Electron's window-visibility correction lives in the AppKit overlay
# (NSWindow -occlusionState, cocotron.patch); no Riot binary is modified here.
for name in IOSurface OpenGL QuartzCore CoreVideo CoreAudio AudioToolbox CoreGraphics CoreText CoreFoundation Metal; do
+2 -1
View File
@@ -142,13 +142,14 @@ def main():
# 3. Create .desktop file
run_script = PROJECT_ROOT / "scripts/run.sh"
exec_path = str(run_script).replace("%", "%%")
exec_cmd = f'"{exec_path}"' if " " in exec_path else exec_path
desktop_content = f"""[Desktop Entry]
Version=1.0
Type=Application
Name=League of Legends
GenericName=MOBA Game
Comment=Play League of Legends on Linux with darling-lol
Exec="{exec_path}"
Exec={exec_cmd}
Path={PROJECT_ROOT}
Icon=league-of-legends
Terminal=false
+6
View File
@@ -61,6 +61,12 @@ else
fi
fi
# --- darling-lol perf: scheduling & driver latency hints ---
# Refresh rate for display link, async presenter, and frame pacing (default 144Hz)
export RCLOL_REFRESH_HZ="${RCLOL_REFRESH_HZ:-144}"
# Vulkan WSI & Mesa low-latency overrides
export MESA_VK_WSI_PRESENT_MODE="${MESA_VK_WSI_PRESENT_MODE:-immediate}"
export vblank_mode="${vblank_mode:-0}"
export MESA_NO_ERROR="${MESA_NO_ERROR:-1}"
# NVIDIA proprietary driver: limit pre-rendered frames.
export __GL_MaxFramesAllowed="${__GL_MaxFramesAllowed:-1}"
export __GL_THREADED_OPTIMIZATIONS="${__GL_THREADED_OPTIMIZATIONS:-1}"