mirror of
https://github.com/wez/wezterm.git
synced 2024-08-17 02:00:25 +03:00
Accept drag and drop of URLs from browsers and plain text on X11
For filenames and urls an additional space is inserted after the last item to enable adding more files and urls with another drag-and-drop operation without the need to manually enter the space in between.
This commit is contained in:
parent
b888c547db
commit
3d511bbd67
@ -1011,6 +1011,28 @@ impl TermWindow {
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
WindowEvent::DroppedString(text) => {
|
||||
let pane = match self.get_active_pane_or_overlay() {
|
||||
Some(pane) => pane,
|
||||
None => return Ok(true),
|
||||
};
|
||||
pane.send_paste(text.as_str())?;
|
||||
Ok(true)
|
||||
}
|
||||
WindowEvent::DroppedUrl(urls) => {
|
||||
let pane = match self.get_active_pane_or_overlay() {
|
||||
Some(pane) => pane,
|
||||
None => return Ok(true),
|
||||
};
|
||||
let urls = urls
|
||||
.iter()
|
||||
.map(|url| self.config.quote_dropped_files.escape(&url.to_string()))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ")
|
||||
+ " ";
|
||||
pane.send_paste(urls.as_str())?;
|
||||
Ok(true)
|
||||
}
|
||||
WindowEvent::DroppedFile(paths) => {
|
||||
let pane = match self.get_active_pane_or_overlay() {
|
||||
Some(pane) => pane,
|
||||
@ -1024,7 +1046,8 @@ impl TermWindow {
|
||||
.escape(&path.to_string_lossy())
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
.join(" ")
|
||||
+ " ";
|
||||
pane.send_paste(&paths)?;
|
||||
Ok(true)
|
||||
}
|
||||
|
@ -85,6 +85,8 @@ impl MyWindow {
|
||||
| WindowEvent::FocusChanged(_)
|
||||
| WindowEvent::DraggedFile(_)
|
||||
| WindowEvent::DroppedFile(_)
|
||||
| WindowEvent::DroppedUrl(_)
|
||||
| WindowEvent::DroppedString(_)
|
||||
| WindowEvent::PerformKeyAssignment(_)
|
||||
| WindowEvent::MouseLeave
|
||||
| WindowEvent::SetInnerSizeCompleted => {}
|
||||
|
@ -7,6 +7,7 @@ use std::any::Any;
|
||||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
pub mod bitmaps;
|
||||
pub use wezterm_color_types as color;
|
||||
mod configuration;
|
||||
@ -205,6 +206,12 @@ pub enum WindowEvent {
|
||||
// Called when the files are dropped into the window
|
||||
DroppedFile(Vec<PathBuf>),
|
||||
|
||||
// Called when urls are dropped into the window
|
||||
DroppedUrl(Vec<Url>),
|
||||
|
||||
// Called when text is dropped into the window
|
||||
DroppedString(String),
|
||||
|
||||
/// Called by menubar dispatching stuff on some systems
|
||||
PerformKeyAssignment(config::keyassignment::KeyAssignment),
|
||||
|
||||
|
@ -35,6 +35,7 @@ pub struct XConnection {
|
||||
pub atom_targets: Atom,
|
||||
pub atom_clipboard: Atom,
|
||||
pub atom_texturilist: Atom,
|
||||
pub atom_xmozurl: Atom,
|
||||
pub atom_xdndaware: Atom,
|
||||
pub atom_xdndtypelist: Atom,
|
||||
pub atom_xdndselection: Atom,
|
||||
@ -626,6 +627,7 @@ impl XConnection {
|
||||
let atom_targets = Self::intern_atom(&conn, "TARGETS")?;
|
||||
let atom_clipboard = Self::intern_atom(&conn, "CLIPBOARD")?;
|
||||
let atom_texturilist = Self::intern_atom(&conn, "text/uri-list")?;
|
||||
let atom_xmozurl = Self::intern_atom(&conn, "text/x-moz-url")?;
|
||||
let atom_xdndaware = Self::intern_atom(&conn, "XdndAware")?;
|
||||
let atom_xdndtypelist = Self::intern_atom(&conn, "XdndTypeList")?;
|
||||
let atom_xdndselection = Self::intern_atom(&conn, "XdndSelection")?;
|
||||
@ -762,6 +764,7 @@ impl XConnection {
|
||||
atom_protocols,
|
||||
atom_clipboard,
|
||||
atom_texturilist,
|
||||
atom_xmozurl,
|
||||
atom_xdndaware,
|
||||
atom_xdndtypelist,
|
||||
atom_xdndselection,
|
||||
|
@ -576,10 +576,17 @@ impl XWindowInner {
|
||||
};
|
||||
}
|
||||
self.drag_and_drop.target_type = xcb::x::ATOM_NONE;
|
||||
for t in &self.drag_and_drop.src_types {
|
||||
if *t == conn.atom_texturilist {
|
||||
self.drag_and_drop.target_type = conn.atom_texturilist;
|
||||
for t in [
|
||||
conn.atom_texturilist,
|
||||
conn.atom_xmozurl,
|
||||
conn.atom_utf8_string,
|
||||
] {
|
||||
if self.drag_and_drop.src_types.contains(&t) {
|
||||
self.drag_and_drop.target_type = t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for t in &self.drag_and_drop.src_types {
|
||||
log::trace!("types offered: {}", conn.atom_name(*t));
|
||||
}
|
||||
log::trace!(
|
||||
@ -1105,7 +1112,54 @@ impl XWindowInner {
|
||||
long_length: u32::max_value(),
|
||||
}) {
|
||||
Ok(prop) => {
|
||||
if selection.target() == conn.atom_texturilist {
|
||||
if selection.target() == conn.atom_utf8_string {
|
||||
let text = String::from_utf8_lossy(prop.value()).to_string();
|
||||
self.events.dispatch(WindowEvent::DroppedString(text));
|
||||
} else if selection.target() == conn.atom_xmozurl {
|
||||
let raw = prop.value();
|
||||
let data;
|
||||
if raw.len() >= 2
|
||||
&& ((raw[0], raw[1]) == (0xfe, 0xff)
|
||||
|| (raw[0] != 0x00 && raw[1] == 0x00))
|
||||
{
|
||||
data = String::from_utf16_lossy(
|
||||
raw.chunks_exact(2)
|
||||
.map(|x: &[u8]| u16::from(x[1]) << 8 | u16::from(x[0]))
|
||||
.collect::<Vec<u16>>()
|
||||
.as_slice(),
|
||||
);
|
||||
} else if raw.len() >= 2
|
||||
&& ((raw[0], raw[1]) == (0xff, 0xfe)
|
||||
|| (raw[0] == 0x00 && raw[1] != 0x00))
|
||||
{
|
||||
data = String::from_utf16_lossy(
|
||||
raw.chunks_exact(2)
|
||||
.map(|x: &[u8]| u16::from(x[0]) << 8 | u16::from(x[1]))
|
||||
.collect::<Vec<u16>>()
|
||||
.as_slice(),
|
||||
);
|
||||
} else {
|
||||
data = String::from_utf8_lossy(prop.value()).to_string();
|
||||
}
|
||||
use url::Url;
|
||||
let urls = data
|
||||
.lines()
|
||||
.step_by(2)
|
||||
.filter_map(|line| {
|
||||
// the lines alternate between the urls and their titles
|
||||
Url::parse(line)
|
||||
.map_err(|err| {
|
||||
log::error!(
|
||||
"Error parsing dropped file line {} as url: {:#}",
|
||||
line,
|
||||
err
|
||||
);
|
||||
})
|
||||
.ok()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.events.dispatch(WindowEvent::DroppedUrl(urls));
|
||||
} else if selection.target() == conn.atom_texturilist {
|
||||
let paths = String::from_utf8_lossy(prop.value())
|
||||
.lines()
|
||||
.filter_map(|line| {
|
||||
|
Loading…
Reference in New Issue
Block a user