mirror of
https://github.com/wez/wezterm.git
synced 2024-08-17 02:00:25 +03:00
Use PrimarySelectionHandler provided by SCTK
Also converts other DataDevice-handling code to use Read/WritePipe instead of the FileDescriptor API.
This commit is contained in:
parent
b23a424e21
commit
84e8c966a1
@ -1,17 +1,14 @@
|
||||
use anyhow::{anyhow, Error, bail};
|
||||
use filedescriptor::{FileDescriptor, Pipe};
|
||||
use anyhow::{anyhow, bail};
|
||||
use smithay_client_toolkit as toolkit;
|
||||
use toolkit::globals::GlobalData;
|
||||
use wayland_client::{Dispatch, event_created_child};
|
||||
use wayland_client::globals::{GlobalList, BindError};
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1;
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_v1::{ZwpPrimarySelectionDeviceV1, self, Event as PrimarySelectionDeviceEvent};
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_offer_v1::{ZwpPrimarySelectionOfferV1, Event as PrimarySelectionOfferEvent};
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_source_v1::{ZwpPrimarySelectionSourceV1, Event as PrimarySelectionSourceEvent};
|
||||
use std::io::Write;
|
||||
use std::os::fd::{AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use toolkit::reexports::client::protocol::wl_data_offer::WlDataOffer;
|
||||
use toolkit::data_device_manager::data_offer::SelectionOffer;
|
||||
use toolkit::data_device_manager::{ReadPipe, WritePipe};
|
||||
use toolkit::primary_selection::device::PrimarySelectionDeviceHandler;
|
||||
use toolkit::primary_selection::selection::PrimarySelectionSourceHandler;
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1;
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1;
|
||||
|
||||
use crate::{Clipboard, ConnectionOps};
|
||||
|
||||
@ -20,7 +17,7 @@ use super::state::WaylandState;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CopyAndPaste {
|
||||
data_offer: Option<WlDataOffer>,
|
||||
data_offer: Option<SelectionOffer>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for CopyAndPaste {
|
||||
@ -36,41 +33,31 @@ impl CopyAndPaste {
|
||||
Arc::new(Mutex::new(Default::default()))
|
||||
}
|
||||
|
||||
pub(super) fn get_clipboard_data(
|
||||
&mut self,
|
||||
clipboard: Clipboard,
|
||||
) -> anyhow::Result<FileDescriptor> {
|
||||
pub(super) fn get_clipboard_data(&mut self, clipboard: Clipboard) -> anyhow::Result<ReadPipe> {
|
||||
let conn = crate::Connection::get().unwrap().wayland();
|
||||
let wayland_state = conn.wayland_state.borrow();
|
||||
let primary_selection = if let Clipboard::PrimarySelection = clipboard {
|
||||
wayland_state.primary_selection_manager.as_ref()
|
||||
wayland_state.primary_selection_device.as_ref()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match primary_selection {
|
||||
Some(primary_selection) => {
|
||||
let inner = primary_selection.inner.lock().unwrap();
|
||||
let offer = inner
|
||||
.offer
|
||||
.as_ref()
|
||||
let offer = primary_selection
|
||||
.data()
|
||||
.selection_offer()
|
||||
.ok_or_else(|| anyhow!("no primary selection offer"))?;
|
||||
let pipe = Pipe::new().map_err(Error::msg)?;
|
||||
offer.receive(TEXT_MIME_TYPE.to_string(), unsafe {
|
||||
BorrowedFd::borrow_raw(pipe.write.as_raw_fd())
|
||||
});
|
||||
Ok(pipe.read)
|
||||
let pipe = offer.receive(TEXT_MIME_TYPE.to_string())?;
|
||||
Ok(pipe)
|
||||
}
|
||||
None => {
|
||||
let offer = self
|
||||
.data_offer
|
||||
.as_ref()
|
||||
.ok_or_else(|| anyhow!("no data offer"))?;
|
||||
let pipe = Pipe::new().map_err(Error::msg)?;
|
||||
offer.receive(TEXT_MIME_TYPE.to_string(), unsafe {
|
||||
BorrowedFd::borrow_raw(pipe.write.as_raw_fd())
|
||||
});
|
||||
Ok(pipe.read)
|
||||
let pipe = offer.receive(TEXT_MIME_TYPE.to_string())?;
|
||||
Ok(pipe)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -82,18 +69,16 @@ impl CopyAndPaste {
|
||||
let last_serial = *wayland_state.last_serial.borrow();
|
||||
|
||||
let primary_selection = if let Clipboard::PrimarySelection = clipboard {
|
||||
wayland_state.primary_selection_manager.as_ref()
|
||||
wayland_state.primary_selection_device.as_ref()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
match primary_selection {
|
||||
Some(primary_selection) => {
|
||||
let manager = &primary_selection.manager;
|
||||
let selection_device = wayland_state.primary_select_device.as_ref().unwrap();
|
||||
let source = manager.create_source(&qh, PrimarySelectionManagerData::default());
|
||||
source.offer(TEXT_MIME_TYPE.to_string());
|
||||
selection_device.set_selection(Some(&source), last_serial);
|
||||
let manager = wayland_state.primary_selection_manager.as_ref().unwrap();
|
||||
let source = manager.create_selection_source(&qh, [TEXT_MIME_TYPE]);
|
||||
source.set_selection(&primary_selection, last_serial);
|
||||
wayland_state
|
||||
.primary_selection_source
|
||||
.replace((source, data));
|
||||
@ -109,7 +94,7 @@ impl CopyAndPaste {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn confirm_selection(&mut self, offer: WlDataOffer) {
|
||||
pub(super) fn confirm_selection(&mut self, offer: SelectionOffer) {
|
||||
self.data_offer.replace(offer);
|
||||
}
|
||||
}
|
||||
@ -126,14 +111,22 @@ impl WaylandState {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn write_selection_to_pipe(fd: FileDescriptor, text: &str) {
|
||||
pub(super) fn write_selection_to_pipe(fd: WritePipe, text: &str) {
|
||||
if let Err(e) = write_pipe_with_timeout(fd, text.as_bytes()) {
|
||||
log::error!("while sending primary selection to pipe: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
fn write_pipe_with_timeout(mut file: FileDescriptor, data: &[u8]) -> anyhow::Result<()> {
|
||||
file.set_non_blocking(true)?;
|
||||
fn write_pipe_with_timeout(mut file: WritePipe, data: &[u8]) -> anyhow::Result<()> {
|
||||
// set non-blocking I/O on the pipe
|
||||
// (adapted from FileDescriptor::set_non_blocking_impl in /filedescriptor/src/unix.rs)
|
||||
if unsafe { libc::fcntl(file.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK) } != 0 {
|
||||
bail!(
|
||||
"failed to change non-blocking mode: {}",
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
}
|
||||
|
||||
let mut pfd = libc::pollfd {
|
||||
fd: file.as_raw_fd(),
|
||||
events: libc::POLLOUT,
|
||||
@ -161,6 +154,8 @@ fn write_pipe_with_timeout(mut file: FileDescriptor, data: &[u8]) -> anyhow::Res
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// Smithay has their own primary selection handler in 0.18
|
||||
// Some code borrowed from https://github.com/Smithay/client-toolkit/commit/4a5c4f59f640bc588a55277261bbed1bd2abea98
|
||||
pub(super) struct PrimarySelectionManagerState {
|
||||
@ -308,3 +303,47 @@ impl Dispatch<ZwpPrimarySelectionDeviceV1, PrimarySelectionManagerData, WaylandS
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl PrimarySelectionDeviceHandler for WaylandState {
|
||||
fn selection(
|
||||
&mut self,
|
||||
_conn: &wayland_client::Connection,
|
||||
_qh: &wayland_client::QueueHandle<Self>,
|
||||
_primary_selection_device: &ZwpPrimarySelectionDeviceV1,
|
||||
) {
|
||||
// TODO: do we need to do anything here?
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimarySelectionSourceHandler for WaylandState {
|
||||
fn send_request(
|
||||
&mut self,
|
||||
_conn: &wayland_client::Connection,
|
||||
_qh: &wayland_client::QueueHandle<Self>,
|
||||
source: &ZwpPrimarySelectionSourceV1,
|
||||
mime: String,
|
||||
write_pipe: toolkit::data_device_manager::WritePipe,
|
||||
) {
|
||||
if mime != TEXT_MIME_TYPE {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some((ps_source, data)) = &self.primary_selection_source {
|
||||
if ps_source.inner() != source {
|
||||
return;
|
||||
}
|
||||
write_selection_to_pipe(write_pipe, data);
|
||||
}
|
||||
}
|
||||
|
||||
fn cancelled(
|
||||
&mut self,
|
||||
_conn: &wayland_client::Connection,
|
||||
_qh: &wayland_client::QueueHandle<Self>,
|
||||
source: &ZwpPrimarySelectionSourceV1,
|
||||
) {
|
||||
self.primary_selection_source.take();
|
||||
source.destroy();
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,3 @@
|
||||
use std::os::fd::{FromRawFd, IntoRawFd};
|
||||
|
||||
use filedescriptor::FileDescriptor;
|
||||
use smithay_client_toolkit::data_device_manager::data_device::DataDeviceHandler;
|
||||
use smithay_client_toolkit::data_device_manager::data_offer::DataOfferHandler;
|
||||
use smithay_client_toolkit::data_device_manager::data_source::DataSourceHandler;
|
||||
@ -59,7 +56,6 @@ impl DataDeviceHandler for WaylandState {
|
||||
.unwrap();
|
||||
|
||||
let window_id = SurfaceUserData::from_wl(&offer.surface).window_id;
|
||||
let offer = offer.inner().clone();
|
||||
|
||||
pstate.drag_and_drop.offer = Some(SurfaceAndOffer { window_id, offer });
|
||||
}
|
||||
@ -110,10 +106,7 @@ impl DataDeviceHandler for WaylandState {
|
||||
}
|
||||
|
||||
if let Some(copy_and_paste) = self.resolve_copy_and_paste() {
|
||||
copy_and_paste
|
||||
.lock()
|
||||
.unwrap()
|
||||
.confirm_selection(offer.inner().clone());
|
||||
copy_and_paste.lock().unwrap().confirm_selection(offer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,7 +184,6 @@ impl DataSourceHandler for WaylandState {
|
||||
if cp_source.inner() != source {
|
||||
return;
|
||||
}
|
||||
let fd = unsafe { FileDescriptor::from_raw_fd(fd.into_raw_fd()) };
|
||||
write_selection_to_pipe(fd, data);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
use crate::wayland::read_pipe_with_timeout;
|
||||
use crate::ConnectionOps;
|
||||
use filedescriptor::{FileDescriptor, Pipe};
|
||||
use smithay_client_toolkit as toolkit;
|
||||
use std::os::fd::{AsRawFd, BorrowedFd};
|
||||
use std::path::PathBuf;
|
||||
use toolkit::reexports::client::protocol::wl_data_offer::WlDataOffer;
|
||||
use toolkit::data_device_manager::data_offer::DragOffer;
|
||||
use toolkit::data_device_manager::ReadPipe;
|
||||
use url::Url;
|
||||
|
||||
use super::data_device::URI_MIME_TYPE;
|
||||
@ -17,12 +16,12 @@ pub struct DragAndDrop {
|
||||
|
||||
pub(super) struct SurfaceAndOffer {
|
||||
pub(super) window_id: usize,
|
||||
pub(super) offer: WlDataOffer,
|
||||
pub(super) offer: DragOffer,
|
||||
}
|
||||
|
||||
pub(super) struct SurfaceAndPipe {
|
||||
pub(super) window_id: usize,
|
||||
pub(super) read: FileDescriptor,
|
||||
pub(super) read: ReadPipe,
|
||||
}
|
||||
|
||||
impl DragAndDrop {
|
||||
@ -30,18 +29,15 @@ impl DragAndDrop {
|
||||
/// returning that surface and pipe descriptor.
|
||||
pub(super) fn create_pipe_for_drop(&mut self) -> Option<SurfaceAndPipe> {
|
||||
let SurfaceAndOffer { window_id, offer } = self.offer.take()?;
|
||||
let pipe = Pipe::new()
|
||||
.map_err(|err| log::error!("Unable to create pipe: {:#}", err))
|
||||
let read = offer
|
||||
.receive(URI_MIME_TYPE.to_string())
|
||||
.map_err(|err| log::error!("Unable to receive data: {:#}", err))
|
||||
.ok()?;
|
||||
offer.receive(URI_MIME_TYPE.to_string(), unsafe {
|
||||
BorrowedFd::borrow_raw(pipe.write.as_raw_fd())
|
||||
});
|
||||
let read = pipe.read;
|
||||
offer.finish();
|
||||
Some(SurfaceAndPipe { window_id, read })
|
||||
}
|
||||
|
||||
pub(super) fn read_paths_from_pipe(read: FileDescriptor) -> Option<Vec<PathBuf>> {
|
||||
pub(super) fn read_paths_from_pipe(read: ReadPipe) -> Option<Vec<PathBuf>> {
|
||||
read_pipe_with_timeout(read)
|
||||
.map_err(|err| {
|
||||
log::error!("Error while reading pipe from drop result: {:#}", err);
|
||||
|
@ -3,7 +3,6 @@ use smithay_client_toolkit::seat::{Capability, SeatHandler, SeatState};
|
||||
use wayland_client::protocol::wl_seat::WlSeat;
|
||||
use wayland_client::{Connection, QueueHandle};
|
||||
|
||||
use crate::wayland::copy_and_paste::PrimarySelectionManagerData;
|
||||
use crate::wayland::keyboard::KeyboardData;
|
||||
use crate::wayland::pointer::PointerUserData;
|
||||
use crate::wayland::SurfaceUserData;
|
||||
@ -56,11 +55,11 @@ impl SeatHandler for WaylandState {
|
||||
let data_device = data_device_manager.get_data_device(qh, &seat);
|
||||
self.data_device.replace(data_device);
|
||||
|
||||
let primary_select_device = self.primary_selection_manager.as_ref().map(|m| {
|
||||
m.manager
|
||||
.get_device(&seat, qh, PrimarySelectionManagerData::default())
|
||||
});
|
||||
self.primary_select_device = primary_select_device;
|
||||
let primary_selection_device = self
|
||||
.primary_selection_manager
|
||||
.as_ref()
|
||||
.map(|m| m.get_selection_device(qh, &seat));
|
||||
self.primary_selection_device = primary_selection_device;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,9 @@ use smithay_client_toolkit::data_device_manager::data_source::CopyPasteSource;
|
||||
use smithay_client_toolkit::data_device_manager::DataDeviceManagerState;
|
||||
use smithay_client_toolkit::globals::GlobalData;
|
||||
use smithay_client_toolkit::output::{OutputHandler, OutputState};
|
||||
use smithay_client_toolkit::primary_selection::device::PrimarySelectionDevice;
|
||||
use smithay_client_toolkit::primary_selection::selection::PrimarySelectionSource;
|
||||
use smithay_client_toolkit::primary_selection::PrimarySelectionManagerState;
|
||||
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_head_v1::ZwlrOutputHeadV1;
|
||||
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_manager_v1::ZwlrOutputManagerV1;
|
||||
use smithay_client_toolkit::reexports::protocols_wlr::output_management::v1::client::zwlr_output_mode_v1::ZwlrOutputModeV1;
|
||||
@ -20,23 +23,18 @@ use smithay_client_toolkit::shm::slot::SlotPool;
|
||||
use smithay_client_toolkit::shm::{Shm, ShmHandler};
|
||||
use smithay_client_toolkit::subcompositor::SubcompositorState;
|
||||
use smithay_client_toolkit::{
|
||||
delegate_compositor, delegate_data_device, delegate_output, delegate_pointer, delegate_registry, delegate_seat, delegate_shm, delegate_subcompositor, delegate_xdg_shell, delegate_xdg_window, registry_handlers
|
||||
delegate_compositor, delegate_data_device, delegate_output, delegate_pointer, delegate_primary_selection, delegate_registry, delegate_seat, delegate_shm, delegate_subcompositor, delegate_xdg_shell, delegate_xdg_window, registry_handlers
|
||||
};
|
||||
use wayland_client::backend::ObjectId;
|
||||
use wayland_client::globals::GlobalList;
|
||||
use wayland_client::protocol::wl_keyboard::WlKeyboard;
|
||||
use wayland_client::protocol::wl_output::WlOutput;
|
||||
use wayland_client::{delegate_dispatch, Connection, QueueHandle};
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_manager_v1::ZwpPrimarySelectionDeviceManagerV1;
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_device_v1::ZwpPrimarySelectionDeviceV1;
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_offer_v1::ZwpPrimarySelectionOfferV1;
|
||||
use wayland_protocols::wp::primary_selection::zv1::client::zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1;
|
||||
use wayland_protocols::wp::text_input::zv3::client::zwp_text_input_manager_v3::ZwpTextInputManagerV3;
|
||||
use wayland_protocols::wp::text_input::zv3::client::zwp_text_input_v3::ZwpTextInputV3;
|
||||
|
||||
use crate::x11::KeyboardWithFallback;
|
||||
|
||||
use super::copy_and_paste::{PrimarySelectionManagerData, PrimarySelectionManagerState};
|
||||
use super::inputhandler::{TextInputData, TextInputState};
|
||||
use super::pointer::{PendingMouse, PointerUserData};
|
||||
use super::{OutputManagerData, OutputManagerState, SurfaceUserData, WaylandWindowInner};
|
||||
@ -69,8 +67,8 @@ pub(super) struct WaylandState {
|
||||
pub(super) data_device: Option<DataDevice>,
|
||||
pub(super) copy_paste_source: Option<(CopyPasteSource, String)>,
|
||||
pub(super) primary_selection_manager: Option<PrimarySelectionManagerState>,
|
||||
pub(super) primary_select_device: Option<ZwpPrimarySelectionDeviceV1>,
|
||||
pub(super) primary_selection_source: Option<(ZwpPrimarySelectionSourceV1, String)>,
|
||||
pub(super) primary_selection_device: Option<PrimarySelectionDevice>,
|
||||
pub(super) primary_selection_source: Option<(PrimarySelectionSource, String)>,
|
||||
pub(super) shm: Shm,
|
||||
pub(super) mem_pool: RefCell<SlotPool>,
|
||||
}
|
||||
@ -111,7 +109,7 @@ impl WaylandState {
|
||||
data_device: None,
|
||||
copy_paste_source: None,
|
||||
primary_selection_manager: PrimarySelectionManagerState::bind(globals, qh).ok(),
|
||||
primary_select_device: None,
|
||||
primary_selection_device: None,
|
||||
primary_selection_source: None,
|
||||
shm,
|
||||
mem_pool: RefCell::new(mem_pool),
|
||||
@ -169,14 +167,11 @@ delegate_pointer!(WaylandState, pointer: [PointerUserData]);
|
||||
delegate_xdg_shell!(WaylandState);
|
||||
delegate_xdg_window!(WaylandState);
|
||||
|
||||
delegate_primary_selection!(WaylandState);
|
||||
|
||||
delegate_dispatch!(WaylandState: [ZwpTextInputManagerV3: GlobalData] => TextInputState);
|
||||
delegate_dispatch!(WaylandState: [ZwpTextInputV3: TextInputData] => TextInputState);
|
||||
|
||||
delegate_dispatch!(WaylandState: [ZwlrOutputManagerV1: GlobalData] => OutputManagerState);
|
||||
delegate_dispatch!(WaylandState: [ZwlrOutputHeadV1: OutputManagerData] => OutputManagerState);
|
||||
delegate_dispatch!(WaylandState: [ZwlrOutputModeV1: OutputManagerData] => OutputManagerState);
|
||||
|
||||
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionDeviceManagerV1: GlobalData] => PrimarySelectionManagerState);
|
||||
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionDeviceV1: PrimarySelectionManagerData] => PrimarySelectionManagerState);
|
||||
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionSourceV1: PrimarySelectionManagerData] => PrimarySelectionManagerState);
|
||||
delegate_dispatch!(WaylandState: [ZwpPrimarySelectionOfferV1: PrimarySelectionManagerData] => PrimarySelectionManagerState);
|
||||
|
@ -14,13 +14,13 @@ use anyhow::{anyhow, bail};
|
||||
use async_io::Timer;
|
||||
use async_trait::async_trait;
|
||||
use config::ConfigHandle;
|
||||
use filedescriptor::FileDescriptor;
|
||||
use promise::{Future, Promise};
|
||||
use raw_window_handle::{
|
||||
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||
WaylandDisplayHandle, WaylandWindowHandle,
|
||||
};
|
||||
use smithay_client_toolkit::compositor::{CompositorHandler, SurfaceData, SurfaceDataExt};
|
||||
use smithay_client_toolkit::data_device_manager::ReadPipe;
|
||||
use smithay_client_toolkit::reexports::csd_frame::{
|
||||
DecorationsFrame, FrameAction, ResizeEdge, WindowState as SCTKWindowState,
|
||||
};
|
||||
@ -463,10 +463,18 @@ pub(crate) struct PendingEvent {
|
||||
pub(crate) window_state: Option<WindowState>,
|
||||
}
|
||||
|
||||
pub(crate) fn read_pipe_with_timeout(mut file: FileDescriptor) -> anyhow::Result<String> {
|
||||
pub(crate) fn read_pipe_with_timeout(mut file: ReadPipe) -> anyhow::Result<String> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
file.set_non_blocking(true)?;
|
||||
// set non-blocking I/O on the pipe
|
||||
// (adapted from FileDescriptor::set_non_blocking_impl in /filedescriptor/src/unix.rs)
|
||||
if unsafe { libc::fcntl(file.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK) } != 0 {
|
||||
bail!(
|
||||
"failed to change non-blocking mode: {}",
|
||||
std::io::Error::last_os_error()
|
||||
)
|
||||
}
|
||||
|
||||
let mut pfd = libc::pollfd {
|
||||
fd: file.as_raw_fd(),
|
||||
events: libc::POLLIN,
|
||||
|
Loading…
Reference in New Issue
Block a user