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" version = "0.5.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cfg-if",
"image", "image",
"leanshot-x11", "leanshot-x11",
"libc", "libc",

View file

@ -12,19 +12,28 @@ members = ["x11"]
[features] [features]
default = ["backend-x11", "backend-x11-glx"] default = ["backend-x11", "backend-x11-glx"]
backend-x11 = [] backend-x11 = ["leanshot-x11"]
backend-x11-glx = ["backend-x11"] backend-x11-glx = ["backend-x11", "leanshot-x11/glx"]
backend-xcb = ["xcb-util", "xcb"] backend-xcb = ["xcb-util", "xcb"]
[dependencies] [dependencies]
anyhow = "1.0.38" anyhow = "1.0.42"
image = { version = "0.23.13", default-features = false, features = ["jpeg", "png"] } image = { version = "0.23.14", default-features = false, features = ["jpeg", "png"] }
leanshot-x11 = { path = "x11" }
log = "0.4.14" log = "0.4.14"
stderrlog = "0.5.1" stderrlog = "0.5.1"
structopt = "0.3.21" structopt = "0.3.22"
libc = "0.2.86" libc = "0.2.98"
# x11
leanshot-x11 = { path = "x11", optional = true }
# xcb
xcb-util = { version = "0.3.0", features = ["image", "cursor"], optional = true } xcb-util = { version = "0.3.0", features = ["image", "cursor"], optional = true }
xcb = { version = "0.9.0", 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 { 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<()>; fn save_cropped_to(&self, path: impl AsRef<Path>, section: Option<Rectangle>) -> Result<()>;
} }

View file

@ -1,7 +1,8 @@
use std::path::Path; use std::path::Path;
use anyhow::Result; 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::gui_trait::{Capture, Gui};
use crate::rect::Rectangle; use crate::rect::Rectangle;
@ -15,33 +16,71 @@ impl X11Gui {
let disp = Display::connect(None)?; let disp = Display::connect(None)?;
Ok(X11Gui { conn: disp }) Ok(X11Gui { conn: disp })
} }
fn get_default_screen(&self) -> Screen {
self.conn.default_screen()
}
} }
impl Gui for X11Gui { impl Gui for X11Gui {
type Capture = ScreenCapture; 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( fn interactive_select(
&self, &self,
_: &<Self as Gui>::Capture, _: &Self::Capture,
) -> Result<Option<Rectangle>, anyhow::Error> { ) -> Result<Option<Rectangle>> {
todo!() todo!()
} }
} }
pub struct ScreenCapture {} pub struct ScreenCapture {
image: XImage,
}
impl Capture for ScreenCapture { impl Capture for ScreenCapture {
fn save_to(&self, _: impl AsRef<Path>) -> Result<(), anyhow::Error> {
todo!()
}
fn save_cropped_to( fn save_cropped_to(
&self, &self,
_: impl AsRef<Path>, to: impl AsRef<Path>,
_: Option<Rectangle>, section: Option<Rectangle>,
) -> Result<(), anyhow::Error> { ) -> Result<()> {
todo!() 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 { 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<()> { fn save_cropped_to(&self, to: impl AsRef<Path>, section: Option<Rectangle>) -> Result<()> {
let to = to.as_ref(); let to = to.as_ref();
let image = ImageBuffer::<Bgra<u8>, _>::from_raw( let image = ImageBuffer::<Bgra<u8>, _>::from_raw(

View file

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

View file

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

View file

@ -13,6 +13,7 @@ mod drawable;
mod event; mod event;
mod image; mod image;
mod pixmap; mod pixmap;
mod screen;
mod visual; mod visual;
mod window; mod window;
@ -24,5 +25,6 @@ pub use self::drawable::Drawable;
pub use self::event::{Event, EventKind}; pub use self::event::{Event, EventKind};
pub use self::image::{Image, ImageByteOrder, PixBuffer}; pub use self::image::{Image, ImageByteOrder, PixBuffer};
pub use self::pixmap::PixMap; pub use self::pixmap::PixMap;
pub use self::screen::Screen;
pub use self::visual::{Visual, VisualInfo}; pub use self::visual::{Visual, VisualInfo};
pub use self::window::{EventMask, SetWindowAttributes, Window, WindowAttributes}; 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::atom::Atom;
use super::display::{Display, GetDisplay}; use super::display::{Display, GetDisplay};
use super::screen::Screen;
use super::drawable::Drawable; use super::drawable::Drawable;
use super::image::Image; use super::image::Image;
@ -33,7 +34,7 @@ impl<'a> Window<'a> {
Some(parent) => parent, Some(parent) => parent,
None => display.get_default_root_window()?, None => display.get_default_root_window()?,
}; };
let visual = display.default_visual(0); let visual = display.default_visual(Screen { display, num: 0 });
let window = unsafe { let window = unsafe {
xlib::XCreateWindow( xlib::XCreateWindow(
display.as_raw(), display.as_raw(),