gpui_linux: Fix "No Apps Available" dialog when opening URIs on Linux/Wayland (#49752)

Taha created

Closes #48169

Before you mark this PR as ready for review, make sure that you have:
- [ ] Added a solid test coverage and/or screenshots from doing manual
testing
- [x] Done a self-review taking into account security and performance
aspects
- [ ] Aligned any UI changes with the [UI
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)

Release Notes:

- Fixed "No Apps Available" dialog when opening URIs on Linux/Wayland

Swaps the order of `open_uri_internal` function: try xdg-open first, and
only fall back to the portal if every candidate command fails.

Build Tests:
I tested the build on Arch Linux & MacOS Tahoe and there were no issues.
No error logs when opening repo links.

Change summary

crates/gpui_linux/src/linux/platform.rs | 42 ++++++++++++++++++---------
1 file changed, 28 insertions(+), 14 deletions(-)

Detailed changes

crates/gpui_linux/src/linux/platform.rs 🔗

@@ -633,28 +633,42 @@ pub(super) fn open_uri_internal(
     if let Some(uri) = ashpd::Uri::parse(uri).log_err() {
         executor
             .spawn(async move {
-                match ashpd::desktop::open_uri::OpenFileRequest::default()
-                    .activation_token(activation_token.clone().map(ashpd::ActivationToken::from))
-                    .send_uri(&uri)
-                    .await
-                    .and_then(|e| e.response())
-                {
-                    Ok(()) => return,
-                    Err(e) => log::error!("Failed to open with dbus: {}", e),
-                }
-
+                let mut xdg_open_failed = false;
                 for mut command in open::commands(uri.to_string()) {
                     if let Some(token) = activation_token.as_ref() {
                         command.env("XDG_ACTIVATION_TOKEN", token);
                     }
                     let program = format!("{:?}", command.get_program());
                     match smol::process::Command::from(command).spawn() {
-                        Ok(mut cmd) => {
-                            cmd.status().await.log_err();
-                            return;
+                        Ok(mut cmd) => match cmd.status().await {
+                            Ok(status) if status.success() => return,
+                            Ok(status) => {
+                                log::error!("Command {} exited with status: {}", program, status);
+                                xdg_open_failed = true;
+                            }
+                            Err(e) => {
+                                log::error!("Failed to get status from {}: {}", program, e);
+                                xdg_open_failed = true;
+                            }
+                        },
+                        Err(e) => {
+                            log::error!("Failed to open with {}: {}", program, e);
+                            xdg_open_failed = true;
                         }
+                    }
+                }
+
+                if xdg_open_failed {
+                    match ashpd::desktop::open_uri::OpenFileRequest::default()
+                        .activation_token(activation_token.map(ashpd::ActivationToken::from))
+                        .send_uri(&uri)
+                        .await
+                        .and_then(|e| e.response())
+                    {
+                        Ok(()) => {}
+                        Err(ashpd::Error::Response(ashpd::desktop::ResponseError::Cancelled)) => {}
                         Err(e) => {
-                            log::error!("Failed to open with {}: {}", program, e)
+                            log::error!("Failed to open with dbus: {}", e);
                         }
                     }
                 }