From c519114a9f34644017bc75e5e3c38ad61cc15e74 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Wed, 28 Jul 2021 16:25:32 -0500 Subject: [PATCH] fullscreen for x11 --- Cargo.lock | 1 - Cargo.toml | 25 +++++++++----- src/gui_trait.rs | 5 ++- src/gui_x11.rs | 67 ++++++++++++++++++++++++++++++-------- src/gui_xcb.rs | 4 --- src/main.rs | 1 + x11/src/xlib/display.rs | 18 +++++++--- x11/src/xlib/mod.rs | 2 ++ x11/src/xlib/screen.rs | 18 ++++++++++ x11/src/xlib/window/mod.rs | 3 +- 10 files changed, 111 insertions(+), 33 deletions(-) create mode 100644 x11/src/xlib/screen.rs diff --git a/Cargo.lock b/Cargo.lock index d163be9..82c33a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -185,7 +185,6 @@ name = "leanshot" version = "0.5.0" dependencies = [ "anyhow", - "cfg-if", "image", "leanshot-x11", "libc", diff --git a/Cargo.toml b/Cargo.toml index 19ac64f..aad048d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/src/gui_trait.rs b/src/gui_trait.rs index ef407fd..c9d8c1f 100644 --- a/src/gui_trait.rs +++ b/src/gui_trait.rs @@ -11,6 +11,9 @@ pub trait Gui { } pub trait Capture { - fn save_to(&self, path: impl AsRef) -> Result<()>; + fn save_to(&self, to: impl AsRef) -> Result<()> { + self.save_cropped_to(to, None) + } + fn save_cropped_to(&self, path: impl AsRef, section: Option) -> Result<()>; } diff --git a/src/gui_x11.rs b/src/gui_x11.rs index 399adda..50cd164 100644 --- a/src/gui_x11.rs +++ b/src/gui_x11.rs @@ -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<::Capture, anyhow::Error> { - todo!() + + fn capture_entire_screen(&self) -> Result { + // 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, - _: &::Capture, - ) -> Result, anyhow::Error> { + _: &Self::Capture, + ) -> Result> { todo!() } } -pub struct ScreenCapture {} +pub struct ScreenCapture { + image: XImage, +} impl Capture for ScreenCapture { - fn save_to(&self, _: impl AsRef) -> Result<(), anyhow::Error> { - todo!() - } - fn save_cropped_to( &self, - _: impl AsRef, - _: Option, - ) -> Result<(), anyhow::Error> { - todo!() + to: impl AsRef, + section: Option, + ) -> Result<()> { + let to = to.as_ref(); + + let buffer = self.image.buffer(); + + let image = ImageBuffer::, _>::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(()) } } diff --git a/src/gui_xcb.rs b/src/gui_xcb.rs index fc0c69a..84cc100 100644 --- a/src/gui_xcb.rs +++ b/src/gui_xcb.rs @@ -296,10 +296,6 @@ pub struct ScreenCapture { } impl Capture for ScreenCapture { - fn save_to(&self, to: impl AsRef) -> Result<()> { - self.save_cropped_to(to, None) - } - fn save_cropped_to(&self, to: impl AsRef, section: Option) -> Result<()> { let to = to.as_ref(); let image = ImageBuffer::, _>::from_raw( diff --git a/src/main.rs b/src/main.rs index 43a7431..c1eefd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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"))] diff --git a/x11/src/xlib/display.rs b/x11/src/xlib/display.rs index c1b3fca..528ac08 100644 --- a/x11/src/xlib/display.rs +++ b/x11/src/xlib/display.rs @@ -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 { - let inner = unsafe { xlib::XRootWindow(self.inner, screen) }; + pub fn get_root_window(&self, screen: Screen) -> Result { + let inner = unsafe { xlib::XRootWindow(self.inner, screen.num) }; if inner == 0 { return Err(Error::GetWindowError); } diff --git a/x11/src/xlib/mod.rs b/x11/src/xlib/mod.rs index 9e35a04..af81915 100644 --- a/x11/src/xlib/mod.rs +++ b/x11/src/xlib/mod.rs @@ -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}; diff --git a/x11/src/xlib/screen.rs b/x11/src/xlib/screen.rs new file mode 100644 index 0000000..8f63909 --- /dev/null +++ b/x11/src/xlib/screen.rs @@ -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) } + } +} diff --git a/x11/src/xlib/window/mod.rs b/x11/src/xlib/window/mod.rs index 22d2fc9..15243d3 100644 --- a/x11/src/xlib/window/mod.rs +++ b/x11/src/xlib/window/mod.rs @@ -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(),