diff --git a/scripts/create-desktop-entry.sh b/scripts/create-desktop-entry.sh new file mode 100755 index 0000000..81b8c22 --- /dev/null +++ b/scripts/create-desktop-entry.sh @@ -0,0 +1,7 @@ +#!/bin/sh +# Create/update GNOME desktop entry and launcher icon. +set -eu +repo=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd) +cd "$repo" +python3 scripts/configure.py >/dev/null +python3 build/runtime/tools/riot-desktop-entry.py diff --git a/scripts/install-runtime.sh b/scripts/install-runtime.sh index 2fccf55..278244e 100755 --- a/scripts/install-runtime.sh +++ b/scripts/install-runtime.sh @@ -20,3 +20,7 @@ if [ -f build/runtime/tools/build-riot-libs-runtime.sh ]; then python3 build/runtime/tools/install-riot-libs-runtime.py fi python3 build/runtime/tools/install-darling-system-profiler.py +# darling-lol: install GNOME application launcher and icon. +if [ -f build/runtime/tools/riot-desktop-entry.py ]; then + python3 build/runtime/tools/riot-desktop-entry.py || true +fi diff --git a/scripts/installer.sh b/scripts/installer.sh index c7520eb..d9d1268 100755 --- a/scripts/installer.sh +++ b/scripts/installer.sh @@ -14,10 +14,12 @@ export RIOT_LAUNCHER_HOST RCLOL_REGION # client fails under Darling, so start the installed client here. sh scripts/run.sh || true unset RIOT_LAUNCHER_HOST +python3 build/runtime/tools/riot-desktop-entry.py || true prefix=${DPREFIX:-$HOME/.darling} if [ ! -d "$prefix/Users/Shared/Riot Games/Riot Client.app/Contents/MacOS" ]; then echo "The installer exited without installing the Riot Client. Its logs are in" >&2 echo "$prefix/Users//Library/Logs/Riot Games/Install League of Legends $region/Launcher" >&2 exit 1 fi +python3 build/runtime/tools/riot-desktop-entry.py || true exec sh scripts/run.sh diff --git a/tools/riot-desktop-entry.py b/tools/riot-desktop-entry.py new file mode 100755 index 0000000..1458bfb --- /dev/null +++ b/tools/riot-desktop-entry.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +"""Create and install the GNOME / FreeDesktop desktop entry and launcher icon.""" +import os +import shutil +import subprocess +import sys +from pathlib import Path + +PROJECT_ROOT = Path("@PROJECT_ROOT@") +HOST_HOME = Path("@HOST_HOME@") +DPREFIX = Path("@DPREFIX@") + +SVG_ICON_CONTENT = """ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +""" + + +def extract_best_png_from_icns(icns_path: Path) -> bytes | None: + """Extract the highest-resolution embedded PNG from an Apple ICNS file.""" + try: + data = icns_path.read_bytes() + if not data.startswith(b"icns"): + return None + offset = 8 + best_png = None + best_len = 0 + while offset + 8 <= len(data): + size = int.from_bytes(data[offset + 4 : offset + 8], "big") + if size < 8 or offset + size > len(data): + break + chunk = data[offset + 8 : offset + size] + if chunk.startswith(b"\x89PNG\r\n\x1a\n") and len(chunk) > best_len: + best_png = chunk + best_len = len(chunk) + offset += size + return best_png + except Exception: + return None + + +def find_candidate_icns() -> Path | None: + """Find any available Riot or League .icns icon files.""" + candidates = [ + *list((PROJECT_ROOT / "build/installer").glob("*League of Legends*.app/Contents/Resources/*.icns")), + *list(DPREFIX.glob("Users/Shared/Riot Games/Riot Client.app/Contents/Resources/*.icns")), + *list(DPREFIX.glob("Applications/Riot Client.app/Contents/Resources/*.icns")), + *list(DPREFIX.glob("Applications/League of Legends.app/Contents/Resources/*.icns")), + ] + for c in candidates: + if c.is_file() and c.stat().st_size > 1024: + return c + return None + + +def main(): + icons_base = HOST_HOME / ".local/share/icons" + apps_base = HOST_HOME / ".local/share/applications" + desktop_dir = HOST_HOME / "Desktop" + + scalable_dir = icons_base / "hicolor/scalable/apps" + png_dir = icons_base / "hicolor/512x512/apps" + scalable_dir.mkdir(parents=True, exist_ok=True) + png_dir.mkdir(parents=True, exist_ok=True) + apps_base.mkdir(parents=True, exist_ok=True) + + # 1. Install scalable SVG icon + svg_target = scalable_dir / "league-of-legends.svg" + svg_target.write_text(SVG_ICON_CONTENT) + shutil.copyfile(svg_target, icons_base / "league-of-legends.svg") + + # 2. Extract or generate PNG icon + png_target = png_dir / "league-of-legends.png" + icns_file = find_candidate_icns() + extracted = False + if icns_file: + png_data = extract_best_png_from_icns(icns_file) + if png_data: + png_target.write_bytes(png_data) + shutil.copyfile(png_target, icons_base / "league-of-legends.png") + extracted = True + print(f"Extracted official icon from {icns_file.name} to {png_target}") + + if not extracted and not png_target.exists(): + # Try to rasterize SVG via rsvg-convert or magick + rsvg = shutil.which("rsvg-convert") + magick = shutil.which("magick") or shutil.which("convert") + if rsvg: + subprocess.run([rsvg, "-w", "512", "-h", "512", str(svg_target), "-o", str(png_target)], check=False) + if png_target.exists(): + shutil.copyfile(png_target, icons_base / "league-of-legends.png") + elif magick: + subprocess.run([magick, "-background", "none", "-resize", "512x512", str(svg_target), str(png_target)], check=False) + if png_target.exists(): + shutil.copyfile(png_target, icons_base / "league-of-legends.png") + + # 3. Create .desktop file + run_script = PROJECT_ROOT / "scripts/run.sh" + 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={run_script} +Icon=league-of-legends +Terminal=false +Categories=Game;ActionGame;StrategyGame; +Keywords=riot;league;lol;darling;games; +StartupWMClass=League of Legends +StartupNotify=true +""" + + desktop_file = apps_base / "league-of-legends.desktop" + desktop_file.write_text(desktop_content) + 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" + 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) + print(f"Created desktop shortcut: {desktop_shortcut}") + + # 4. Refresh icon and desktop databases + update_desktop = shutil.which("update-desktop-database") + if update_desktop: + subprocess.run([update_desktop, str(apps_base)], check=False) + + update_icons = shutil.which("gtk-update-icon-cache") + if update_icons: + subprocess.run([update_icons, "-f", "-t", str(icons_base / "hicolor")], check=False) + + print("GNOME application launcher and icon installed successfully.") + + +if __name__ == "__main__": + main()