1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

Added support for kitty images protocol using Shared Memory (#1810)

* termwiz: add support for kitty image using shm mode
* termwiz: kitty image shm cleanup error handling
* termwiz: kitty image shm create wrapper for HANDLE and impl Drop for it
* termwiz: kitty image shm refactor windows implementation

Signed-off-by: Shreesh Adiga <16567adigashreesh@gmail.com>
This commit is contained in:
tantei3 2022-04-04 01:29:58 +05:30 committed by GitHub
parent 14323a08d1
commit 60ec82554b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 171 additions and 4 deletions

1
Cargo.lock generated
View File

@ -4038,6 +4038,7 @@ dependencies = [
"libc",
"log",
"memmem",
"nix 0.23.1",
"num-derive",
"num-traits",
"ordered-float",

View File

@ -58,6 +58,7 @@ version = "0.3"
[target."cfg(unix)".dependencies]
signal-hook = "0.1"
termios = "0.3"
nix = "0.23.1"
[target."cfg(windows)".dependencies.winapi]
features = [
"winbase",
@ -68,6 +69,8 @@ features = [
"handleapi",
"fileapi",
"synchapi",
"memoryapi",
"winnt",
]
version = "0.3"

View File

@ -246,14 +246,177 @@ impl KittyImageData {
Ok(data)
}
Self::SharedMem { .. } => {
log::error!("kitty image protocol via shared memory is not supported");
Err(std::io::ErrorKind::Unsupported.into())
}
Self::SharedMem {
name,
data_offset,
data_size,
} => read_shared_memory_data(&name, data_offset, data_size),
}
}
}
#[cfg(unix)]
fn read_shared_memory_data(
name: &str,
data_offset: Option<u32>,
data_size: Option<u32>,
) -> std::result::Result<std::vec::Vec<u8>, std::io::Error> {
use nix::sys::mman::{shm_open, shm_unlink};
use std::fs::File;
use std::os::unix::io::FromRawFd;
let raw_fd = shm_open(
name,
nix::fcntl::OFlag::O_RDONLY,
nix::sys::stat::Mode::empty(),
)
.map_err(|_| {
let err = std::io::Error::last_os_error();
std::io::Error::new(
std::io::ErrorKind::Other,
format!("shm_open {} failed: {:#}", name, err),
)
})?;
let mut f = unsafe { File::from_raw_fd(raw_fd) };
if let Some(offset) = data_offset {
f.seek(std::io::SeekFrom::Start(offset.into()))?;
}
let data = if let Some(len) = data_size {
let mut res = vec![0u8; len as usize];
f.read_exact(&mut res)?;
res
} else {
let mut res = vec![];
f.read_to_end(&mut res)?;
res
};
if let Err(err) = shm_unlink(name) {
log::warn!(
"Unable to unlink kitty image protocol shm file {}: {:#}",
name,
err
);
}
Ok(data)
}
#[cfg(windows)]
mod win {
use winapi::um::handleapi::CloseHandle;
use winapi::um::memoryapi::{
MapViewOfFile, OpenFileMappingW, UnmapViewOfFile, VirtualQuery, FILE_MAP_ALL_ACCESS,
};
use winapi::um::winnt::{HANDLE, MEMORY_BASIC_INFORMATION};
struct HandleWrapper {
handle: HANDLE,
}
struct SharedMemObject {
_handle: HandleWrapper,
buf: *mut u8,
}
impl Drop for HandleWrapper {
fn drop(&mut self) {
unsafe {
CloseHandle(self.handle);
}
}
}
impl Drop for SharedMemObject {
fn drop(&mut self) {
unsafe {
UnmapViewOfFile(self.buf as _);
}
}
}
/// Convert a rust string to a windows wide string
fn wide_string(s: &str) -> Vec<u16> {
use std::os::windows::ffi::OsStrExt;
std::ffi::OsStr::new(s)
.encode_wide()
.chain(std::iter::once(0))
.collect()
}
pub fn read_shared_memory_data(
name: &str,
data_offset: Option<u32>,
data_size: Option<u32>,
) -> std::result::Result<std::vec::Vec<u8>, std::io::Error> {
let wide_name = wide_string(&name);
let handle = unsafe { OpenFileMappingW(FILE_MAP_ALL_ACCESS, 0, wide_name.as_ptr()) };
if handle.is_null() {
let err = std::io::Error::last_os_error();
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("OpenFileMappingW {} failed: {:#}", name, err),
));
}
let handle_wrapper = HandleWrapper { handle };
let buf = unsafe { MapViewOfFile(handle_wrapper.handle, FILE_MAP_ALL_ACCESS, 0, 0, 0) };
if buf.is_null() {
let err = std::io::Error::last_os_error();
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("MapViewOfFile failed: {:#}", err),
));
}
let shm = SharedMemObject {
_handle: handle_wrapper,
buf: buf as *mut u8,
};
let mut memory_info = MEMORY_BASIC_INFORMATION::default();
let res = unsafe {
VirtualQuery(
shm.buf as _,
&mut memory_info as *mut MEMORY_BASIC_INFORMATION,
std::mem::size_of::<MEMORY_BASIC_INFORMATION>(),
)
};
if res == 0 {
let err = std::io::Error::last_os_error();
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"Can't get the size of Shared Memory, VirtualQuery failed: {:#}",
err
),
));
}
let mut size = memory_info.RegionSize;
let offset = data_offset.unwrap_or(0) as usize;
if offset >= size {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"offset {} bigger than or equal to shm region size {}",
offset, size
),
));
}
size = size.saturating_sub(offset);
if let Some(val) = data_size {
size = size.min(val as usize);
}
let buf_slice = unsafe { std::slice::from_raw_parts(shm.buf.add(offset), size) };
let data = buf_slice.to_vec();
Ok(data)
}
}
#[cfg(windows)]
use win::read_shared_memory_data;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum KittyImageVerbosity {
Verbose,