diff --git a/bottles/backend/managers/installer.py b/bottles/backend/managers/installer.py index 0fb1e65f278..49289639171 100644 --- a/bottles/backend/managers/installer.py +++ b/bottles/backend/managers/installer.py @@ -479,7 +479,7 @@ def install( # create Desktop entry bottles_icons_path = os.path.join(ManagerUtils.get_bottle_path(config), "icons") icon_path = os.path.join(bottles_icons_path, executable.get("icon")) - ManagerUtils.create_desktop_entry(_config, _program, False, icon_path) + ManagerUtils.create_desktop_entry(_config, _program, False, icon_path, True) if is_final: step_fn() diff --git a/bottles/backend/utils/imagemagick.py b/bottles/backend/utils/imagemagick.py index c83e560158d..d1acf054575 100644 --- a/bottles/backend/utils/imagemagick.py +++ b/bottles/backend/utils/imagemagick.py @@ -85,4 +85,4 @@ def convert( cmd += " -flatten" cmd += f" '{dest}'" - subprocess.Popen(["bash", "-c", cmd]) + subprocess.run(["bash", "-c", cmd]) diff --git a/bottles/backend/utils/manager.py b/bottles/backend/utils/manager.py index af92788aa76..e332057428c 100644 --- a/bottles/backend/utils/manager.py +++ b/bottles/backend/utils/manager.py @@ -24,6 +24,8 @@ import icoextract # type: ignore [import-untyped] +from bottles.backend.params import APP_ID + from bottles.backend.globals import Paths from bottles.backend.logger import Logger from bottles.backend.models.config import BottleConfig @@ -32,6 +34,11 @@ from bottles.backend.utils.generic import get_mime from bottles.backend.utils.imagemagick import ImageMagickUtils +import uuid +from gi.repository import GLib, Gio, Gtk, Xdp, XdpGtk4 + +portal = Xdp.Portal() + logging = Logger() @@ -224,6 +231,7 @@ def create_desktop_entry( skip_icon: bool = False, custom_icon: str = "", use_xdp: bool = False, + window: Gtk.Window = None, ) -> bool: if not os.path.exists(Paths.applications) and not use_xdp: return False @@ -279,41 +287,49 @@ def create_desktop_entry( f.write(f"Exec={cmd_legacy} -b '{config.get('Name')}'\n") return True - ''' - WIP: the following code is not working yet, it raises an error: - GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod - import uuid - from gi.repository import Gio, Xdp - portal = Xdp.Portal() + def prepare_install_cb (self, result): + ret = portal.dynamic_launcher_prepare_install_finish(result) + id = f"{config.get('Name')}.{program.get('name')}" + sum_type = GLib.ChecksumType.SHA1 + exec = "bottles-cli run -p {} -b '{}' -- %u".format( + shlex.quote(program.get('name')), config.get('Name') + ) + portal.dynamic_launcher_install( + ret["token"], + "{}.App_{}.desktop".format( + APP_ID, GLib.compute_checksum_for_string(sum_type, id, -1) + ), + """[Desktop Entry] + Exec={} + Type=Application + Terminal=false + Categories=Application; + Comment=Launch {} using Bottles. + StartupWMClass={}""".format( + exec, program.get("name"), program.get("name") + ) + #TODO: Desktop Actions Configure missing + #[Desktop Action Configure] + #Name=Configure in Bottles + #Exec={} + ) + #TODO: Require xdp>=1.20.1 if icon == "com.usebottles.bottles-program": - _icon = Gio.BytesIcon.new(icon.encode("utf-8")) + icon += ".svg" + _icon = Gio.File.new_for_uri( + f"resource:/com/usebottles/bottles/icons/scalable/apps/{icon}" + ) else: - _icon = Gio.FileIcon.new(Gio.File.new_for_path(icon)) - icon_v = _icon.serialize() - token = portal.dynamic_launcher_request_install_token(program.get("name"), icon_v) - portal.dynamic_launcher_install( - token, - f"com.usebottles.bottles.{config.get('Name')}.{program.get('name')}.{str(uuid.uuid4())}.desktop", - """ - [Desktop Entry] - Exec={} - Type=Application - Terminal=false - Categories=Application; - Comment=Launch {} using Bottles. - Actions=Configure; - [Desktop Action Configure] - Name=Configure in Bottles - Exec={} - """.format( - f"{cmd_cli} run -p {shlex.quote(program.get('name'))} -b '{config.get('Path')}'", - program.get("name"), - f"{cmd_legacy} -b '{config.get('Name')}'" - ).encode("utf-8") - ) - ''' - return False + _icon = Gio.File.new_for_path(icon) + icon_v = Gio.BytesIcon.new(_icon.load_bytes()[0]).serialize() + portal.dynamic_launcher_prepare_install(XdpGtk4.parent_new_gtk(window), + program.get("name"), icon_v, + Xdp.LauncherType.APPLICATION, + None, True, False, None, + prepare_install_cb) + #TODO: Rework to delay showing the toast + return True @staticmethod def browse_wineprefix(wineprefix: dict): diff --git a/bottles/frontend/widgets/program.py b/bottles/frontend/widgets/program.py index 2b0e43b382a..789d4b15eb7 100644 --- a/bottles/frontend/widgets/program.py +++ b/bottles/frontend/widgets/program.py @@ -304,6 +304,8 @@ def update(result, _error=False): "executable": self.program["executable"], "path": self.program["path"], }, + use_xdp=True, + window=self.window, ) def add_to_library(self, _widget): diff --git a/data/data.gresource.xml.in b/data/data.gresource.xml.in index e690e114bad..45badb913e8 100644 --- a/data/data.gresource.xml.in +++ b/data/data.gresource.xml.in @@ -3,6 +3,9 @@ @APP_ID@.metainfo.xml + + icons/hicolor/scalable/apps/com.usebottles.bottles-program.svg + icons/hicolor/symbolic/apps/bottles-steam-symbolic.svg icons/hicolor/symbolic/actions/external-link-symbolic.svg