Fix in-game keyboard input, initial fullscreen black screen, and desktop launcher icon

This commit is contained in:
Andras Laszlo committed 2026-10-16 17:40:51 +02:00
1 parent 4699618e9f
commit d981cbe8c3
2 files changed
+99 -47

No files matched your search

+81 -42
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..c0361b56 100644
index 5ae29bf4..516decf3 100644
--- a/AppKit/X11.backend/X11Display.m
+++ b/AppKit/X11.backend/X11Display.m
@@ -48,12 +48,271 @@
@@ -3232,7 +3232,20 @@ index 5ae29bf4..c0361b56 100644
NSEventModifierFlags modifierFlags = [self modifierFlagsForState: ev->xkey.state];
char buf[20] = {0};
KeySym keySym;
@@ -1038,6 +1674,18 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1030,7 +1666,11 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
if (ev->type == KeyPress) {
- strLen = Xutf8LookupString(window->_xic, (XKeyPressedEvent *) ev, buf, sizeof(buf) - 1, &keySym, NULL);
+ if (window && window->_xic) {
+ strLen = Xutf8LookupString(window->_xic, (XKeyPressedEvent *) ev, buf, sizeof(buf) - 1, &keySym, NULL);
+ } else {
+ strLen = XLookupString((XKeyEvent*) ev, buf, sizeof(buf) - 1, &keySym, NULL);
+ }
buf[strLen] = 0;
} else {
// Xutf8LookupString() may not be used with KeyRelease
@@ -1038,6 +1678,18 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
buf[strLen] = 0;
}
@@ -3251,12 +3264,30 @@ index 5ae29bf4..c0361b56 100644
id str = [[NSString alloc] initWithCString: buf
encoding: NSUTF8StringEncoding];
NSPoint pos =
@@ -1077,6 +1725,33 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1077,6 +1729,51 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
case ButtonPress:;
+ if (window && !_confinedWindow) {
+ [self updateMouseConfinementForWindow: window];
+ if (window) {
+ Window win = [window windowHandle];
+ XSetInputFocus(_display, win, RevertToPointerRoot, ev->xbutton.time);
+ if (window->_xic)
+ XSetICFocus(window->_xic);
+ Atom activeAtom = XInternAtom(_display, "_NET_ACTIVE_WINDOW", False);
+ XClientMessageEvent act = {0};
+ act.type = ClientMessage;
+ act.window = win;
+ act.message_type = activeAtom;
+ act.format = 32;
+ act.data.l[0] = 1;
+ act.data.l[1] = ev->xbutton.time;
+ XSendEvent(_display, DefaultRootWindow(_display), False,
+ SubstructureNotifyMask | SubstructureRedirectMask,
+ (XEvent *)&act);
+ XFlush(_display);
+ if (!_confinedWindow) {
+ [self updateMouseConfinementForWindow: window];
+ }
+ }
+ if (ev->xbutton.button >= Button4 && ev->xbutton.button <= 7) {
+ pos = [self locationInWindow: window x: ev->xbutton.x y: ev->xbutton.y
@@ -3285,7 +3316,7 @@ index 5ae29bf4..c0361b56 100644
NSTimeInterval now = [[NSDate date] timeIntervalSinceReferenceDate];
if (now - lastClickTimeStamp < [self doubleClickInterval]) {
@@ -1086,8 +1761,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1086,8 +1783,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
}
lastClickTimeStamp = now;
@@ -3296,7 +3327,7 @@ index 5ae29bf4..c0361b56 100644
switch (ev->xbutton.button) {
case Button1:
@@ -1096,10 +1771,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1096,10 +1793,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
case Button3:
type = NSRightMouseDown;
break;
@@ -3307,7 +3338,7 @@ index 5ae29bf4..c0361b56 100644
default:
type = NSOtherMouseDown;
}
@@ -1113,14 +1784,22 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1113,14 +1806,22 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
clickCount: clickCount
deltaX: 0.0
deltaY: 0.0];
@@ -3334,7 +3365,7 @@ index 5ae29bf4..c0361b56 100644
CGFloat deltaY = 0.0;
switch (ev->xbutton.button) {
@@ -1130,14 +1809,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1130,14 +1831,6 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
case Button3:
type = NSRightMouseUp;
break;
@@ -3349,7 +3380,7 @@ index 5ae29bf4..c0361b56 100644
default:
type = NSOtherMouseUp;
}
@@ -1151,7 +1822,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1151,7 +1844,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
clickCount: clickCount
deltaX: 0.0
deltaY: deltaY];
@@ -3360,7 +3391,7 @@ index 5ae29bf4..c0361b56 100644
[self postEvent: event atStart: NO];
break;
@@ -1160,49 +1833,113 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1160,49 +1855,113 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
// ev->xmotion.x, ev->xmotion.y, ev->xmotion.x_root,
// ev->xmotion.y_root);
@@ -3500,7 +3531,7 @@ index 5ae29bf4..c0361b56 100644
mouseEventWithType: type
location: pos
modifierFlags:
@@ -1211,28 +1948,58 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1211,28 +1970,58 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
clickCount: 1
deltaX: deltaX
deltaY: deltaY];
@@ -3561,7 +3592,7 @@ index 5ae29bf4..c0361b56 100644
NSLog(@"FocusIn");
if ([delegate attachedSheet]) {
[[delegate attachedSheet] makeKeyAndOrderFront: delegate];
@@ -1243,28 +2010,67 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1243,28 +2032,59 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
checkForAppDeactivation: NO];
lastFocusedWindow = nil;
}
@@ -3592,14 +3623,6 @@ index 5ae29bf4..c0361b56 100644
+ 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];
@@ -3631,7 +3654,7 @@ index 5ae29bf4..c0361b56 100644
O2Rect rect = NSMakeRect(ev->xexpose.x, ev->xexpose.y,
ev->xexpose.width, ev->xexpose.height);
@@ -1301,11 +2107,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1301,11 +2121,23 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
case UnmapNotify:
@@ -3659,7 +3682,7 @@ index 5ae29bf4..c0361b56 100644
break;
case MapRequest:
@@ -1317,10 +2135,15 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1317,10 +2149,15 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
case ConfigureNotify:
@@ -3675,7 +3698,7 @@ index 5ae29bf4..c0361b56 100644
break;
case ConfigureRequest:
@@ -1344,6 +2167,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1344,6 +2181,8 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
case PropertyNotify:
@@ -3684,7 +3707,7 @@ index 5ae29bf4..c0361b56 100644
if ([window respondsToSelector: @selector(propertyNotify:)]) {
[window propertyNotify: &ev->xproperty];
}
@@ -1399,7 +2224,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1399,7 +2238,9 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
break;
default:
@@ -3695,7 +3718,7 @@ index 5ae29bf4..c0361b56 100644
[self _invalidateRRCache];
break;
}
@@ -1433,6 +2260,10 @@ static NSDictionary *modeInfoToDictionary(const XRRModeInfo *mi, int depth) {
@@ -1433,6 +2274,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);
@@ -3706,7 +3729,7 @@ index 5ae29bf4..c0361b56 100644
return 0;
}
@@ -1476,54 +2307,286 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
@@ -1476,54 +2321,286 @@ void CGNativeBorderFrameWidthsForStyle(NSUInteger styleMask, CGFloat *top,
return frame;
}
@@ -3891,7 +3914,7 @@ index 5ae29bf4..c0361b56 100644
+ return;
+ }
+ unsigned mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask;
+ int status=XGrabPointer(_display, win, False, mask, GrabModeAsync, GrabModeAsync,
+ int status=XGrabPointer(_display, win, True, mask, GrabModeAsync, GrabModeAsync,
+ win, None, CurrentTime);
+ if (getenv("RCLOL_INPUT_TRACE")) fprintf(stderr,"CONFINEMENT fullscreen=%d window=%lu result=%d\n",fullscreen,win,status);
+ if (rclolTraceOn())
@@ -4429,7 +4452,7 @@ index bfe3839a..dbc974a0 100644
- (void) frameChanged;
- (void) setLastKnownCursorPosition: (CGPoint) point;
diff --git a/AppKit/X11.backend/X11Window.m b/AppKit/X11.backend/X11Window.m
index f4925b66..04fa8146 100644
index f4925b66..af6df163 100644
--- a/AppKit/X11.backend/X11Window.m
+++ b/AppKit/X11.backend/X11Window.m
@@ -38,6 +38,34 @@
@@ -4580,7 +4603,23 @@ index f4925b66..04fa8146 100644
}
XSetWMSizeHints(_display, _window, sh, XA_WM_NORMAL_HINTS);
@@ -338,7 +423,6 @@ static NSData *makeWindowIcon() {
@@ -304,7 +389,14 @@ static NSData *makeWindowIcon() {
states[states_cnt++] =
(long) XInternAtom(_display, "_NET_WM_STATE_MODAL", False);
}
- if (mask & NSWindowStyleMaskFullScreen) {
+ NSString *procName = [[NSProcessInfo processInfo] processName];
+ BOOL isGame = (procName && [procName rangeOfString:@"League" options:NSCaseInsensitiveSearch].location != NSNotFound &&
+ [procName rangeOfString:@"Ux" options:NSCaseInsensitiveSearch].location == NSNotFound);
+ BOOL makeFullscreen = (mask & NSWindowStyleMaskFullScreen) != 0;
+ if (!makeFullscreen && isGame && (mask == NSBorderlessWindowMask || !(mask & NSTitledWindowMask))) {
+ makeFullscreen = YES;
+ }
+ if (makeFullscreen) {
states[states_cnt++] = (long) XInternAtom(
_display, "_NET_WM_STATE_FULLSCREEN", False);
}
@@ -338,7 +430,6 @@ static NSData *makeWindowIcon() {
}
+ (void) removeDecorationForWindow: (Window) w onDisplay: (Display *) dpy {
@@ -4588,7 +4627,7 @@ index f4925b66..04fa8146 100644
struct {
unsigned long flags;
unsigned long functions;
@@ -358,6 +442,7 @@ static NSData *makeWindowIcon() {
@@ -358,6 +449,7 @@ static NSData *makeWindowIcon() {
if (!_mapped) {
XMapWindow(_display, _window);
_mapped = YES;
@@ -4596,7 +4635,7 @@ index f4925b66..04fa8146 100644
}
}
@@ -377,15 +462,27 @@ static NSData *makeWindowIcon() {
@@ -377,15 +469,27 @@ static NSData *makeWindowIcon() {
- (void) syncDelegateProperties {
long mask = KeyPressMask | KeyReleaseMask | ExposureMask |
StructureNotifyMask | EnterWindowMask | LeaveWindowMask |
@@ -4629,7 +4668,7 @@ index f4925b66..04fa8146 100644
// TODO: background color
}
@@ -393,6 +490,28 @@ static NSData *makeWindowIcon() {
@@ -393,6 +497,28 @@ static NSData *makeWindowIcon() {
// This is essentially dealloc; we release our contexts
// and windows, but unlike dealloc, this method can be called
// several times, so set everything to nil/NULL/0.
@@ -4658,7 +4697,7 @@ index f4925b66..04fa8146 100644
[_context release];
_context = nil;
@@ -421,6 +540,388 @@ static NSData *makeWindowIcon() {
@@ -421,6 +547,388 @@ static NSData *makeWindowIcon() {
}
}
@@ -5047,7 +5086,7 @@ index f4925b66..04fa8146 100644
- (Window) windowHandle {
return _window;
}
@@ -470,14 +971,31 @@ static NSData *makeWindowIcon() {
@@ -470,14 +978,31 @@ static NSData *makeWindowIcon() {
const char *text = [title cString];
XStringListToTextProperty((char **) &text, 1, &prop);
XSetWMName(_display, _window, &prop);
@@ -5080,7 +5119,7 @@ index f4925b66..04fa8146 100644
}
- (void) setHasShadow: (BOOL) value {
@@ -488,6 +1006,25 @@ static NSData *makeWindowIcon() {
@@ -488,6 +1013,25 @@ static NSData *makeWindowIcon() {
_level = value;
}
@@ -5106,7 +5145,7 @@ index f4925b66..04fa8146 100644
- (void) setOpaque: (BOOL) value {
_isOpaque = value;
}
@@ -543,6 +1080,18 @@ static NSData *makeWindowIcon() {
@@ -543,6 +1087,18 @@ static NSData *makeWindowIcon() {
- (void) makeKey {
[self ensureMapped];
XRaiseWindow(_display, _window);
@@ -5125,7 +5164,7 @@ index f4925b66..04fa8146 100644
}
- (void) makeMain {
@@ -559,7 +1108,29 @@ static NSData *makeWindowIcon() {
@@ -559,7 +1115,29 @@ static NSData *makeWindowIcon() {
XRaiseWindow(_display, _window);
}
@@ -5155,7 +5194,7 @@ index f4925b66..04fa8146 100644
Atom wmState = XInternAtom(_display, "_NET_WM_STATE", FALSE);
Atom hiddenState = XInternAtom(_display, "_NET_WM_STATE_HIDDEN", FALSE);
@@ -615,6 +1186,12 @@ static NSData *makeWindowIcon() {
@@ -615,6 +1193,12 @@ static NSData *makeWindowIcon() {
}
- (void) openGLFlushBuffer {
@@ -5168,7 +5207,7 @@ index f4925b66..04fa8146 100644
CGLError error;
CGLContextObj prevContext = CGLGetCurrentContext();
@@ -652,7 +1229,7 @@ static NSData *makeWindowIcon() {
@@ -652,7 +1236,7 @@ static NSData *makeWindowIcon() {
}
- (O2Rect) frame {
@@ -5177,7 +5216,7 @@ index f4925b66..04fa8146 100644
}
static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
@@ -666,6 +1243,7 @@ static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
@@ -666,6 +1250,7 @@ static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
}
- (void) frameChanged {
@@ -5185,7 +5224,7 @@ index f4925b66..04fa8146 100644
XErrorHandler previousHandler = XSetErrorHandler(ignoreBadWindow);
@try {
Window root, parent;
@@ -710,14 +1288,6 @@ static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
@@ -710,14 +1295,6 @@ static int ignoreBadWindow(Display *display, XErrorEvent *errorEvent) {
[_deviceDictionary addEntriesFromDictionary: entries];
}
+18 -5
View File
@@ -148,12 +148,13 @@ Name=League of Legends
GenericName=MOBA Game
Comment=Play League of Legends on Linux with darling-lol
Exec={run_script}
Path={PROJECT_ROOT}
Icon=league-of-legends
Terminal=false
Categories=Game;ActionGame;StrategyGame;
Keywords=riot;league;lol;darling;games;
StartupWMClass=League of Legends
StartupNotify=true
StartupWMClass=Riot Client
StartupNotify=false
"""
desktop_file = apps_base / "league-of-legends.desktop"
@@ -161,11 +162,23 @@ StartupNotify=true
os.chmod(desktop_file, 0o755)
print(f"Created application launcher: {desktop_file}")
if desktop_dir.is_dir():
desktop_shortcut = desktop_dir / "league-of-legends.desktop"
target_desktop_dirs = []
try:
res = subprocess.run(["xdg-user-dir", "DESKTOP"], capture_output=True, text=True, check=False)
if res.returncode == 0 and res.stdout.strip():
d = Path(res.stdout.strip())
if d.is_dir() and d not in target_desktop_dirs:
target_desktop_dirs.append(d)
except Exception:
pass
for cand in [HOST_HOME / "Desktop", HOST_HOME / "Asztal"]:
if cand.is_dir() and cand not in target_desktop_dirs:
target_desktop_dirs.append(cand)
for ddir in target_desktop_dirs:
desktop_shortcut = ddir / "league-of-legends.desktop"
desktop_shortcut.write_text(desktop_content)
os.chmod(desktop_shortcut, 0o755)
# Mark as trusted on GNOME Desktop if gio is available
gio = shutil.which("gio")
if gio:
subprocess.run([gio, "set", str(desktop_shortcut), "metadata::trusted", "true"], check=False)