source code

This commit is contained in:
rustdesk
2021-03-29 15:59:14 +08:00
parent 002fce136c
commit d1013487e2
175 changed files with 35074 additions and 2 deletions

View File

@@ -0,0 +1,123 @@
use std::{io, ptr, slice};
use libc;
use super::ffi::*;
use super::Display;
pub struct Capturer {
display: Display,
shmid: i32,
xcbid: u32,
buffer: *const u8,
size: usize,
use_yuv: bool,
yuv: Vec<u8>,
}
impl Capturer {
pub fn new(display: Display, use_yuv: bool) -> io::Result<Capturer> {
// Calculate dimensions.
let pixel_width = 4;
let rect = display.rect();
let size = (rect.w as usize) * (rect.h as usize) * pixel_width;
// Create a shared memory segment.
let shmid = unsafe {
libc::shmget(
libc::IPC_PRIVATE,
size,
// Everyone can do anything.
libc::IPC_CREAT | 0o777,
)
};
if shmid == -1 {
return Err(io::Error::last_os_error());
}
// Attach the segment to a readable address.
let buffer = unsafe { libc::shmat(shmid, ptr::null(), libc::SHM_RDONLY) } as *mut u8;
if buffer as isize == -1 {
return Err(io::Error::last_os_error());
}
// Attach the segment to XCB.
let server = display.server().raw();
let xcbid = unsafe { xcb_generate_id(server) };
unsafe {
xcb_shm_attach(
server,
xcbid,
shmid as u32,
0, // False, i.e. not read-only.
);
}
let c = Capturer {
display,
shmid,
xcbid,
buffer,
size,
use_yuv,
yuv: Vec::new(),
};
Ok(c)
}
pub fn display(&self) -> &Display {
&self.display
}
fn get_image(&self) {
let rect = self.display.rect();
unsafe {
let request = xcb_shm_get_image_unchecked(
self.display.server().raw(),
self.display.root(),
rect.x,
rect.y,
rect.w,
rect.h,
!0,
XCB_IMAGE_FORMAT_Z_PIXMAP,
self.xcbid,
0,
);
let response =
xcb_shm_get_image_reply(self.display.server().raw(), request, ptr::null_mut());
libc::free(response as *mut _);
}
}
pub fn frame<'b>(&'b mut self) -> &'b [u8] {
self.get_image();
let result = unsafe { slice::from_raw_parts(self.buffer, self.size) };
if self.use_yuv {
crate::common::bgra_to_i420(self.display.w(), self.display.h(), &result, &mut self.yuv);
&self.yuv[..]
} else {
result
}
}
}
impl Drop for Capturer {
fn drop(&mut self) {
unsafe {
// Detach segment from XCB.
xcb_shm_detach(self.display.server().raw(), self.xcbid);
// Detach segment from our space.
libc::shmdt(self.buffer as *mut _);
// Destroy the shared memory segment.
libc::shmctl(self.shmid, libc::IPC_RMID, ptr::null_mut());
}
}
}

View File

@@ -0,0 +1,55 @@
use std::rc::Rc;
use super::ffi::*;
use super::Server;
#[derive(Debug)]
pub struct Display {
server: Rc<Server>,
default: bool,
rect: Rect,
root: xcb_window_t,
}
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Rect {
pub x: i16,
pub y: i16,
pub w: u16,
pub h: u16,
}
impl Display {
pub unsafe fn new(
server: Rc<Server>,
default: bool,
rect: Rect,
root: xcb_window_t,
) -> Display {
Display {
server,
default,
rect,
root,
}
}
pub fn server(&self) -> &Rc<Server> {
&self.server
}
pub fn is_default(&self) -> bool {
self.default
}
pub fn rect(&self) -> Rect {
self.rect
}
pub fn w(&self) -> usize {
self.rect.w as _
}
pub fn h(&self) -> usize {
self.rect.h as _
}
pub fn root(&self) -> xcb_window_t {
self.root
}
}

205
libs/scrap/src/x11/ffi.rs Normal file
View File

