@@ -39,7 +39,7 @@ class DesktopInstaller(
3939 private val isRunningInFlatpak: Boolean by lazy {
4040 try {
4141 File (" /.flatpak-info" ).exists() ||
42- System .getenv(" FLATPAK_ID" ) != null
42+ System .getenv(" FLATPAK_ID" ) != null
4343 } catch (_: Exception ) {
4444 false
4545 }
@@ -67,22 +67,16 @@ class DesktopInstaller(
6767 }
6868
6969 override fun openApp (packageName : String ): Boolean {
70- // Desktop apps are launched differently per platform
7170 Logger .d { " Open app not supported on desktop for: $packageName " }
7271 return false
7372 }
7473
7574 override fun openWithExternalInstaller (filePath : String ) {
76- // Not applicable on desktop
7775 }
7876
7977 override fun isAssetInstallable (assetName : String ): Boolean {
8078 val name = assetName.lowercase()
8179
82- // In Flatpak, only allow downloading — we can't actually install system packages.
83- // AppImages also can't run inside the sandbox (no FUSE).
84- // We still mark them as "installable" so the user can download them,
85- // but installation will hand off to the host system.
8680 val hasValidExtension =
8781 when (platform) {
8882 Platform .ANDROID -> {
@@ -126,9 +120,6 @@ class DesktopInstaller(
126120
127121 Platform .LINUX -> {
128122 if (isRunningInFlatpak) {
129- // In Flatpak, prefer native packages over AppImages since AppImages
130- // need FUSE (unavailable in sandbox). The user will install from
131- // their file manager on the host, where DEB/RPM work natively.
132123 when (linuxPackageType) {
133124 LinuxPackageType .DEB -> listOf (" .deb" , " .appimage" , " .rpm" )
134125 LinuxPackageType .RPM -> listOf (" .rpm" , " .appimage" , " .deb" )
@@ -202,8 +193,6 @@ class DesktopInstaller(
202193 private fun determineLinuxPackageType (): LinuxPackageType {
203194 if (platform != Platform .LINUX ) return LinuxPackageType .UNIVERSAL
204195
205- // Inside Flatpak, /etc/os-release belongs to the runtime (org.freedesktop.Platform),
206- // not the host OS. We need to read the host's os-release instead.
207196 if (isRunningInFlatpak) {
208197 return try {
209198 detectHostLinuxPackageType()
@@ -394,9 +383,6 @@ class DesktopInstaller(
394383 withContext(Dispatchers .IO ) {
395384 val ext = extOrMime.lowercase().removePrefix(" ." )
396385
397- // In Flatpak we don't need to check executable permissions — we won't be
398- // running anything ourselves. The file is downloaded to xdg-download and
399- // the user installs from their host file manager.
400386 if (isRunningInFlatpak) {
401387 Logger .d { " Running in Flatpak — skipping permission checks for .$ext " }
402388 return @withContext
@@ -410,7 +396,7 @@ class DesktopInstaller(
410396 if (! canSetExecutable) {
411397 throw IllegalStateException (
412398 " Unable to set executable permissions. AppImage installation requires " +
413- " the ability to make files executable." ,
399+ " the ability to make files executable." ,
414400 )
415401 }
416402 } finally {
@@ -431,7 +417,6 @@ class DesktopInstaller(
431417 }
432418
433419 override fun uninstall (packageName : String ) {
434- // Desktop doesn't have a unified uninstall mechanism
435420 Logger .d { " Uninstall not supported on desktop for: $packageName " }
436421 }
437422
@@ -447,17 +432,10 @@ class DesktopInstaller(
447432
448433 val ext = extOrMime.lowercase().removePrefix(" ." )
449434
450- // Inside the Flatpak sandbox we cannot:
451- // - Run pkexec/sudo (no privilege escalation)
452- // - Access system package managers (apt, dnf, rpm, etc.)
453- // - Mount AppImages (no FUSE / /dev/fuse)
454- // - Open terminal emulators (not in the sandbox)
455- // Instead, we open the downloaded file in the host's default file manager
456- // via the xdg-open portal, so the user can install it natively.
457- if (isRunningInFlatpak) {
458- installFromFlatpak(file, ext)
459- return @withContext
460- }
435+ if (isRunningInFlatpak) {
436+ installFromFlatpak(file, ext)
437+ return @withContext InstallOutcome .DELEGATED_TO_SYSTEM
438+ }
461439
462440 when (platform) {
463441 Platform .WINDOWS -> installWindows(file, ext)
@@ -467,8 +445,8 @@ class DesktopInstaller(
467445 }
468446
469447 InstallOutcome .DELEGATED_TO_SYSTEM
470- }
471448
449+ }
472450
473451 /* *
474452 * Flatpak-sandboxed installation flow.
@@ -486,9 +464,6 @@ class DesktopInstaller(
486464
487465 when (ext) {
488466 " deb" , " rpm" -> {
489- // xdg-open goes through the Flatpak portal → opens on the host.
490- // On most distros, .deb/.rpm files open in GNOME Software, KDE Discover,
491- // or the default package installer.
492467 Logger .d { " Opening .$ext package via xdg-open portal for host installation" }
493468 try {
494469 val process = ProcessBuilder (" xdg-open" , file.absolutePath).start()
@@ -498,7 +473,7 @@ class DesktopInstaller(
498473 showFlatpakNotification(
499474 title = " Package Ready to Install" ,
500475 message = " The ${ext.uppercase()} package has been opened in your system's " +
501- " software installer. Follow the prompts to complete installation." ,
476+ " software installer. Follow the prompts to complete installation." ,
502477 )
503478 } else {
504479 Logger .w { " xdg-open exited with code $exitCode " }
@@ -519,12 +494,8 @@ class DesktopInstaller(
519494 }
520495
521496 " appimage" -> {
522- // AppImages can't run inside Flatpak (no FUSE), and there's no point
523- // moving them to ~/Applications from within the sandbox.
524- // Instead, set executable and open the file manager so the user can find it.
525497 Logger .d { " AppImage downloaded in Flatpak — preparing for host launch" }
526498
527- // Try to make it executable (may work if it's on a filesystem we can chmod)
528499 try {
529500 file.setExecutable(true , false )
530501 Logger .d { " Set executable permission on AppImage" }
@@ -537,7 +508,6 @@ class DesktopInstaller(
537508 message = " Right-click → Properties → mark as executable, then double-click to run." ,
538509 )
539510
540- // Open the file manager highlighting the downloaded file
541511 openInFileManager(file)
542512 }
543513
@@ -586,8 +556,6 @@ class DesktopInstaller(
586556 */
587557 private fun openInFileManager (file : File ) {
588558 try {
589- // D-Bus call to org.freedesktop.FileManager1.ShowItems — this highlights
590- // the specific file in the file manager. Works via Flatpak portal.
591559 val fileUri = " file://${file.absolutePath} "
592560 val process = ProcessBuilder (
593561 " gdbus" , " call" ,
@@ -608,7 +576,6 @@ class DesktopInstaller(
608576 Logger .w { " D-Bus ShowItems not available: ${e.message} " }
609577 }
610578
611- // Fallback: open the parent directory
612579 try {
613580 val parentDir = file.parentFile ? : return
614581 ProcessBuilder (" xdg-open" , parentDir.absolutePath).start()
@@ -752,7 +719,12 @@ class DesktopInstaller(
752719 val installMethods =
753720 listOf (
754721 listOf (" pkexec" , " apt" , " install" , " -y" , file.absolutePath),
755- listOf (" pkexec" , " sh" , " -c" , " dpkg -i '${file.absolutePath} ' || apt-get install -f -y" ),
722+ listOf (
723+ " pkexec" ,
724+ " sh" ,
725+ " -c" ,
726+ " dpkg -i '${file.absolutePath} ' || apt-get install -f -y"
727+ ),
756728 listOf (" gdebi-gtk" , file.absolutePath),
757729 null ,
758730 )
@@ -1144,7 +1116,7 @@ class DesktopInstaller(
11441116 e.printStackTrace()
11451117 throw IllegalStateException (
11461118 " Failed to install AppImage: ${e.message} . " +
1147- " Please ensure you have write permissions to ~/Applications folder." ,
1119+ " Please ensure you have write permissions to ~/Applications folder." ,
11481120 e,
11491121 )
11501122 } catch (e: SecurityException ) {
0 commit comments