Files
sims/sims/modules/launcher/apps.py

88 lines
2.8 KiB
Python

import re
import shlex
import subprocess
from fabric.utils.helpers import DesktopApp, get_desktop_applications
from fabric.widgets.box import Box
from fabric.widgets.image import Image
from fabric.widgets.label import Label
from gi.repository import Gtk
from .base import FuzzyMenu
ICON_SIZE = 32
_FIELD_CODE_RE = re.compile(r"^%[fFuUickdDnNvm]$")
class AppProvider:
def items(self) -> list[DesktopApp]:
return get_desktop_applications()
def filter(self, items: list[DesktopApp], query: str) -> list[DesktopApp]:
if not query:
return items
q = query.lower()
return [a for a in items if _matches(a, q)]
def render(self, item: DesktopApp) -> Gtk.Widget:
children: list[Gtk.Widget] = []
pixbuf = item.get_icon_pixbuf(size=ICON_SIZE)
if pixbuf is not None:
children.append(Image(pixbuf=pixbuf, name="app-icon"))
primary = item.display_name or item.name or ""
text_box = Box(name="app-text", orientation="v", spacing=0)
text_box.add(Label(label=primary, name="app-name", h_align="start"))
if item.generic_name and item.generic_name != primary:
text_box.add(
Label(label=item.generic_name, name="app-generic", h_align="start")
)
children.append(text_box)
return Box(name="slot-box", orientation="h", spacing=10, children=children)
def activate(self, item: DesktopApp) -> None:
# Launch in a transient systemd --user scope so the app gets its own
# cgroup instead of inheriting sims.service's. start_new_session alone
# only changes POSIX session/pgid; systemd tracks units by cgroup and
# would kill children with sims on stop (default KillMode=control-group).
if item.command_line:
argv = [
t for t in shlex.split(item.command_line) if not _FIELD_CODE_RE.match(t)
]
if argv:
subprocess.Popen(
[
"systemd-run",
"--quiet",
"--user",
"--scope",
"--collect",
"--",
*argv,
],
start_new_session=True,
)
return
item.launch()
def _matches(app: DesktopApp, q: str) -> bool:
for field in (app.name, app.display_name, app.generic_name, app.executable):
if field and q in field.lower():
return True
return False
def AppLauncher(monitor: int = 0) -> FuzzyMenu:
return FuzzyMenu(
provider=AppProvider(),
monitor=monitor,
placeholder="Search Apps...",
window_name="app-launcher",
max_results=8,
)