@@ -0,0 +1,205 @@
#![allow(non_camel_case_types)]
use libc::c_void;
#[link(name = "xcb")]
#[link(name = "xcb-shm")]
#[link(name = "xcb-randr")]
extern "C" {
pub fn xcb_connect(displayname: *const i8, screenp: *mut i32) -> *mut xcb_connection_t;
pub fn xcb_disconnect(c: *mut xcb_connection_t);
pub fn xcb_connection_has_error(c: *mut xcb_connection_t) -> i32;
pub fn xcb_get_setup(c: *mut xcb_connection_t) -> *const xcb_setup_t;
pub fn xcb_setup_roots_iterator(r: *const xcb_setup_t) -> xcb_screen_iterator_t;
pub fn xcb_screen_next(i: *mut xcb_screen_iterator_t);
pub fn xcb_generate_id(c: *mut xcb_connection_t) -> u32;
pub fn xcb_shm_attach(
c: *mut xcb_connection_t,
shmseg: xcb_shm_seg_t,
shmid: u32,
read_only: u8,
) -> xcb_void_cookie_t;
pub fn xcb_shm_detach(c: *mut xcb_connection_t, shmseg: xcb_shm_seg_t) -> xcb_void_cookie_t;
pub fn xcb_shm_get_image_unchecked(
c: *mut xcb_connection_t,
drawable: xcb_drawable_t,
x: i16,
y: i16,
width: u16,
height: u16,
plane_mask: u32,
format: u8,
shmseg: xcb_shm_seg_t,
offset: u32,
) -> xcb_shm_get_image_cookie_t;
pub fn xcb_shm_get_image_reply(
c: *mut xcb_connection_t,
cookie: xcb_shm_get_image_cookie_t,
e: *mut *mut xcb_generic_error_t,
) -> *mut xcb_shm_get_image_reply_t;
pub fn xcb_randr_get_monitors_unchecked(
c: *mut xcb_connection_t,
window: xcb_window_t,
get_active: u8,
) -> xcb_randr_get_monitors_cookie_t;
pub fn xcb_randr_get_monitors_reply(
c: *mut xcb_connection_t,
cookie: xcb_randr_get_monitors_cookie_t,
e: *mut *mut xcb_generic_error_t,
) -> *mut xcb_randr_get_monitors_reply_t;
pub fn xcb_randr_get_monitors_monitors_iterator(
r: *const xcb_randr_get_monitors_reply_t,
) -> xcb_randr_monitor_info_iterator_t;
pub fn xcb_randr_monitor_info_next(i: *mut xcb_randr_monitor_info_iterator_t);
}
pub const XCB_IMAGE_FORMAT_Z_PIXMAP: u8 = 2;
pub type xcb_atom_t = u32;
pub type xcb_connection_t = c_void;
pub type xcb_window_t = u32;
pub type xcb_keycode_t = u8;
pub type xcb_visualid_t = u32;
pub type xcb_timestamp_t = u32;
pub type xcb_colormap_t = u32;
pub type xcb_shm_seg_t = u32;
pub type xcb_drawable_t = u32;
#[repr(C)]
pub struct xcb_setup_t {
pub status: u8,
pub pad0: u8,
pub protocol_major_version: u16,
pub protocol_minor_version: u16,
pub length: u16,
pub release_number: u32,
pub resource_id_base: u32,
pub resource_id_mask: u32,
pub motion_buffer_size: u32,
pub vendor_len: u16,
pub maximum_request_length: u16,
pub roots_len: u8,
pub pixmap_formats_len: u8,
pub image_byte_order: u8,
pub bitmap_format_bit_order: u8,
pub bitmap_format_scanline_unit: u8,
pub bitmap_format_scanline_pad: u8,
pub min_keycode: xcb_keycode_t,
pub max_keycode: xcb_keycode_t,
pub pad1: [u8; 4],
}
#[repr(C)]
pub struct xcb_screen_iterator_t {
pub data: *mut xcb_screen_t,
pub rem: i32,
pub index: i32,
}
#[repr(C)]
pub struct xcb_screen_t {
pub root: xcb_window_t,
pub default_colormap: xcb_colormap_t,
pub white_pixel: u32,
pub black_pixel: u32,
pub current_input_masks: u32,
pub width_in_pixels: u16,
pub height_in_pixels: u16,
pub width_in_millimeters: u16,
pub height_in_millimeters: u16,
pub min_installed_maps: u16,
pub max_installed_maps: u16,
pub root_visual: xcb_visualid_t,
pub backing_stores: u8,
pub save_unders: u8,
pub root_depth: u8,
pub allowed_depths_len: u8,
}
#[repr(C)]
pub struct xcb_randr_monitor_info_iterator_t {
pub data: *mut xcb_randr_monitor_info_t,
pub rem: i32,
pub index: i32,
}
#[repr(C)]
pub struct xcb_randr_monitor_info_t {
pub name: xcb_atom_t,
pub primary: u8,
pub automatic: u8,
pub n_output: u16,
pub x: i16,
pub y: i16,
pub width: u16,
pub height: u16,
pub width_mm: u32,
pub height_mm: u32,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct xcb_randr_get_monitors_cookie_t {
pub sequence: u32,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct xcb_shm_get_image_cookie_t {
pub sequence: u32,
}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct xcb_void_cookie_t {
pub sequence: u32,
}
#[repr(C)]
pub struct xcb_generic_error_t {
pub response_type: u8,
pub error_code: u8,
pub sequence: u16,
pub resource_id: u32,
pub minor_code: u16,
pub major_code: u8,
pub pad0: u8,
pub pad: [u32; 5],
pub full_sequence: u32,
}
#[repr(C)]
pub struct xcb_shm_get_image_reply_t {
pub response_type: u8,
pub depth: u8,
pub sequence: u16,
pub length: u32,
pub visual: xcb_visualid_t,
pub size: u32,
}
#[repr(C)]
pub struct xcb_randr_get_monitors_reply_t {
pub response_type: u8,
pub pad0: u8,
pub sequence: u16,
pub length: u32,
pub timestamp: xcb_timestamp_t,
pub n_monitors: u32,
pub n_outputs: u32,
pub pad1: [u8; 12],
}

View File

@@ -0,0 +1,93 @@
use std::ptr;
use std::rc::Rc;
use libc;
use super::ffi::*;
use super::{Display, Rect, Server};
//TODO: Do I have to free the displays?
pub struct DisplayIter {
outer: xcb_screen_iterator_t,
inner: Option<(xcb_randr_monitor_info_iterator_t, xcb_window_t)>,
server: Rc<Server>,
}
impl DisplayIter {
pub unsafe fn new(server: Rc<Server>) -> DisplayIter {
let mut outer = xcb_setup_roots_iterator(server.setup());
let inner = Self::next_screen(&mut outer, &server);
DisplayIter {
outer,
inner,
server,
}
}
fn next_screen(
outer: &mut xcb_screen_iterator_t,
server: &Server,
) -> Option<(xcb_randr_monitor_info_iterator_t, xcb_window_t)> {
if outer.rem == 0 {
return None;
}
unsafe {
let root = (*outer.data).root;
let cookie = xcb_randr_get_monitors_unchecked(
server.raw(),
root,
1, //TODO: I don't know if this should be true or false.
);
let response = xcb_randr_get_monitors_reply(server.raw(), cookie, ptr::null_mut());
let inner = xcb_randr_get_monitors_monitors_iterator(response);
libc::free(response as *mut _);
xcb_screen_next(outer);
Some((inner, root))
}
}
}
impl Iterator for DisplayIter {
type Item = Display;
fn next(&mut self) -> Option<Display> {
loop {
if let Some((ref mut inner, root)) = self.inner {
// If there is something in the current screen, return that.
if inner.rem != 0 {
unsafe {
let data = &*inner.data;
let display = Display::new(
self.server.clone(),
data.primary != 0,
Rect {
x: data.x,
y: data.y,
w: data.width,
h: data.height,
},
root,
);
xcb_randr_monitor_info_next(inner);
return Some(display);
}
}
} else {
// If there is no current screen, the screen iterator is empty.
return None;
}
// The current screen was empty, so try the next screen.
self.inner = Self::next_screen(&mut self.outer, &self.server);
}
}
}

10
libs/scrap/src/x11/mod.rs Normal file
View File

@@ -0,0 +1,10 @@
pub use self::capturer::*;
pub use self::display::*;
pub use self::iter::*;
pub use self::server::*;
mod capturer;
mod display;
mod ffi;
mod iter;
mod server;

View File

@@ -0,0 +1,122 @@
use std::ptr;
use std::rc::Rc;
use super::ffi::*;
use super::DisplayIter;
#[derive(Debug)]
pub struct Server {
raw: *mut xcb_connection_t,
screenp: i32,
setup: *const xcb_setup_t,
}
/*
use std::cell::RefCell;
thread_local! {
static SERVER: RefCell<Option<Rc<Server>>> = RefCell::new(None);
}
*/
impl Server {
pub fn displays(slf: Rc<Server>) -> DisplayIter {
unsafe { DisplayIter::new(slf) }
}
pub fn default() -> Result<Rc<Server>, Error> {
Ok(Rc::new(Server::connect(ptr::null())?))
/*
let mut res = Err(Error::from(0));
SERVER.with(|xdo| {
if let Ok(mut server) = xdo.try_borrow_mut() {
if server.is_some() {
unsafe {
if 0 != xcb_connection_has_error(server.as_ref().unwrap().raw) {
*server = None;
println!("Reset x11 connection");
}
}
}
if server.is_none() {
println!("New x11 connection");
match Server::connect(ptr::null()) {
Ok(s) => {
let s = Rc::new(s);
res = Ok(s.clone());
*server = Some(s);
}
Err(err) => {
res = Err(err);
}
}
} else {
res = Ok(server.as_ref().map(|x| x.clone()).unwrap());
}
}
});
res
*/
}
pub fn connect(addr: *const i8) -> Result<Server, Error> {
unsafe {
let mut screenp = 0;
let raw = xcb_connect(addr, &mut screenp);
let error = xcb_connection_has_error(raw);
if error != 0 {
xcb_disconnect(raw);
Err(Error::from(error))
} else {
let setup = xcb_get_setup(raw);
Ok(Server {
raw,
screenp,
setup,
})
}
}
}
pub fn raw(&self) -> *mut xcb_connection_t {
self.raw
}
pub fn screenp(&self) -> i32 {
self.screenp
}
pub fn setup(&self) -> *const xcb_setup_t {
self.setup
}
}
impl Drop for Server {
fn drop(&mut self) {
unsafe {
xcb_disconnect(self.raw);
}
}
}
#[derive(Clone, Copy, Debug)]
pub enum Error {
Generic,
UnsupportedExtension,
InsufficientMemory,
RequestTooLong,
ParseError,
InvalidScreen,
}
impl From<i32> for Error {
fn from(x: i32) -> Error {
use self::Error::*;
match x {
2 => UnsupportedExtension,
3 => InsufficientMemory,
4 => RequestTooLong,
5 => ParseError,
6 => InvalidScreen,
_ => Generic,
}
}
}