wayland: Implement activate()
API and use portals to open URLs and paths (#13336)
This PR consists of two main changes: 1. The first commit changes the `open` crate for opening URLs/paths for the `OpenURI` desktop portal. This fixes the activation token not being passed to programs (at least on KDE). 2. The second commit implements the window `activate()` API on Wayland. This allows KWin and Mutter to show a visual indicator when the window is requesting attention. (see https://github.com/zed-industries/zed/issues/12557)  Release Notes: - N/A
This commit is contained in:
parent
414cff5c14
commit
0b6ef995d4
8 changed files with 140 additions and 80 deletions
|
@ -7,7 +7,7 @@ use std::ffi::OsString;
|
|||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::os::fd::{AsRawFd, FromRawFd};
|
||||
use std::os::fd::{AsFd, AsRawFd, FromRawFd};
|
||||
use std::panic::Location;
|
||||
use std::rc::Weak;
|
||||
use std::{
|
||||
|
@ -20,6 +20,8 @@ use std::{
|
|||
|
||||
use anyhow::anyhow;
|
||||
use ashpd::desktop::file_chooser::{OpenFileRequest, SaveFileRequest};
|
||||
use ashpd::desktop::open_uri::{OpenDirectoryRequest, OpenFileRequest as OpenUriRequest};
|
||||
use ashpd::{url, ActivationToken};
|
||||
use async_task::Runnable;
|
||||
use calloop::channel::Channel;
|
||||
use calloop::{EventLoop, LoopHandle, LoopSignal};
|
||||
|
@ -67,6 +69,7 @@ pub trait LinuxClient {
|
|||
) -> anyhow::Result<Box<dyn PlatformWindow>>;
|
||||
fn set_cursor_style(&self, style: CursorStyle);
|
||||
fn open_uri(&self, uri: &str);
|
||||
fn reveal_path(&self, path: PathBuf);
|
||||
fn write_to_primary(&self, item: ClipboardItem);
|
||||
fn write_to_clipboard(&self, item: ClipboardItem);
|
||||
fn read_from_primary(&self) -> Option<ClipboardItem>;
|
||||
|
@ -344,13 +347,7 @@ impl<P: LinuxClient + 'static> Platform for P {
|
|||
}
|
||||
|
||||
fn reveal_path(&self, path: &Path) {
|
||||
if path.is_dir() {
|
||||
open::that_detached(path);
|
||||
return;
|
||||
}
|
||||
// If `path` is a file, the system may try to open it in a text editor
|
||||
let dir = path.parent().unwrap_or(Path::new(""));
|
||||
open::that_detached(dir);
|
||||
self.reveal_path(path.to_owned());
|
||||
}
|
||||
|
||||
fn on_quit(&self, callback: Box<dyn FnMut()>) {
|
||||
|
@ -511,18 +508,40 @@ impl<P: LinuxClient + 'static> Platform for P {
|
|||
fn add_recent_document(&self, _path: &Path) {}
|
||||
}
|
||||
|
||||
pub(super) fn open_uri_internal(uri: &str, activation_token: Option<&str>) {
|
||||
let mut last_err = None;
|
||||
for mut command in open::commands(uri) {
|
||||
if let Some(token) = activation_token {
|
||||
command.env("XDG_ACTIVATION_TOKEN", token);
|
||||
}
|
||||
match command.spawn() {
|
||||
Ok(_) => return,
|
||||
Err(err) => last_err = Some(err),
|
||||
}
|
||||
pub(super) fn open_uri_internal(
|
||||
executor: BackgroundExecutor,
|
||||
uri: &str,
|
||||
activation_token: Option<String>,
|
||||
) {
|
||||
if let Some(uri) = url::Url::parse(uri).log_err() {
|
||||
executor
|
||||
.spawn(async move {
|
||||
OpenUriRequest::default()
|
||||
.activation_token(activation_token.map(ActivationToken::from))
|
||||
.send_uri(&uri)
|
||||
.await
|
||||
.log_err();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
log::error!("failed to open uri: {uri:?}, last error: {last_err:?}");
|
||||
}
|
||||
|
||||
pub(super) fn reveal_path_internal(
|
||||
executor: BackgroundExecutor,
|
||||
path: PathBuf,
|
||||
activation_token: Option<String>,
|
||||
) {
|
||||
executor
|
||||
.spawn(async move {
|
||||
if let Some(dir) = File::open(path).log_err() {
|
||||
OpenDirectoryRequest::default()
|
||||
.activation_token(activation_token.map(ActivationToken::from))
|
||||
.send(&dir.as_fd())
|
||||
.await
|
||||
.log_err();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub(super) fn is_within_click_distance(a: Point<Pixels>, b: Point<Pixels>) -> bool {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue