Merge pull request #12 from kchibisov/tty-switch

Fix clipboard dying after keyboard capability is removed from the seat and then re-added.
This commit is contained in:
Victor Berger 2020-03-09 22:44:18 +01:00 committed by GitHub
commit b0b1d427f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 287 additions and 235 deletions

View file

@ -4,6 +4,7 @@
- Fix crash when receiving non-utf8 data - Fix crash when receiving non-utf8 data
- **Breaking** `load` and `load_primary` now return `Result<String>` to indicate errors - **Breaking** `load` and `load_primary` now return `Result<String>` to indicate errors
- Fix clipboard dying after TTY switch
## 0.3.7 -- 2020-02-27 ## 0.3.7 -- 2020-02-27

View file

@ -13,9 +13,13 @@ use nix::unistd::{close, pipe2};
use sctk::data_device::{DataDevice, DataSource, DataSourceEvent}; use sctk::data_device::{DataDevice, DataSource, DataSourceEvent};
use sctk::keyboard::{map_keyboard_auto, Event as KbEvent}; use sctk::keyboard::{map_keyboard_auto, Event as KbEvent};
use sctk::reexports::client::protocol::{ use sctk::reexports::client::protocol::{
wl_data_device_manager, wl_display::WlDisplay, wl_pointer::Event as PtrEvent, wl_registry, wl_data_device_manager,
wl_seat, wl_display::WlDisplay,
wl_pointer::Event as PtrEvent,
wl_registry,
wl_seat::{self, Capability},
}; };
use sctk::reexports::client::{Display, EventQueue, GlobalEvent, GlobalManager, NewProxy}; use sctk::reexports::client::{Display, EventQueue, GlobalEvent, GlobalManager, NewProxy};
use sctk::reexports::protocols::misc::gtk_primary_selection::client::{ use sctk::reexports::protocols::misc::gtk_primary_selection::client::{
gtk_primary_selection_device::Event as GtkPrimarySelectionDeviceEvent, gtk_primary_selection_device::Event as GtkPrimarySelectionDeviceEvent,
@ -38,7 +42,7 @@ use sctk::wayland_client::sys::client::wl_display;
type SeatMap = HashMap< type SeatMap = HashMap<
String, String,
( (
Arc<Mutex<DataDevice>>, Arc<Mutex<Option<DataDevice>>>,
u32, u32,
Arc<Mutex<Option<PrimarySelectionDevice>>>, Arc<Mutex<Option<PrimarySelectionDevice>>>,
Arc<Mutex<Option<PrimarySelectionOffer>>>, Arc<Mutex<Option<PrimarySelectionOffer>>>,
@ -298,20 +302,25 @@ fn clipboard_thread(
.get(&seat_name.unwrap_or_else(|| last_seat_name.lock().unwrap().clone())) .get(&seat_name.unwrap_or_else(|| last_seat_name.lock().unwrap().clone()))
.map_or(Ok(String::new()), |seat| { .map_or(Ok(String::new()), |seat| {
let mut reader = None; let mut reader = None;
seat.0.lock().unwrap().with_selection(|offer| { if let Some(device) = seat.0.lock().unwrap().as_ref() {
if let Some(offer) = offer { device.with_selection(|offer| {
offer.with_mime_types(|types| { if let Some(offer) = offer {
if types.contains(&"text/plain;charset=utf-8".to_string()) { offer.with_mime_types(|types| {
reader = Some( if types
offer .contains(&"text/plain;charset=utf-8".to_string())
.receive("text/plain;charset=utf-8".into()) {
.unwrap(), reader = Some(
); offer
} .receive("text/plain;charset=utf-8".into())
}); .unwrap(),
} );
}); }
event_queue.sync_roundtrip().unwrap(); });
}
});
event_queue.sync_roundtrip().unwrap();
}
reader.map_or(Ok(String::new()), |mut reader| { reader.map_or(Ok(String::new()), |mut reader| {
let mut contents = String::new(); let mut contents = String::new();
if let Err(err) = reader.read_to_string(&mut contents) { if let Err(err) = reader.read_to_string(&mut contents) {
@ -335,21 +344,21 @@ fn clipboard_thread(
if let Some((device, enter_serial, _, _, _, _)) = seat_map if let Some((device, enter_serial, _, _, _, _)) = seat_map
.get(&seat_name.unwrap_or_else(|| last_seat_name.lock().unwrap().clone())) .get(&seat_name.unwrap_or_else(|| last_seat_name.lock().unwrap().clone()))
{ {
let data_source = DataSource::new( if let Some(device) = device.lock().unwrap().as_ref() {
data_device_manager.lock().unwrap().as_ref().unwrap(), let data_source = DataSource::new(
&["text/plain;charset=utf-8"], data_device_manager.lock().unwrap().as_ref().unwrap(),
move |source_event| { &["text/plain;charset=utf-8"],
if let DataSourceEvent::Send { mut pipe, .. } = source_event { move |source_event| {
write!(pipe, "{}", contents).unwrap(); if let DataSourceEvent::Send { mut pipe, .. } = source_event {
} write!(pipe, "{}", contents).unwrap();
}, }
); },
device );
.lock()
.unwrap()
.set_selection(&Some(data_source), *enter_serial);
event_queue.sync_roundtrip().unwrap(); device.set_selection(&Some(data_source), *enter_serial);
event_queue.sync_roundtrip().unwrap();
}
} }
} }
// Load text from primary clipboard // Load text from primary clipboard
@ -539,17 +548,197 @@ fn implement_seat(
primary_device_manager: Arc<Mutex<Option<PrimarySelectionDeviceMgr>>>, primary_device_manager: Arc<Mutex<Option<PrimarySelectionDeviceMgr>>>,
gtk_primary_device_manager: Arc<Mutex<Option<GtkPrimarySelectionDeviceManager>>>, gtk_primary_device_manager: Arc<Mutex<Option<GtkPrimarySelectionDeviceManager>>>,
) { ) {
let device = Arc::new(Mutex::new(None));
let device_clone = device.clone();
let seat_name = Arc::new(Mutex::new(String::new())); let seat_name = Arc::new(Mutex::new(String::new()));
let seat_name_clone = seat_name.clone(); let seat_name_clone = seat_name.clone();
let seat_map_clone = seat_map.clone();
let primary_device = Arc::new(Mutex::new(None));
let primary_offer = Arc::new(Mutex::new(None));
let primary_device_clone = primary_device.clone();
let primary_offer_clone = primary_offer.clone();
let gtk_primary_device = Arc::new(Mutex::new(None));
let gtk_primary_offer = Arc::new(Mutex::new(None));
let gtk_primary_device_clone = gtk_primary_device.clone();
let gtk_primary_offer_clone = gtk_primary_offer.clone();
let mut pointer = None;
let mut keyboard = None;
// Register the seat // Register the seat
let seat = reg let seat = reg
.bind::<wl_seat::WlSeat, _>(version, id, move |proxy| { .bind::<wl_seat::WlSeat, _>(version, id, move |proxy| {
proxy.implement_closure( proxy.implement_closure(
move |event, _| { move |event, seat| match event {
if let wl_seat::Event::Name { name } = event { wl_seat::Event::Name { name } => *seat_name_clone.lock().unwrap() = name,
*seat_name_clone.lock().unwrap() = name wl_seat::Event::Capabilities { capabilities } => {
if capabilities.contains(Capability::Pointer) {
if pointer.is_none() {
let device_clone = device_clone.clone();
let primary_device_clone = primary_device_clone.clone();
let primary_offer_clone = primary_offer_clone.clone();
let gtk_primary_device_clone = gtk_primary_device_clone.clone();
let gtk_primary_offer_clone = gtk_primary_offer_clone.clone();
let last_seat_name_clone = last_seat_name.clone();
let seat_map_clone = seat_map_clone.clone();
let seat_name_clone = seat_name_clone.clone();
pointer = Some(
seat.get_pointer(move |pointer| {
pointer.implement_closure(
move |evt, _| {
// Set this seat as the last to send an event
*last_seat_name_clone.lock().unwrap() =
seat_name_clone.lock().unwrap().clone();
// Get serials from recieved events from the seat
// pointer
match evt {
PtrEvent::Enter { serial, .. } => {
if let Some(seat) =
seat_map_clone.lock().unwrap().get_mut(
&seat_name_clone
.lock()
.unwrap()
.clone(),
)
{
// Update serial if "seat" is already
// presented
seat.1 = serial;
return;
}
seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(),
(
device_clone.clone(),
serial,
primary_device_clone.clone(),
primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
),
);
}
PtrEvent::Button { serial, .. } => {
if let Some(seat) =
seat_map_clone.lock().unwrap().get_mut(
&seat_name_clone
.lock()
.unwrap()
.clone(),
)
{
// Update serial if seat is already
// presented
seat.1 = serial;
return;
}
// This is for consistency with
// `PtrEvent::Enter`
seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(),
(
device_clone.clone(),
serial,
primary_device_clone.clone(),
primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
),
);
}
_ => {}
}
},
(),
)
})
.unwrap(),
);
}
} else if let Some(pointer) = pointer.take() {
// Release old pointer
if pointer.as_ref().version() >= 3 {
pointer.release();
}
}
if capabilities.contains(Capability::Keyboard) {
if keyboard.is_none() {
let device_clone = device_clone.clone();
let primary_device_clone = primary_device_clone.clone();
let primary_offer_clone = primary_offer_clone.clone();
let gtk_primary_device_clone = gtk_primary_device_clone.clone();
let gtk_primary_offer_clone = gtk_primary_offer_clone.clone();
let last_seat_name_clone = last_seat_name.clone();
let seat_map_clone = seat_map_clone.clone();
let seat_name_clone = seat_name_clone.clone();
keyboard = Some(
map_keyboard_auto(&seat, move |event, _| {
// Set this seat as the last to send an event
*last_seat_name_clone.lock().unwrap() =
seat_name_clone.lock().unwrap().clone();
// Get serials from recieved events from the seat keyboard
match event {
KbEvent::Enter { serial, .. } => {
seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(),
(
device_clone.clone(),
serial,
primary_device_clone.clone(),
primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
),
);
}
KbEvent::Key { serial, .. } => {
seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(),
(
device_clone.clone(),
serial,
primary_device_clone.clone(),
primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
),
);
}
KbEvent::Leave { .. } => {
seat_map_clone
.lock()
.unwrap()
.remove(&*seat_name_clone.lock().unwrap());
}
_ => {}
}
})
.unwrap(),
);
}
} else if let Some(keyboard) = keyboard.take() {
// Release old keyboard
if keyboard.as_ref().version() >= 3 {
keyboard.release();
}
}
} }
_ => (),
}, },
(), (),
) )
@ -557,215 +746,77 @@ fn implement_seat(
.unwrap(); .unwrap();
// Create a device for the seat // Create a device for the seat
let device = Arc::new(Mutex::new(DataDevice::init_for_seat( *device.lock().unwrap() = Some(DataDevice::init_for_seat(
data_device_manager, data_device_manager,
&seat, &seat,
|_| {}, |_| {},
))); ));
let primary_offer = Arc::new(Mutex::new(None)); if let Some(manager) = &*primary_device_manager.lock().unwrap() {
let primary_offer_clone = primary_offer.clone(); *primary_device.lock().unwrap() = manager
let gtk_primary_offer = Arc::new(Mutex::new(None)); .get_device(&seat, |proxy| {
let gtk_primary_offer_clone = gtk_primary_offer.clone(); proxy.implement_closure(
let seat_map_clone = seat_map.clone(); move |event, _| {
let seat_name_clone = seat_name.clone(); if let ZwpPrimarySelectionDeviceEvent::DataOffer { offer } = event {
let (primary_device, gtk_primary_device) = if let Some(manager) = *primary_offer.lock().unwrap() = Some(offer.implement_dummy());
&*primary_device_manager.lock().unwrap()
{
(
Arc::new(Mutex::new(
manager
.get_device(&seat, |proxy| {
let primary_offer_clone = primary_offer_clone.clone();
proxy.implement_closure(
move |event, _| {
if let ZwpPrimarySelectionDeviceEvent::DataOffer { offer } = event {
*primary_offer_clone.lock().unwrap() =
Some(offer.implement_dummy());
let map_contents = seat_map_clone let map_contents = seat_map
.lock() .lock()
.unwrap() .unwrap()
.get(&seat_name_clone.lock().unwrap().clone()) .get(&seat_name.lock().unwrap().clone())
.cloned(); .cloned();
if let Some(map_contents) = map_contents { if let Some(map_contents) = map_contents {
seat_map_clone.lock().unwrap().insert( seat_map.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(), seat_name.lock().unwrap().clone(),
( (
map_contents.0.clone(), map_contents.0.clone(),
map_contents.1, map_contents.1,
map_contents.2.clone(), map_contents.2,
primary_offer_clone.clone(), primary_offer.clone(),
Arc::new(Mutex::new(None)), Arc::new(Mutex::new(None)),
Arc::new(Mutex::new(None)), Arc::new(Mutex::new(None)),
), ),
); );
} }
} }
}, },
(), (),
) )
}) })
.ok(), .ok();
)),
Arc::new(Mutex::new(None)),
)
} else if let Some(manager) = &*gtk_primary_device_manager.lock().unwrap() { } else if let Some(manager) = &*gtk_primary_device_manager.lock().unwrap() {
( *gtk_primary_device.lock().unwrap() = manager
Arc::new(Mutex::new(None)), .get_device(&seat, |proxy| {
Arc::new(Mutex::new( proxy.implement_closure(
manager move |event, _| {
.get_device(&seat, |proxy| { if let GtkPrimarySelectionDeviceEvent::DataOffer { offer } = event {
let gtk_primary_offer_clone = gtk_primary_offer_clone.clone(); *gtk_primary_offer.lock().unwrap() = Some(offer.implement_dummy());
proxy.implement_closure(
move |event, _| {
if let GtkPrimarySelectionDeviceEvent::DataOffer { offer } = event {
*gtk_primary_offer_clone.lock().unwrap() =
Some(offer.implement_dummy());
let map_contents = seat_map_clone let map_contents = seat_map
.lock() .lock()
.unwrap() .unwrap()
.get(&seat_name_clone.lock().unwrap().clone()) .get(&seat_name.lock().unwrap().clone())
.cloned(); .cloned();
if let Some(map_contents) = map_contents { if let Some(map_contents) = map_contents {
seat_map_clone.lock().unwrap().insert( seat_map.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(), seat_name.lock().unwrap().clone(),
( (
map_contents.0.clone(), map_contents.0.clone(),
map_contents.1, map_contents.1,
Arc::new(Mutex::new(None)), Arc::new(Mutex::new(None)),
Arc::new(Mutex::new(None)), Arc::new(Mutex::new(None)),
map_contents.4.clone(), map_contents.4,
gtk_primary_offer_clone.clone(), gtk_primary_offer.clone(),
), ),
); );
} }
}
},
(),
)
})
.ok(),
)),
)
} else {
(Arc::new(Mutex::new(None)), Arc::new(Mutex::new(None)))
};
let seat_map_clone = seat_map.clone();
let device_clone = device.clone();
let primary_device_clone = primary_device.clone();
let primary_offer_clone = primary_offer_clone.clone();
let gtk_primary_device_clone = gtk_primary_device.clone();
let gtk_primary_offer_clone = gtk_primary_offer_clone.clone();
let seat_name_clone = seat_name.clone();
let last_seat_name_clone = last_seat_name.clone();
map_keyboard_auto(&seat, move |event, _| {
// Set this seat as the last to send an event
*last_seat_name_clone.lock().unwrap() = seat_name_clone.lock().unwrap().clone();
// Get serials from recieved events from the seat keyboard
match event {
KbEvent::Enter { serial, .. } => {
seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(),
(
device_clone.clone(),
serial,
primary_device_clone.clone(),
primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
),
);
}
KbEvent::Key { serial, .. } => {
seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(),
(
device_clone.clone(),
serial,
primary_device_clone.clone(),
primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
),
);
}
KbEvent::Leave { .. } => {
seat_map_clone
.lock()
.unwrap()
.remove(&*seat_name_clone.lock().unwrap());
}
_ => {}
}
})
.unwrap();
seat.get_pointer(|pointer| {
pointer.implement_closure(
move |evt, _| {
// Set this seat as the last to send an event
*last_seat_name.lock().unwrap() = seat_name.lock().unwrap().clone();
// Get serials from recieved events from the seat pointer
match evt {
PtrEvent::Enter { serial, .. } => {
if let Some(seat) = seat_map
.lock()
.unwrap()
.get_mut(&seat_name.lock().unwrap().clone())
{
// Update serial if "seat" is already presented
seat.1 = serial;
return;
} }
},
seat_map.lock().unwrap().insert( (),
seat_name.lock().unwrap().clone(), )
( })
device.clone(), .ok();
serial, }
primary_device.clone(),
primary_offer.clone(),
gtk_primary_device.clone(),
gtk_primary_offer.clone(),
),
);
}
PtrEvent::Button { serial, .. } => {
if let Some(seat) = seat_map
.lock()
.unwrap()
.get_mut(&seat_name.lock().unwrap().clone())
{
// Update serial if seat is already presented
seat.1 = serial;
return;
}
// This is for consistency with `PtrEvent::Enter`
seat_map.lock().unwrap().insert(
seat_name.lock().unwrap().clone(),
(
device.clone(),
serial,
primary_device.clone(),
primary_offer.clone(),
gtk_primary_device.clone(),
gtk_primary_offer.clone(),
),
);
}
_ => {}
}
},
(),
)
})
.unwrap();
} }
// Normalize \r and \r\n into \n. // Normalize \r and \r\n into \n.