Implement gtk-primary-selection protocol (#7)

Add fallback to gtk primary selection, when zwp primary selection is not available
This commit is contained in:
Kirill Chibisov 2019-08-13 18:58:12 +03:00 • committed by trimental
parent 2fdbb82802
commit 29b2884442
2 changed files with 206 additions and 55 deletions

View file

@ -2,6 +2,8 @@
## Unreleased ## Unreleased
- Add fallback to gtk primary selection, when zwp primary selection is not available
## 0.3.3 -- 2019-06-14 ## 0.3.3 -- 2019-06-14
- Update nix version to 0.14.1 - Update nix version to 0.14.1

View file

@ -17,6 +17,12 @@ use sctk::reexports::client::protocol::{
wl_seat, wl_seat,
}; };
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::{
gtk_primary_selection_device::Event as GtkPrimarySelectionDeviceEvent,
gtk_primary_selection_device::GtkPrimarySelectionDevice,
gtk_primary_selection_device_manager::GtkPrimarySelectionDeviceManager,
gtk_primary_selection_offer::GtkPrimarySelectionOffer, gtk_primary_selection_source,
};
use sctk::reexports::protocols::unstable::primary_selection::v1::client::{ use sctk::reexports::protocols::unstable::primary_selection::v1::client::{
zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1 as PrimarySelectionDeviceMgr, zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1 as PrimarySelectionDeviceMgr,
zwp_primary_selection_device_v1::{ zwp_primary_selection_device_v1::{
@ -36,6 +42,8 @@ type SeatMap = HashMap<
u32, u32,
Arc<Mutex<Option<PrimarySelectionDevice>>>, Arc<Mutex<Option<PrimarySelectionDevice>>>,
Arc<Mutex<Option<PrimarySelectionOffer>>>, Arc<Mutex<Option<PrimarySelectionOffer>>>,
Arc<Mutex<Option<GtkPrimarySelectionDevice>>>,
Arc<Mutex<Option<GtkPrimarySelectionOffer>>>,
), ),
>; >;
@ -182,12 +190,14 @@ fn clipboard_thread(
let mut unimplemented_seats = Vec::new(); let mut unimplemented_seats = Vec::new();
let primary_selection_device_manager = Arc::new(Mutex::new(None)); let primary_selection_device_manager = Arc::new(Mutex::new(None));
let gtk_primary_selection_device_manager = Arc::new(Mutex::new(None));
// Store the name of the seat that last sends an event for use as the default seat // Store the name of the seat that last sends an event for use as the default seat
let last_seat_name = Arc::new(Mutex::new(String::new())); let last_seat_name = Arc::new(Mutex::new(String::new()));
let data_device_manager_clone = data_device_manager.clone(); let data_device_manager_clone = data_device_manager.clone();
let primary_selection_device_manager_clone = primary_selection_device_manager.clone(); let primary_selection_device_manager_clone = primary_selection_device_manager.clone();
let gtk_primary_selection_device_manager_clone = gtk_primary_selection_device_manager.clone();
let seat_map_clone = seat_map.clone(); let seat_map_clone = seat_map.clone();
let last_seat_name_clone = last_seat_name.clone(); let last_seat_name_clone = last_seat_name.clone();
@ -212,6 +222,7 @@ fn clipboard_thread(
data_device_manager, data_device_manager,
&reg, &reg,
primary_selection_device_manager_clone.clone(), primary_selection_device_manager_clone.clone(),
gtk_primary_selection_device_manager_clone.clone(),
); );
} else { } else {
// Store the seat for implementation once wl_data_device_manager is registered // Store the seat for implementation once wl_data_device_manager is registered
@ -237,6 +248,7 @@ fn clipboard_thread(
data_device_manager_clone.lock().unwrap().as_ref().unwrap(), data_device_manager_clone.lock().unwrap().as_ref().unwrap(),
&reg, &reg,
primary_selection_device_manager_clone.clone(), primary_selection_device_manager_clone.clone(),
gtk_primary_selection_device_manager_clone.clone(),
); );
} }
} else if "zwp_primary_selection_device_manager_v1" == interface.as_str() { } else if "zwp_primary_selection_device_manager_v1" == interface.as_str() {
@ -249,6 +261,15 @@ fn clipboard_thread(
) )
.unwrap(), .unwrap(),
); );
} else if "gtk_primary_selection_device_manager" == interface.as_str() {
*gtk_primary_selection_device_manager_clone.lock().unwrap() = Some(
reg.bind::<GtkPrimarySelectionDeviceManager, _>(
version,
id,
NewProxy::implement_dummy,
)
.unwrap(),
);
} }
} }
}); });
@ -296,7 +317,7 @@ fn clipboard_thread(
let seat_map = seat_map.lock().unwrap().clone(); let seat_map = seat_map.lock().unwrap().clone();
// Get the requested seat from the seat map // Get the requested seat from the seat map
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( let data_source = DataSource::new(
@ -322,25 +343,63 @@ fn clipboard_thread(
let seat_map = seat_map.lock().unwrap().clone(); let seat_map = seat_map.lock().unwrap().clone();
// Get the primary clipboard contents of the requested seat from the seat map // Get the primary clipboard contents of the requested seat from the seat map
let contents = seat_map let contents = if primary_selection_device_manager.lock().unwrap().is_some() {
.get(&seat_name.unwrap_or_else(|| last_seat_name.lock().unwrap().clone())) seat_map
.map_or(String::new(), |seat| { .get(
seat.3 &seat_name
.lock() .unwrap_or_else(|| last_seat_name.lock().unwrap().clone()),
.unwrap() )
.as_ref() .map_or(String::new(), |seat| {
.map_or(String::new(), |primary_offer| { seat.3.lock().unwrap().as_ref().map_or(
let (readfd, writefd) = pipe2(OFlag::O_CLOEXEC).unwrap(); String::new(),
let mut file = unsafe { std::fs::File::from_raw_fd(readfd) }; |primary_offer| {
primary_offer let (readfd, writefd) = pipe2(OFlag::O_CLOEXEC).unwrap();
.receive("text/plain;charset=utf-8".to_string(), writefd); let mut file =
close(writefd).unwrap(); unsafe { std::fs::File::from_raw_fd(readfd) };
let mut contents = String::new(); primary_offer.receive(
event_queue.sync_roundtrip().unwrap(); "text/plain;charset=utf-8".to_string(),
file.read_to_string(&mut contents).unwrap(); writefd,
contents );
}) close(writefd).unwrap();
}); let mut contents = String::new();
event_queue.sync_roundtrip().unwrap();
file.read_to_string(&mut contents).unwrap();
contents
},
)
})
} else if gtk_primary_selection_device_manager
.lock()
.unwrap()
.is_some()
{
seat_map
.get(
&seat_name
.unwrap_or_else(|| last_seat_name.lock().unwrap().clone()),
)
.map_or(String::new(), |seat| {
seat.5.lock().unwrap().as_ref().map_or(
String::new(),
|primary_offer| {
let (readfd, writefd) = pipe2(OFlag::O_CLOEXEC).unwrap();
let mut file =
unsafe { std::fs::File::from_raw_fd(readfd) };
primary_offer.receive(
"text/plain;charset=utf-8".to_string(),
writefd,
);
close(writefd).unwrap();
let mut contents = String::new();
event_queue.sync_roundtrip().unwrap();
file.read_to_string(&mut contents).unwrap();
contents
},
)
})
} else {
String::new()
};
load_send.send(contents).unwrap(); load_send.send(contents).unwrap();
} }
// Store text in the primary clipboard // Store text in the primary clipboard
@ -349,8 +408,10 @@ fn clipboard_thread(
let seat_map = seat_map.lock().unwrap().clone(); let seat_map = seat_map.lock().unwrap().clone();
// Get the requested seat from the seat map // Get the requested seat from the seat map
if let Some((_, enter_serial, primary_device, _)) = seat_map if let Some((_, enter_serial, primary_device, _, gtk_primary_device, _)) =
.get(&seat_name.unwrap_or_else(|| last_seat_name.lock().unwrap().clone())) seat_map.get(
&seat_name.unwrap_or_else(|| last_seat_name.lock().unwrap().clone()),
)
{ {
if let Some(manager) = &*primary_selection_device_manager.lock().unwrap() { if let Some(manager) = &*primary_selection_device_manager.lock().unwrap() {
if let Some(primary_device) = &*primary_device.lock().unwrap() { if let Some(primary_device) = &*primary_device.lock().unwrap() {
@ -378,6 +439,35 @@ fn clipboard_thread(
} }
primary_device.set_selection(source.ok().as_ref(), *enter_serial); primary_device.set_selection(source.ok().as_ref(), *enter_serial);
} }
} else if let Some(manager) =
&*gtk_primary_selection_device_manager.lock().unwrap()
{
if let Some(gtk_primary_device) = &*gtk_primary_device.lock().unwrap() {
let source = manager.create_source(|proxy| {
proxy.implement_closure(
move |event, _| {
if let gtk_primary_selection_source::Event::Send {
mime_type,
fd,
} = event
{
if mime_type == "text/plain;charset=utf-8" {
let mut file =
unsafe { std::fs::File::from_raw_fd(fd) };
file.write_fmt(format_args!("{}", contents))
.unwrap();
}
}
},
(),
)
});
if let Ok(source) = &source {
source.offer("text/plain;charset=utf-8".to_string());
}
gtk_primary_device
.set_selection(source.ok().as_ref(), *enter_serial);
}
} }
} }
} }
@ -399,6 +489,7 @@ fn implement_seat(
data_device_manager: &wl_data_device_manager::WlDataDeviceManager, data_device_manager: &wl_data_device_manager::WlDataDeviceManager,
reg: &wl_registry::WlRegistry, reg: &wl_registry::WlRegistry,
primary_device_manager: Arc<Mutex<Option<PrimarySelectionDeviceMgr>>>, primary_device_manager: Arc<Mutex<Option<PrimarySelectionDeviceMgr>>>,
gtk_primary_device_manager: Arc<Mutex<Option<GtkPrimarySelectionDeviceManager>>>,
) { ) {
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();
@ -426,50 +517,100 @@ fn implement_seat(
let primary_offer = Arc::new(Mutex::new(None)); let primary_offer = Arc::new(Mutex::new(None));
let primary_offer_clone = primary_offer.clone(); let primary_offer_clone = primary_offer.clone();
let gtk_primary_offer = Arc::new(Mutex::new(None));
let gtk_primary_offer_clone = gtk_primary_offer.clone();
let seat_map_clone = seat_map.clone(); let seat_map_clone = seat_map.clone();
let seat_name_clone = seat_name.clone(); let seat_name_clone = seat_name.clone();
let primary_device = if let Some(manager) = &*primary_device_manager.lock().unwrap() { let (primary_device, gtk_primary_device) = if let Some(manager) =
Arc::new(Mutex::new( &*primary_device_manager.lock().unwrap()
manager {
.get_device(&seat, |proxy| { (
let primary_offer_clone = primary_offer_clone.clone(); Arc::new(Mutex::new(
proxy.implement_closure( manager
move |event, _| { .get_device(&seat, |proxy| {
if let ZwpPrimarySelectionDeviceEvent::DataOffer { offer } = event { let primary_offer_clone = primary_offer_clone.clone();
*primary_offer_clone.lock().unwrap() = proxy.implement_closure(
Some(offer.implement_dummy()); 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_clone
.lock() .lock()
.unwrap() .unwrap()
.get(&seat_name_clone.lock().unwrap().clone()) .get(&seat_name_clone.lock().unwrap().clone())
.map(|c| c.clone()); .map(|c| c.clone());
if let Some(map_contents) = map_contents { if let Some(map_contents) = map_contents {
seat_map_clone.lock().unwrap().insert( seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(), seat_name_clone.lock().unwrap().clone(),
( (
map_contents.0.clone(), map_contents.0.clone(),
map_contents.1, map_contents.1,
map_contents.2.clone(), map_contents.2.clone(),
primary_offer_clone.clone(), primary_offer_clone.clone(),
), 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() {
(
Arc::new(Mutex::new(None)),
Arc::new(Mutex::new(
manager
.get_device(&seat, |proxy| {
let gtk_primary_offer_clone = gtk_primary_offer_clone.clone();
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
.lock()
.unwrap()
.get(&seat_name_clone.lock().unwrap().clone())
.map(|c| c.clone());
if let Some(map_contents) = map_contents {
seat_map_clone.lock().unwrap().insert(
seat_name_clone.lock().unwrap().clone(),
(
map_contents.0.clone(),
map_contents.1,
Arc::new(Mutex::new(None)),
Arc::new(Mutex::new(None)),
map_contents.4.clone(),
gtk_primary_offer_clone.clone(),
),
);
}
}
},
(),
)
})
.ok(),
)),
)
} else { } else {
Arc::new(Mutex::new(None)) (Arc::new(Mutex::new(None)), Arc::new(Mutex::new(None)))
}; };
let seat_map_clone = seat_map.clone(); let seat_map_clone = seat_map.clone();
let device_clone = device.clone(); let device_clone = device.clone();
let primary_device_clone = primary_device.clone(); let primary_device_clone = primary_device.clone();
let primary_offer_clone = primary_offer_clone.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 seat_name_clone = seat_name.clone();
let last_seat_name_clone = last_seat_name.clone(); let last_seat_name_clone = last_seat_name.clone();
map_keyboard_auto(&seat, move |event, _| { map_keyboard_auto(&seat, move |event, _| {
@ -486,6 +627,8 @@ fn implement_seat(
serial, serial,
primary_device_clone.clone(), primary_device_clone.clone(),
primary_offer_clone.clone(), primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
), ),
); );
} }
@ -497,6 +640,8 @@ fn implement_seat(
serial, serial,
primary_device_clone.clone(), primary_device_clone.clone(),
primary_offer_clone.clone(), primary_offer_clone.clone(),
gtk_primary_device_clone.clone(),
gtk_primary_offer_clone.clone(),
), ),
); );
} }
@ -527,6 +672,8 @@ fn implement_seat(
serial, serial,
primary_device.clone(), primary_device.clone(),
primary_offer.clone(), primary_offer.clone(),
gtk_primary_device.clone(),
gtk_primary_offer.clone(),
), ),
); );
} }
@ -538,6 +685,8 @@ fn implement_seat(
serial, serial,
primary_device.clone(), primary_device.clone(),
primary_offer.clone(), primary_offer.clone(),
gtk_primary_device.clone(),
gtk_primary_offer.clone(),
), ),
); );
} }