Add startup application picker
This commit is contained in:
@@ -37,8 +37,8 @@ def xdg_data_roots() -> list[Path]:
|
||||
return [data_home, *(Path(item) for item in data_dirs.split(":") if item)]
|
||||
|
||||
|
||||
def discovered_desktop_ids() -> set[str]:
|
||||
desktop_ids: set[str] = set()
|
||||
def discovered_desktop_files() -> dict[str, Path]:
|
||||
desktop_files: dict[str, Path] = {}
|
||||
for root in xdg_data_roots():
|
||||
applications = root / "applications"
|
||||
if not applications.is_dir():
|
||||
@@ -47,8 +47,12 @@ def discovered_desktop_ids() -> set[str]:
|
||||
if not path.is_file():
|
||||
continue
|
||||
relative = path.relative_to(applications)
|
||||
desktop_ids.add("-".join(relative.parts))
|
||||
return desktop_ids
|
||||
desktop_files.setdefault("-".join(relative.parts), path)
|
||||
return desktop_files
|
||||
|
||||
|
||||
def discovered_desktop_ids() -> set[str]:
|
||||
return set(discovered_desktop_files())
|
||||
|
||||
|
||||
def require_desktop_id(desktop_id: str, *, discovered: set[str]) -> None:
|
||||
@@ -184,12 +188,7 @@ def set_default(role: str, desktop_id: str) -> None:
|
||||
run(command)
|
||||
|
||||
|
||||
def update_hidden(path: Path, *, hidden: bool) -> None:
|
||||
try:
|
||||
original = path.read_text(encoding="utf-8")
|
||||
except (OSError, UnicodeError) as error:
|
||||
raise BoundaryError("That autostart entry could not be read.") from error
|
||||
|
||||
def with_hidden(original: str, *, hidden: bool) -> str:
|
||||
lines = original.splitlines()
|
||||
output: list[str] = []
|
||||
section = ""
|
||||
@@ -216,24 +215,63 @@ def update_hidden(path: Path, *, hidden: bool) -> None:
|
||||
raise BoundaryError("That autostart entry is not a desktop file.")
|
||||
if not wrote_hidden:
|
||||
output.append(f"Hidden={'true' if hidden else 'false'}")
|
||||
return "\n".join(output) + "\n"
|
||||
|
||||
mode = path.stat().st_mode
|
||||
|
||||
def write_atomic(path: Path, text: str, *, mode: int) -> None:
|
||||
temporary_path: Path | None = None
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(
|
||||
"w", encoding="utf-8", dir=path.parent, prefix=f".{path.name}.", delete=False
|
||||
) as temporary:
|
||||
temporary.write("\n".join(output) + "\n")
|
||||
temporary.write(text)
|
||||
temporary.flush()
|
||||
os.fsync(temporary.fileno())
|
||||
temporary_path = Path(temporary.name)
|
||||
temporary_path.chmod(mode)
|
||||
os.replace(temporary_path, path)
|
||||
except OSError as error:
|
||||
if "temporary_path" in locals():
|
||||
if temporary_path is not None:
|
||||
temporary_path.unlink(missing_ok=True)
|
||||
raise BoundaryError("That autostart entry could not be updated.") from error
|
||||
|
||||
|
||||
def update_hidden(path: Path, *, hidden: bool) -> None:
|
||||
try:
|
||||
original = path.read_text(encoding="utf-8")
|
||||
except (OSError, UnicodeError) as error:
|
||||
raise BoundaryError("That autostart entry could not be read.") from error
|
||||
|
||||
mode = path.stat().st_mode
|
||||
write_atomic(path, with_hidden(original, hidden=hidden), mode=mode)
|
||||
|
||||
|
||||
def add_autostart(desktop_id: str) -> None:
|
||||
desktop_files = discovered_desktop_files()
|
||||
require_desktop_id(desktop_id, discovered=set(desktop_files))
|
||||
source = desktop_files[desktop_id]
|
||||
directory = autostart_directory()
|
||||
try:
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
except OSError as error:
|
||||
raise BoundaryError("The user autostart directory could not be created.") from error
|
||||
|
||||
target = directory / desktop_id
|
||||
if target.is_symlink():
|
||||
raise BoundaryError("That autostart entry is not available.")
|
||||
if target.exists():
|
||||
if not target.is_file():
|
||||
raise BoundaryError("That autostart entry is not available.")
|
||||
update_hidden(target, hidden=False)
|
||||
return
|
||||
|
||||
try:
|
||||
original = source.read_text(encoding="utf-8")
|
||||
except (OSError, UnicodeError) as error:
|
||||
raise BoundaryError("That application could not be read.") from error
|
||||
write_atomic(target, with_hidden(original, hidden=False), mode=0o644)
|
||||
|
||||
|
||||
def set_autostart(desktop_id: str, enabled_text: str) -> None:
|
||||
if enabled_text not in {"true", "false"}:
|
||||
raise BoundaryError("Autostart state must be true or false.")
|
||||
@@ -260,10 +298,12 @@ def main(arguments: list[str]) -> int:
|
||||
set_default(arguments[1], arguments[2])
|
||||
elif len(arguments) == 3 and arguments[0] == "set-autostart":
|
||||
set_autostart(arguments[1], arguments[2])
|
||||
elif len(arguments) == 2 and arguments[0] == "add-autostart":
|
||||
add_autostart(arguments[1])
|
||||
else:
|
||||
raise BoundaryError(
|
||||
"Usage: panama-default-apps snapshot | set-default ROLE DESKTOP_ID | "
|
||||
"set-autostart DESKTOP_ID true|false"
|
||||
"set-autostart DESKTOP_ID true|false | add-autostart DESKTOP_ID"
|
||||
)
|
||||
except BoundaryError as error:
|
||||
print(str(error), file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user