xstate: always advertise utf8 mime type as UTF8_STRING from Wayland selection
Fixes #87
This commit is contained in:
parent
ba9c1a6a3e
commit
8f55e27f63
3 changed files with 92 additions and 3 deletions
|
|
@ -12,6 +12,7 @@ use xcb::x;
|
|||
struct SelectionTargetId {
|
||||
name: String,
|
||||
atom: x::Atom,
|
||||
source: Option<String>,
|
||||
}
|
||||
|
||||
struct PendingSelectionData {
|
||||
|
|
@ -227,10 +228,18 @@ impl XState {
|
|||
}
|
||||
|
||||
pub(crate) fn set_clipboard(&mut self, selection: ForeignSelection) {
|
||||
let mimes = selection
|
||||
let mut utf8_xwl = false;
|
||||
let mut utf8_wl = false;
|
||||
let mut mimes: Vec<SelectionTargetId> = selection
|
||||
.mime_types
|
||||
.iter()
|
||||
.map(|mime| {
|
||||
match mime.as_str() {
|
||||
"UTF8_STRING" => utf8_xwl = true,
|
||||
"text/plain;charset=utf-8" => utf8_wl = true,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let atom = self
|
||||
.connection
|
||||
.wait_for_reply(self.connection.send_request(&x::InternAtom {
|
||||
|
|
@ -242,10 +251,28 @@ impl XState {
|
|||
SelectionTargetId {
|
||||
name: mime.clone(),
|
||||
atom: atom.atom(),
|
||||
source: None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
if utf8_wl && !utf8_xwl {
|
||||
let name = "UTF8_STRING".to_string();
|
||||
let atom = self
|
||||
.connection
|
||||
.wait_for_reply(self.connection.send_request(&x::InternAtom {
|
||||
only_if_exists: false,
|
||||
name: name.as_bytes(),
|
||||
}))
|
||||
.unwrap()
|
||||
.atom();
|
||||
mimes.push(SelectionTargetId {
|
||||
name,
|
||||
atom,
|
||||
source: Some("text/plain;charset=utf-8".to_string()),
|
||||
});
|
||||
}
|
||||
|
||||
self.selection_data.current_selection = Some(CurrentSelection::Wayland {
|
||||
mimes,
|
||||
inner: selection,
|
||||
|
|
@ -364,7 +391,12 @@ impl XState {
|
|||
return true;
|
||||
};
|
||||
|
||||
let data = inner.receive(target.name.clone(), server_state);
|
||||
let mime_name = target
|
||||
.source
|
||||
.as_ref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| target.name.clone());
|
||||
let data = inner.receive(mime_name, server_state);
|
||||
match self.connection.send_and_check_request(&x::ChangeProperty {
|
||||
mode: x::PropMode::Replace,
|
||||
window: e.requestor(),
|
||||
|
|
@ -479,6 +511,7 @@ impl XState {
|
|||
.map(|target_atom| SelectionTargetId {
|
||||
name: get_atom_name(&self.connection, target_atom),
|
||||
atom: target_atom,
|
||||
source: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
|
|
|||
|
|
@ -1306,3 +1306,59 @@ fn wayland_then_x11_clipboard_owner() {
|
|||
assert_eq!(request.selection(), connection.atoms.clipboard);
|
||||
assert_eq!(request.target(), connection.atoms.targets);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fake_selection_targets() {
|
||||
let mut f = Fixture::new();
|
||||
let mut connection = Connection::new(&f.display);
|
||||
let window = connection.new_window(connection.root, 0, 0, 20, 20, false);
|
||||
connection.get_selection_owner_change_events(true, window);
|
||||
|
||||
let data = b"boingloings";
|
||||
f.map_as_toplevel(&mut connection, window);
|
||||
let offer = vec![testwl::PasteData {
|
||||
mime_type: "text/plain;charset=utf-8".into(),
|
||||
data: data.to_vec(),
|
||||
}];
|
||||
f.testwl.create_data_offer(offer.clone());
|
||||
|
||||
connection.await_selection_owner_change();
|
||||
connection.verify_clipboard_owner(connection.wm_window);
|
||||
connection.get_selection_owner_change_events(false, window);
|
||||
|
||||
let utf8_string = connection
|
||||
.get_reply(&x::InternAtom {
|
||||
only_if_exists: false,
|
||||
name: b"UTF8_STRING",
|
||||
})
|
||||
.atom();
|
||||
|
||||
connection
|
||||
.send_and_check_request(&x::ConvertSelection {
|
||||
requestor: window,
|
||||
selection: connection.atoms.clipboard,
|
||||
target: utf8_string,
|
||||
property: utf8_string,
|
||||
time: x::CURRENT_TIME,
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
f.wait_and_dispatch();
|
||||
let notify = connection.await_selection_notify();
|
||||
assert_eq!(notify.property(), utf8_string, "ConvertSelection failed");
|
||||
|
||||
let reply = connection.get_reply(&x::GetProperty {
|
||||
delete: false,
|
||||
window,
|
||||
property: utf8_string,
|
||||
r#type: utf8_string,
|
||||
long_offset: 0,
|
||||
long_length: data.len() as u32,
|
||||
});
|
||||
let paste_data: &[u8] = reply.value();
|
||||
|
||||
assert_eq!(
|
||||
std::str::from_utf8(paste_data).unwrap(),
|
||||
std::str::from_utf8(data).unwrap()
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -875,7 +875,7 @@ impl Dispatch<WlDataOffer, Vec<PasteData>> for State {
|
|||
let pos = data
|
||||
.iter()
|
||||
.position(|data| data.mime_type == mime_type)
|
||||
.expect("Invalid mime type: {mime_type}");
|
||||
.unwrap_or_else(|| panic!("Invalid mime type: {mime_type}"));
|
||||
|
||||
let mut stream = UnixStream::from(fd);
|
||||
stream.write_all(&data[pos].data).unwrap();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue