move shit around

This commit is contained in:
Michael Zhang 2018-09-11 16:58:16 -05:00
parent 92d476df05
commit dc9d6d3dc3
No known key found for this signature in database
GPG key ID: A1B65B603268116B
28 changed files with 252 additions and 162 deletions

24
Cargo.lock generated
View file

@ -104,15 +104,6 @@ dependencies = [
"synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "imlib2"
version = "0.1.0"
dependencies = [
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"imlib2-sys 0.1.0",
"x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "imlib2-sys" name = "imlib2-sys"
version = "0.1.0" version = "0.1.0"
@ -212,11 +203,12 @@ name = "screenshot"
version = "0.3.0" version = "0.3.0"
dependencies = [ dependencies = [
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"imlib2 0.1.0", "imlib2-sys 0.1.0",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "png 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"xlib 0.1.0", "x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -356,16 +348,6 @@ dependencies = [
"pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "xlib"
version = "0.1.0"
dependencies = [
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"imlib2 0.1.0",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"x11 2.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata] [metadata]
"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"

View file

@ -5,7 +5,7 @@ version = "0.3.0"
authors = ["Michael Zhang <failed.down@gmail.com>"] authors = ["Michael Zhang <failed.down@gmail.com>"]
[workspace] [workspace]
members = [".", "imlib2", "imlib2/imlib2-sys", "xlib"] members = [".", "imlib2-sys"]
[lib] [lib]
crate-type = ["dylib", "rlib"] crate-type = ["dylib", "rlib"]
@ -13,7 +13,8 @@ crate-type = ["dylib", "rlib"]
[dependencies] [dependencies]
failure = "0.1" failure = "0.1"
png = "0.12" png = "0.12"
imlib2 = { path = "imlib2" } imlib2-sys = { path = "imlib2-sys" }
libc = "0.2"
structopt = "0.2" structopt = "0.2"
time = "0.1" time = "0.1"
xlib = { path = "xlib" } x11 = { version = "2.18", features = ["xlib"] }

View file

@ -1,12 +0,0 @@
[package]
name = "imlib2"
version = "0.1.0"
authors = ["Michael Zhang <failed.down@gmail.com>"]
[lib]
path = "lib.rs"
[dependencies]
failure = "0.1"
imlib2-sys = { path = "imlib2-sys" }
x11 = { version = "2.18", features = ["xlib"] }

View file

@ -1,25 +0,0 @@
//! Safe-ish bindings to imlib2 (at least the only parts I need).
#![deny(missing_docs)]
#[macro_use]
extern crate failure;
extern crate imlib2_sys;
extern crate x11;
mod errors;
mod image;
pub use errors::Error;
pub use image::Image;
pub use imlib2_sys::{Drawable, Pixmap};
/// Set the display for the imlib context.
pub fn context_set_display(display: *mut x11::xlib::Display) {
unsafe { imlib2_sys::imlib_context_set_display(display as *mut imlib2_sys::_XDisplay) };
}
/// Set the visual for the imlib context.
pub fn context_set_visual(visual: *mut x11::xlib::Visual) {
unsafe { imlib2_sys::imlib_context_set_visual(visual as *mut imlib2_sys::Visual) };
}

View file

@ -11,7 +11,7 @@ pub fn capture(opt: &Options) -> Result<(), ScreenshotError> {
_ => gui.display.get_default_root_window()?, _ => gui.display.get_default_root_window()?,
}; };
let capture = gui.capture_window(window_to_capture)?; let capture = gui.capture_window(&opt, window_to_capture)?;
capture.save_image(&opt.outfile)?; capture.save_image(&opt.outfile)?;
Ok(()) Ok(())

View file

@ -1,9 +1,11 @@
use imlib2::{self, Image as Image2}; use imlib2::{self, Image as Image2};
use xlib::{Display, Image, Window, Visual}; use xlib::{Display, EventKind, Visual, Window};
use errors::ScreenshotError; use errors::ScreenshotError;
use Options;
use Rectangle; use Rectangle;
use SelectWindow; use SelectWindow;
use Region;
pub struct GUI { pub struct GUI {
pub(crate) display: Display, pub(crate) display: Display,
@ -15,19 +17,31 @@ impl GUI {
Ok(GUI { display }) Ok(GUI { display })
} }
/// Captures the window and produces a DynamicImage. /// Captures the window and produces an Image.
pub fn capture_window(&self, window: Window) -> Result<Image2, ScreenshotError> { pub fn capture_window(&self, opt: &Options, window: Window) -> Result<Image2, ScreenshotError> {
let attr = window.get_attributes()?; let attr = window.get_attributes()?;
let width = attr.get_width() as i32; let mut width = attr.get_width();
let height = attr.get_height() as i32; let mut height = attr.get_height();
let root = self.display.get_default_root_window()?; let root = self.display.get_default_root_window()?;
let (x, y, _) = self.display.translate_coordinates(window, 0, 0, root)?; let (mut x, mut y, _) = self.display.translate_coordinates(window, 0, 0, root)?;
imlib2::context_set_display(self.display.as_raw()); imlib2::context_set_display(&self.display);
let visual = Visual::default(&self.display, 0); let visual = Visual::default(&self.display, 0);
imlib2::context_set_visual(visual.as_raw()); imlib2::context_set_visual(&visual);
Image2::create_from_drawable(window, 0, x, y, width, height, true).map_err(|err| err.into()) match opt.region {
Region::Selection => {
let region = self.interactive_select()?;
x = region.x;
y = region.y;
width = region.width;
height = region.height;
},
_ => ()
}
Image2::create_from_drawable(window, 0, x, y, width as i32, height as i32, true)
.map_err(|err| err.into())
} }
/// Get the active window. /// Get the active window.
@ -40,8 +54,19 @@ impl GUI {
/// Brings up an interactive selection GUI. /// Brings up an interactive selection GUI.
#[allow(dead_code)] #[allow(dead_code)]
pub fn interactive_select(&self, _capture: &Image) -> Result<Rectangle, ScreenshotError> { pub fn interactive_select(&self) -> Result<Rectangle, ScreenshotError> {
let window = SelectWindow::new(&self.display); let window = SelectWindow::new(&self.display);
let root = self.display.get_default_root_window()?;
let root_im = root.get_image();
let mut done = 0;
while done == 0 && self.display.pending()? > 0 {
let ev = self.display.next_event()?;
match ev.kind() {
EventKind::None => (),
}
}
Err(ScreenshotError::Error) Err(ScreenshotError::Error)
} }
} }

View file

@ -2,9 +2,9 @@ use std::ffi::CString;
use std::path::Path; use std::path::Path;
use imlib2_sys as im; use imlib2_sys as im;
use x11;
use Error; use imlib2::Error;
use xlib::Drawable;
/// A simple wrapper around Imlib_Image /// A simple wrapper around Imlib_Image
pub struct Image { pub struct Image {
@ -14,7 +14,7 @@ pub struct Image {
impl Image { impl Image {
/// Creates an Image from a pixmap. /// Creates an Image from a pixmap.
pub fn create_from_drawable( pub fn create_from_drawable(
drawable: impl AsRef<im::Drawable>, drawable: impl Drawable,
pixmap: im::Pixmap, pixmap: im::Pixmap,
x: i32, x: i32,
y: i32, y: i32,
@ -22,7 +22,7 @@ impl Image {
height: i32, height: i32,
grab_x: bool, grab_x: bool,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
unsafe { im::imlib_context_set_drawable(*drawable.as_ref()) }; unsafe { im::imlib_context_set_drawable(drawable.as_drawable()) };
let image = unsafe { let image = unsafe {
im::imlib_create_image_from_drawable( im::imlib_create_image_from_drawable(
pixmap, pixmap,
@ -33,15 +33,21 @@ impl Image {
if grab_x { 1 } else { 0 }, if grab_x { 1 } else { 0 },
) as im::Imlib_Image ) as im::Imlib_Image
}; };
unsafe { im::imlib_context_set_image(image) };
Ok(Image { inner: image }) Ok(Image { inner: image })
} }
/// Save this image /// Save this image
pub fn save_image(&self, file: impl AsRef<Path>) -> Result<(), Error> { pub fn save_image(&self, file: impl AsRef<Path>) -> Result<(), Error> {
unsafe { im::imlib_context_set_image((*self).inner) };
let mut error = 0; let mut error = 0;
let path = CString::new(file.as_ref().to_str().unwrap()).unwrap(); let path = CString::new(file.as_ref().to_str().unwrap()).unwrap();
unsafe { im::imlib_save_image_with_error_return(path.as_ptr(), &mut error) }; unsafe { im::imlib_save_image_with_error_return(path.as_ptr(), &mut error) };
Ok(()) Ok(())
} }
} }
impl Drop for Image {
fn drop(&mut self) {
unsafe { im::imlib_free_image() };
}
}

26
src/imlib2/mod.rs Normal file
View file

@ -0,0 +1,26 @@
//! Safe-ish bindings to imlib2 (at least the only parts I need).
#![deny(missing_docs)]
mod errors;
mod image;
use imlib2_sys;
pub use self::errors::Error;
pub use self::image::Image;
pub use imlib2_sys::{Drawable, Pixmap};
use xlib::{Display, Visual};
/// Set the display for the imlib context.
pub fn context_set_display(display: &Display) {
unsafe {
imlib2_sys::imlib_context_set_display(display.as_raw() as *mut imlib2_sys::_XDisplay)
};
}
/// Set the visual for the imlib context.
pub fn context_set_visual(visual: &Visual) {
unsafe { imlib2_sys::imlib_context_set_visual(visual.as_raw() as *mut imlib2_sys::Visual) };
}

View file

@ -1,11 +1,14 @@
#![feature(try_from)]
#[macro_use] #[macro_use]
extern crate failure; extern crate failure;
extern crate imlib2; extern crate imlib2_sys;
extern crate libc;
extern crate png; extern crate png;
#[macro_use] #[macro_use]
extern crate structopt; extern crate structopt;
extern crate time; extern crate time;
extern crate xlib; extern crate x11;
mod capture; mod capture;
mod errors; mod errors;
@ -13,9 +16,13 @@ mod gui;
mod options; mod options;
mod window; mod window;
pub mod imlib2;
pub mod xlib;
use structopt::StructOpt; use structopt::StructOpt;
use xlib::Rectangle; use xlib::Rectangle;
use errors::ScreenshotError;
pub use capture::capture; pub use capture::capture;
pub use options::Options; pub use options::{Options, Region};
pub use window::SelectWindow; pub use window::SelectWindow;

View file

@ -8,6 +8,5 @@ use structopt::StructOpt;
pub fn main() -> Result<(), Error> { pub fn main() -> Result<(), Error> {
let opt = Options::from_args(); let opt = Options::from_args();
// let image = capture(&opt)?;
capture(&opt).map(|_| ()).map_err(|err| err.into()) capture(&opt).map(|_| ()).map_err(|err| err.into())
} }

View file

@ -1,20 +1,16 @@
use std::path::PathBuf; use std::path::PathBuf;
#[derive(StructOpt)] use ScreenshotError;
pub enum Region { pub enum Region {
#[structopt(name = "fullscreen")]
Fullscreen, Fullscreen,
#[structopt(name = "window")]
ActiveWindow, ActiveWindow,
#[structopt(name = "select")]
Selection, Selection,
} }
#[derive(StructOpt)] #[derive(StructOpt)]
pub struct Options { pub struct Options {
#[structopt(subcommand)] #[structopt(parse(try_from_str = "Region::from_str"))]
pub region: Region, pub region: Region,
#[structopt(short = "o", long = "out", parse(from_os_str))] #[structopt(short = "o", long = "out", parse(from_os_str))]
@ -23,3 +19,14 @@ pub struct Options {
#[structopt(short = "c")] #[structopt(short = "c")]
pub clipboard: bool, pub clipboard: bool,
} }
impl Region {
pub fn from_str(x: &str) -> Result<Self, ScreenshotError> {
match x {
"fullscreen" => Ok(Region::Fullscreen),
"window" => Ok(Region::ActiveWindow),
"select" | "selection" => Ok(Region::Selection),
_ => Err(ScreenshotError::Error),
}
}
}

View file

@ -1,4 +1,4 @@
use xlib::{Display, Window, Rectangle}; use xlib::{Display, Rectangle, Window};
use errors::ScreenshotError; use errors::ScreenshotError;

View file

@ -1,16 +1,21 @@
use std::ffi::CString; use std::ffi::CString;
use libc;
use x11::xlib as x; use x11::xlib as x;
use Visual; use xlib::{Event, Visual, Window, X11Error};
use Window;
use X11Error;
/// A connection to an X server. /// A connection to an X server.
pub struct Display { pub struct Display {
inner: *mut x::Display, inner: *mut x::Display,
} }
/// Something that's part of a display.
pub trait GetDisplay {
/// Get the current display
fn get_display(&self) -> *mut x::Display;
}
impl Display { impl Display {
/// Opens a new connection to an X server. /// Opens a new connection to an X server.
/// ///
@ -25,6 +30,18 @@ impl Display {
Ok(Display { inner }) Ok(Display { inner })
} }
/// Get the next event, blocks until an event is reached.
pub fn next_event(&self) -> Result<Event, X11Error> {
let event =
unsafe { libc::malloc(::std::mem::size_of::<x::XAnyEvent>()) as *mut x::XAnyEvent };
Event::from_raw(event)
}
/// Returns the number of events that are still pending
pub fn pending(&self) -> Result<i32, X11Error> {
Ok(unsafe { x::XPending(self.inner) })
}
/// Gets the raw X Display handle /// Gets the raw X Display handle
pub fn as_raw(&self) -> *mut x::Display { pub fn as_raw(&self) -> *mut x::Display {
self.inner self.inner

26
src/xlib/drawable.rs Normal file
View file

@ -0,0 +1,26 @@
use x11::xlib as x;
use xlib::{GetDisplay, Image, Rectangle, X11Error};
/// Anything that's drawable
pub trait Drawable: GetDisplay {
/// Get drawable handle
fn as_drawable(&self) -> x::Drawable;
/// Capture a snapshot of this drawable, clipped by rect.
fn get_image(&self, rect: Rectangle) -> Result<Image, X11Error> {
let image = unsafe {
x::XGetImage(
self.get_display(),
self.as_drawable(),
rect.x as i32,
rect.y as i32,
rect.width,
rect.height,
0xffffffff,
x::ZPixmap,
)
};
Ok(Image { inner: image })
}
}

36
src/xlib/event.rs Normal file
View file

@ -0,0 +1,36 @@
use libc;
use x11::xlib as x;
use xlib::X11Error;
/// An x11 Event
pub struct Event {
inner: *mut x::XAnyEvent,
kind: EventKind,
}
/// Type of event
pub enum EventKind {
/// None event
None,
}
impl Event {
/// Returns the EventKind of this event
pub fn kind(&self) -> &EventKind {
&self.kind
}
pub(super) fn from_raw(event: *mut x::XAnyEvent) -> Result<Self, X11Error> {
Ok(Event {
inner: event,
kind: EventKind::None,
})
}
}
impl Drop for Event {
fn drop(&mut self) {
unsafe { libc::free(self.inner as *mut libc::c_void) };
}
}

2
src/xlib/gc.rs Normal file
View file

@ -0,0 +1,2 @@
/// Graphics context
pub struct GC {}

View file

@ -1,6 +1,6 @@
use x11::xlib as x; use x11::xlib as x;
use X11Error; use xlib::X11Error;
/// A handle to an XImage. /// A handle to an XImage.
pub struct Image { pub struct Image {

25
src/xlib/mod.rs Normal file
View file

@ -0,0 +1,25 @@
//! Safe-ish bindings to parts of x11's xlib module.
//!
//! I need this for my project.
#![deny(missing_docs)]
mod display;
mod drawable;
mod errors;
mod event;
mod gc;
mod image;
mod rect;
mod visual;
mod window;
pub use self::display::{Display, GetDisplay};
pub use self::drawable::Drawable;
pub use self::errors::X11Error;
pub use self::event::{Event, EventKind};
pub use self::gc::GC;
pub use self::image::{Image, ImageByteOrder, PixBuffer};
pub use self::rect::Rectangle;
pub use self::visual::Visual;
pub use self::window::{Window, WindowAttributes};

View file

@ -2,9 +2,9 @@
#[derive(Debug)] #[derive(Debug)]
pub struct Rectangle { pub struct Rectangle {
/// x /// x
pub x: u32, pub x: i32,
/// y /// y
pub y: u32, pub y: i32,
/// width /// width
pub width: u32, pub width: u32,
/// height /// height
@ -13,7 +13,7 @@ pub struct Rectangle {
impl Rectangle { impl Rectangle {
/// Create a new Rectangle from u32s /// Create a new Rectangle from u32s
pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { pub fn new(x: i32, y: i32, width: u32, height: u32) -> Self {
Rectangle { Rectangle {
x, x,
y, y,
@ -21,4 +21,4 @@ impl Rectangle {
height, height,
} }
} }
} }

View file

@ -1,6 +1,6 @@
use x11::xlib as x; use x11::xlib as x;
use Display; use xlib::Display;
/// A wrapper around a Visual /// A wrapper around a Visual
pub struct Visual { pub struct Visual {

View file

@ -1,13 +1,10 @@
use std::mem; use std::mem;
use imlib2::Drawable; // use imlib2::Drawable;
use libc; use libc;
use x11::xlib as x; use x11::xlib as x;
use Display; use xlib::{Display, Drawable, GetDisplay, Image, Rectangle, X11Error};
use Image;
use Rectangle;
use X11Error;
/// A wrapper around a window handle. /// A wrapper around a window handle.
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
@ -67,36 +64,44 @@ impl Window {
} }
} }
/// Capture a snapshot of this window.
pub fn get_image(&self) -> Result<Image, X11Error> {
let attr = self.get_attributes()?;
let image = unsafe {
x::XGetImage(
self.display,
self.inner,
attr.get_x(),
attr.get_y(),
attr.get_width(),
attr.get_height(),
0xffffffff,
x::ZPixmap,
)
};
Ok(Image { inner: image })
}
/// Get the raw window handle /// Get the raw window handle
pub fn as_raw(&self) -> x::Window { pub fn as_raw(&self) -> x::Window {
self.inner self.inner
} }
}
impl AsRef<Drawable> for Window { /// Get image
fn as_ref(&self) -> &Drawable { pub fn get_image(&self) -> Result<Image, X11Error> {
&self.inner let attr = self.get_attributes()?;
Drawable::get_image(
self,
Rectangle::new(
attr.get_x(),
attr.get_y(),
attr.get_width(),
attr.get_height(),
),
)
} }
} }
impl GetDisplay for Window {
fn get_display(&self) -> *mut x::Display {
self.display
}
}
impl Drawable for Window {
fn as_drawable(&self) -> x::Drawable {
self.inner
}
}
// impl AsRef<Drawable> for Window {
// fn as_ref(&self) -> &Drawable {
// &self.inner
// }
// }
impl WindowAttributes { impl WindowAttributes {
/// Gets the width of the window /// Gets the width of the window
pub fn get_x(&self) -> i32 { pub fn get_x(&self) -> i32 {

View file

@ -1,11 +0,0 @@
[package]
name = "xlib"
description = "Safe-ish bindings to xlib (or at least the parts that I need)"
version = "0.1.0"
authors = ["Michael Zhang <failed.down@gmail.com>"]
[dependencies]
failure = "0.1"
imlib2 = { path = "../imlib2" }
libc = "0.2"
x11 = { version = "2.18", features = ["xlib"] }

View file

@ -1,26 +0,0 @@
//! Safe-ish bindings to parts of x11's xlib module.
//!
//! I need this for my project.
#![deny(missing_docs)]
#[macro_use]
extern crate failure;
extern crate imlib2;
extern crate libc;
extern crate x11;
mod display;
mod errors;
mod image;
mod visual;
mod rect;
mod window;
pub use display::Display;
pub use errors::X11Error;
pub use image::{Image, ImageByteOrder, PixBuffer};
pub use visual::Visual;
pub use rect::Rectangle;
pub use window::{Window, WindowAttributes};