Fix floating file chooser (#39154)

Closes #39117 

Some window managers (example: hyprland
https://github.com/hyprwm/Hyprland/issues/11229) still won't open a
floating file chooser because they don't support the XDG foreign
protocol yet: https://wayland.app/protocols/xdg-foreign-unstable-v2

Release Notes:

- Fixed file chooser not floating

---------

Co-authored-by: David Kleingeld <davidsk@zed.dev>
This commit is contained in:
Alvaro Parker
2025-10-07 14:06:48 +02:00
committed by GitHub
co-authored by David Kleingeld
parent ffff56f7fe
commit 64eec67a81
7 changed files with 85 additions and 4 deletions
@@ -73,6 +73,13 @@ pub trait LinuxClient {
fn active_window(&self) -> Option<AnyWindowHandle>;
fn window_stack(&self) -> Option<Vec<AnyWindowHandle>>;
fn run(&self);
#[cfg(any(feature = "wayland", feature = "x11"))]
fn window_identifier(
&self,
) -> impl Future<Output = Option<ashpd::WindowIdentifier>> + Send + 'static {
std::future::ready::<Option<ashpd::WindowIdentifier>>(None)
}
}
#[derive(Default)]
@@ -290,6 +297,9 @@ impl<P: LinuxClient + 'static> Platform for P {
#[cfg(not(any(feature = "wayland", feature = "x11")))]
let _ = (done_tx.send(Ok(None)), options);
#[cfg(any(feature = "wayland", feature = "x11"))]
let identifier = self.window_identifier();
#[cfg(any(feature = "wayland", feature = "x11"))]
self.foreground_executor()
.spawn(async move {
@@ -300,6 +310,7 @@ impl<P: LinuxClient + 'static> Platform for P {
};
let request = match ashpd::desktop::file_chooser::OpenFileRequest::default()
.identifier(identifier.await)
.modal(true)
.title(title)
.accept_label(options.prompt.as_ref().map(crate::SharedString::as_str))
@@ -346,6 +357,9 @@ impl<P: LinuxClient + 'static> Platform for P {
#[cfg(not(any(feature = "wayland", feature = "x11")))]
let _ = (done_tx.send(Ok(None)), directory, suggested_name);
#[cfg(any(feature = "wayland", feature = "x11"))]
let identifier = self.window_identifier();
#[cfg(any(feature = "wayland", feature = "x11"))]
self.foreground_executor()
.spawn({
@@ -355,6 +369,7 @@ impl<P: LinuxClient + 'static> Platform for P {
async move {
let mut request_builder =
ashpd::desktop::file_chooser::SaveFileRequest::default()
.identifier(identifier.await)
.modal(true)
.title("Save File")
.current_folder(directory)
@@ -7,6 +7,7 @@ use std::{
time::{Duration, Instant},
};
use ashpd::WindowIdentifier;
use calloop::{
EventLoop, LoopHandle,
timer::{TimeoutAction, Timer},
@@ -858,6 +859,20 @@ impl LinuxClient for WaylandClient {
fn compositor_name(&self) -> &'static str {
"Wayland"
}
fn window_identifier(&self) -> impl Future<Output = Option<WindowIdentifier>> + Send + 'static {
async fn inner(surface: Option<wl_surface::WlSurface>) -> Option<WindowIdentifier> {
if let Some(surface) = surface {
ashpd::WindowIdentifier::from_wayland(&surface).await
} else {
None
}
}
let client_state = self.0.borrow();
let active_window = client_state.keyboard_focused_window.as_ref();
inner(active_window.map(|aw| aw.surface()))
}
}
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for WaylandClientStatePtr {
@@ -1,5 +1,6 @@
use crate::{Capslock, xcb_flush};
use anyhow::{Context as _, anyhow};
use ashpd::WindowIdentifier;
use calloop::{
EventLoop, LoopHandle, RegistrationToken,
generic::{FdWrapper, Generic},
@@ -1652,6 +1653,16 @@ impl LinuxClient for X11Client {
Some(handles)
}
fn window_identifier(&self) -> impl Future<Output = Option<WindowIdentifier>> + Send + 'static {
let state = self.0.borrow();
state
.keyboard_focused_window
.and_then(|focused_window| state.windows.get(&focused_window))
.map(|window| window.window.x_window as u64)
.map(|x_window| std::future::ready(Some(WindowIdentifier::from_xid(x_window))))
.unwrap_or(std::future::ready(None))
}
}
impl X11ClientState {
+1 -1
View File
@@ -284,7 +284,7 @@ pub(crate) struct X11WindowStatePtr {
pub state: Rc<RefCell<X11WindowState>>,
pub(crate) callbacks: Rc<RefCell<Callbacks>>,
xcb: Rc<XCBConnection>,
x_window: xproto::Window,
pub(crate) x_window: xproto::Window,
}
impl rwh::HasWindowHandle for RawWindow {