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:
co-authored by
David Kleingeld
parent
ffff56f7fe
commit
64eec67a81
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user