Files
SaraSuite/Programs/FletIdentity.py
T

68 lines
2.8 KiB
Python

"""Give a Flet program's window its own app ID on Linux, so the desktop can
match it to the program's .desktop entry (icon, name) instead of showing
every Flet program as "com.appveyor.flet" with a generic icon.
The Flet client's ID is a string built into its small launcher binary
(`flet`, ~24 KB); the client sets it as both its GTK application ID and its
process name, so Flet's own FLET_APP_ID (which only changes argv[0]) can't
override it, on Wayland or X11. Instead this makes a per-program copy of the
client in ~/.cache/SaraSuite/FletClient/ with that string replaced; the big
parts (lib/, data/, share/) are symlinks to the original, so a copy costs
~24 KB. Pointing FLET_VIEW_PATH at it makes Flet use the copy.
Used two ways:
- SaraSuite imports it and calls ClientFor() before ft.run.
- Installed programs' launchers run it with their own venv's python:
export FLET_VIEW_PATH="$(python FletIdentity.py srhtnin.SaraFem)"
It prints the copy's folder, or nothing if anything goes wrong, in which
case Flet just uses its normal client.
"""
import sys
from pathlib import Path
OriginalId = b"com.appveyor.flet"
CopiesDir = Path.home() / ".cache" / "SaraSuite" / "FletClient"
def ClientFor(AppId: str) -> str:
"""Folder of a client copy whose app ID is AppId ("" if not possible).
AppId needs a dot (a GTK rule) and at most 17 characters, the length of
the original it replaces in place."""
try:
Encoded = AppId.encode("ascii")
if "." not in AppId or not 0 < len(Encoded) <= len(OriginalId):
return ""
from flet_desktop import ensure_client_cached # the program's own Flet version
Original = Path(ensure_client_cached()) / "flet"
Binary = (Original / "flet").read_bytes()
Copy = CopiesDir / f"{Original.parent.name}-{AppId}" / "flet"
Patched = Binary.replace(
b"\x00" + OriginalId + b"\x00",
b"\x00" + Encoded.ljust(len(OriginalId), b"\x00") + b"\x00",
)
if Binary.count(b"\x00" + OriginalId + b"\x00") != 1:
return "" # not the client layout this was written for
Target = Copy / "flet"
if not (Target.exists() and Target.read_bytes() == Patched):
Copy.mkdir(parents=True, exist_ok=True)
for Part in ("lib", "data", "share"):
Link = Copy / Part
if Link.is_symlink() or Link.exists():
Link.unlink()
if (Original / Part).exists():
Link.symlink_to(Original / Part)
Temporary = Target.with_suffix(".new")
Temporary.write_bytes(Patched)
Temporary.chmod(0o755)
Temporary.replace(Target)
return str(Copy)
except Exception:
return ""
if __name__ == "__main__":
print(ClientFor(sys.argv[1]) if len(sys.argv) > 1 else "")