fullscreen for x11

This commit is contained in:
Michael Zhang 2021-07-28 16:25:32 -05:00
parent 69e226dcf3
commit c519114a9f
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
10 changed files with 111 additions and 33 deletions

1
Cargo.lock generated
View file

@ -185,7 +185,6 @@ name = "leanshot"
version = "0.5.0"
dependencies = [
"anyhow",
"cfg-if",
"image",
"leanshot-x11",
"libc",

View file

@ -12,19 +12,28 @@ members = ["x11"]
[features]
default = ["backend-x11", "backend-x11-glx"]
backend-x11 = []
backend-x11-glx = ["backend-x11"]
backend-x11 = ["leanshot-x11"]
backend-x11-glx = ["backend-x11", "leanshot-x11/glx"]
backend-xcb = ["xcb-util", "xcb"]
[dependencies]
anyhow = "1.0.38"
image = { version = "0.23.13", default-features = false, features = ["jpeg", "png"] }
leanshot-x11 = { path = "x11" }
anyhow = "1.0.42"
image = { version = "0.23.14", default-features = false, features = ["jpeg", "png"] }
log = "0.4.14"
stderrlog = "0.5.1"
structopt = "0.3.21"
libc = "0.2.86"
structopt = "0.3.22"
libc = "0.2.98"
# x11
leanshot-x11 = { path = "x11", optional = true }
# xcb
xcb-util = { version = "0.3.0", features = ["image", "cursor"], optional = true }
xcb = { version = "0.9.0", optional = true }
cfg-if = "1.0.0"
[package.metadata.cargo-all-features]
skip_feature_sets = [
["backend-x11", "backend-xcb"],
[],
]
skip_optional_dependencies = true

View file

@ -11,6 +11,9 @@ pub trait Gui {
}
pub trait Capture {
fn save_to(&self, path: impl AsRef<Path>) -> Result<()>;
fn save_to(&self, to: impl AsRef<Path>) -> Result<()> {
self.save_cropped_to(to, None)
}
fn save_cropped_to(&self, path: impl AsRef<Path>, section: Option<Rectangle>) -> Result<()>;
}

View file

@ -1,7 +1,8 @@
use std::path::Path;
use anyhow::Result;
use x11::xlib::Display;
use x11::xlib::{Display, Image as XImage, Screen};
use image::{Bgra, DynamicImage, ImageBuffer};
use crate::gui_trait::{Capture, Gui};
use crate::rect::Rectangle;
@ -15,33 +16,71 @@ impl X11Gui {
let disp = Display::connect(None)?;
Ok(X11Gui { conn: disp })
}
fn get_default_screen(&self) -> Screen {
self.conn.default_screen()
}
}
impl Gui for X11Gui {
type Capture = ScreenCapture;
fn capture_entire_screen(&self) -> Result<<Self as Gui>::Capture, anyhow::Error> {
todo!()
fn capture_entire_screen(&self) -> Result<Self::Capture> {
// get the dimensions of the screen
let screen = self.get_default_screen();
let (width, height) = (screen.width_in_pixels(), screen.height_in_pixels());
let root_window = self.conn.get_root_window(screen)?;
let image = root_window.get_image()?;
Ok(ScreenCapture { image })
}
fn interactive_select(
&self,
_: &<Self as Gui>::Capture,
) -> Result<Option<Rectangle>, anyhow::Error> {
_: &Self::Capture,
) -> Result<Option<Rectangle>> {
todo!()
}
}
pub struct ScreenCapture {}
pub struct ScreenCapture {
image: XImage,
}
impl Capture for ScreenCapture {
fn save_to(&self, _: impl AsRef<Path>) -> Result<(), anyhow::Error> {
todo!()
}
fn save_cropped_to(
&self,
_: impl AsRef<Path>,
_: Option<Rectangle>,
) -> Result<(), anyhow::Error> {
todo!()
to: impl AsRef<Path>,
section: Option<Rectangle>,
) -> Result<()> {
let to = to.as_ref();
let buffer = self.image.buffer();
let image = ImageBuffer::<Bgra<u8>, _>::from_raw(
self.image.get_width(),
self.image.get_height(),
buffer.get_buffer().to_vec(),
)
.unwrap();
let image = DynamicImage::ImageBgra8(image);
let mut image = DynamicImage::ImageRgb8(image.into_rgb8());
let image = if let Some(section) = section {
// crop the image
image.crop(
section.x as u32,
section.y as u32,
section.width as u32,
section.height as u32,
)
} else {
image
};
image.save(to)?;
Ok(())
}
}

View file

@ -296,10 +296,6 @@ pub struct ScreenCapture {
}
impl Capture for ScreenCapture {
fn save_to(&self, to: impl AsRef<Path>) -> Result<()> {
self.save_cropped_to(to, None)
}
fn save_cropped_to(&self, to: impl AsRef<Path>, section: Option<Rectangle>) -> Result<()> {
let to = to.as_ref();
let image = ImageBuffer::<Bgra<u8>, _>::from_raw(

View file

@ -3,6 +3,7 @@ extern crate log;
#[macro_use]
extern crate anyhow;
#[cfg(feature = "backend-x11")]
extern crate leanshot_x11 as x11;
#[cfg(all(feature = "backend-x11", feature = "backend-xcb"))]

View file

@ -11,6 +11,7 @@ use crate::ffi;
use super::cursor::Cursor;
use super::event::Event;
use super::screen::Screen;
use super::visual::Visual;
use super::window::Window;
@ -99,15 +100,24 @@ impl Display {
self.inner
}
/// Gets the default screen
pub fn default_screen(&self) -> Screen {
let screen = unsafe { xlib::XDefaultScreen(self.inner) };
Screen {
display: self,
num: screen,
}
}
/// Gets the default visual
pub fn default_visual(&self, screen: i32) -> Visual {
let visual = unsafe { xlib::XDefaultVisual(self.inner, screen) };
pub fn default_visual(&self, screen: Screen) -> Visual {
let visual = unsafe { xlib::XDefaultVisual(self.inner, screen.num) };
Visual { inner: visual }
}
/// Returns the root window for the given screen.
pub fn get_root_window(&self, screen: i32) -> Result<Window> {
let inner = unsafe { xlib::XRootWindow(self.inner, screen) };
pub fn get_root_window(&self, screen: Screen) -> Result<Window> {
let inner = unsafe { xlib::XRootWindow(self.inner, screen.num) };
if inner == 0 {
return Err(Error::GetWindowError);
}

View file

@ -13,6 +13,7 @@ mod drawable;
mod event;
mod image;
mod pixmap;
mod screen;
mod visual;
mod window;
@ -24,5 +25,6 @@ pub use self::drawable::Drawable;
pub use self::event::{Event, EventKind};
pub use self::image::{Image, ImageByteOrder, PixBuffer};
pub use self::pixmap::PixMap;
pub use self::screen::Screen;
pub use self::visual::{Visual, VisualInfo};
pub use self::window::{EventMask, SetWindowAttributes, Window, WindowAttributes};

18
x11/src/xlib/screen.rs Normal file
View file

@ -0,0 +1,18 @@
use x11::xlib;
use super::display::Display;
pub struct Screen<'a> {
pub(crate) display: &'a Display,
pub(crate) num: i32,
}
impl<'a> Screen<'a> {
pub fn width_in_pixels(&self) -> i32 {
unsafe { xlib::XDisplayWidth(self.display.inner, self.num) }
}
pub fn height_in_pixels(&self) -> i32 {
unsafe { xlib::XDisplayHeight(self.display.inner, self.num) }
}
}

View file

@ -9,6 +9,7 @@ use crate::rect::Rectangle;
use super::atom::Atom;
use super::display::{Display, GetDisplay};
use super::screen::Screen;
use super::drawable::Drawable;
use super::image::Image;
@ -33,7 +34,7 @@ impl<'a> Window<'a> {
Some(parent) => parent,
None => display.get_default_root_window()?,
};
let visual = display.default_visual(0);
let visual = display.default_visual(Screen { display, num: 0 });
let window = unsafe {
xlib::XCreateWindow(
display.as_raw(),