for some reason still can't get it to do full screen

This commit is contained in:
Michael Zhang 2018-09-30 07:05:02 -05:00
parent c7fc13ed64
commit a8e0349d2a
No known key found for this signature in database
GPG key ID: A1B65B603268116B
31 changed files with 1172 additions and 15051 deletions

804
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -5,16 +5,18 @@ version = "0.3.0"
authors = ["Michael Zhang <failed.down@gmail.com>"] authors = ["Michael Zhang <failed.down@gmail.com>"]
[workspace] [workspace]
members = [".", "imlib2-sys"] members = [".", "imlib2", "imlib2/imlib2-sys", "xlib"]
[lib] [lib]
crate-type = ["dylib", "rlib"] crate-type = ["dylib", "rlib"]
[dependencies] [dependencies]
failure = "0.1" failure = "0.1"
gl = "0.10"
glutin = "0.18"
imlib2 = { path = "imlib2" }
nanovg = { version = "1.0.2", features = ["gl3"] }
png = "0.12" png = "0.12"
imlib2-sys = { path = "imlib2-sys" }
libc = "0.2"
structopt = "0.2" structopt = "0.2"
time = "0.1" time = "0.1"
x11 = { version = "2.18", features = ["xlib"] } xlib = { path = "xlib" }

View file

@ -1,3 +0,0 @@
fn main() {
println!("cargo:rustc-link-lib=Imlib2");
}

File diff suppressed because it is too large Load diff

9
imlib2/Cargo.toml Normal file
View file

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

View file

@ -8,3 +8,4 @@ build = "build.rs"
path = "lib.rs" path = "lib.rs"
[build-dependencies] [build-dependencies]
bindgen = "0.40"

View file

@ -0,0 +1,20 @@
// bindgen build script by remexre
extern crate bindgen;
use std::env;
use std::path::PathBuf;
use bindgen::Builder;
fn main() {
println!("cargo:rustc-link-lib=Imlib2");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
Builder::default()
.header("wrapper.h")
.blacklist_type("max_align_t")
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Unable to write bindings");
}

5
imlib2/imlib2-sys/lib.rs Normal file
View file

@ -0,0 +1,5 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

View file

@ -0,0 +1 @@
#include "Imlib2.h"

View file

@ -3,7 +3,7 @@ use std::path::Path;
use imlib2_sys as im; use imlib2_sys as im;
use imlib2::Error; use Error;
use xlib::Drawable; use xlib::Drawable;
/// A simple wrapper around Imlib_Image /// A simple wrapper around Imlib_Image
@ -44,10 +44,18 @@ impl Image {
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(())
} }
/// Get raw image
pub fn as_raw(&self) -> im::Imlib_Image {
self.inner
}
} }
impl Drop for Image { impl Drop for Image {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { im::imlib_free_image() }; unsafe {
im::imlib_context_set_image(self.inner);
im::imlib_free_image();
}
} }
} }

View file

@ -1,12 +1,15 @@
//! Safe-ish bindings to imlib2 (at least the only parts I need). //! Safe-ish bindings to imlib2 (at least the only parts I need).
#[macro_use]
extern crate failure;
extern crate imlib2_sys;
extern crate xlib;
mod errors; mod errors;
mod image; mod image;
use imlib2_sys; pub use errors::Error;
pub use image::Image;
pub use self::errors::Error;
pub use self::image::Image;
pub use imlib2_sys::{Drawable, Pixmap}; pub use imlib2_sys::{Drawable, Pixmap};
use xlib::{Display, Visual}; use xlib::{Display, Visual};
@ -22,3 +25,13 @@ pub fn context_set_display(display: &Display) {
pub fn context_set_visual(visual: &Visual) { pub fn context_set_visual(visual: &Visual) {
unsafe { imlib2_sys::imlib_context_set_visual(visual.as_raw() as *mut imlib2_sys::Visual) }; unsafe { imlib2_sys::imlib_context_set_visual(visual.as_raw() as *mut imlib2_sys::Visual) };
} }
/// Set the visual for the imlib context.
pub fn context_set_image(image: &Image) {
unsafe { imlib2_sys::imlib_context_set_image(image.as_raw() as imlib2_sys::Imlib_Image) };
}
/// Get a pointer to the raw image data for the current image.
pub fn image_get_data() -> *mut u32 {
unsafe { imlib2_sys::imlib_image_get_data_for_reading_only() }
}

View file

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

View file

@ -1,11 +1,10 @@
use imlib2::{self, Image as Image2}; use imlib2::{self, Image as Image2};
use xlib::{Display, EventKind, Visual, Window}; use xlib::{Display, Visual, Window};
use errors::ScreenshotError; use errors::ScreenshotError;
use Options; use Options;
use Rectangle; use Rectangle;
use Region; use Region;
use SelectWindow;
pub struct GUI { pub struct GUI {
pub(crate) display: Display, pub(crate) display: Display,
@ -22,7 +21,7 @@ impl GUI {
let attr = window.get_attributes()?; let attr = window.get_attributes()?;
let mut width = attr.get_width(); let mut width = attr.get_width();
let mut height = attr.get_height(); let mut height = attr.get_height();
let root = self.display.get_default_root_window()?; let root = attr.get_root();
let (mut x, mut 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); imlib2::context_set_display(&self.display);
@ -31,7 +30,7 @@ impl GUI {
match opt.region { match opt.region {
Region::Selection => { Region::Selection => {
let region = self.interactive_select()?; let region = self.interactive_select(window)?;
x = region.x; x = region.x;
y = region.y; y = region.y;
width = region.width; width = region.width;
@ -53,29 +52,243 @@ impl GUI {
} }
/// Brings up an interactive selection GUI. /// Brings up an interactive selection GUI.
pub fn interactive_select(&self) -> Result<Rectangle, ScreenshotError> { pub fn interactive_select(&self, window: Window) -> 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 = self.display.get_default_root_window()?;
let root_im = root.get_image(); // let root_im = root.get_image();
let mut done = 0; // let mut done = 0;
let mut button_press = false; // let mut button_press = false;
while done == 0 && self.display.pending()? > 0 { // while done == 0 && self.display.pending()? > 0 {
let ev = self.display.next_event()?; // let ev = self.display.next_event()?;
match ev.kind() { // match ev.kind() {
EventKind::ButtonPress => { // EventKind::ButtonPress => {
button_press = true; // button_press = true;
} // }
EventKind::ButtonRelease => { // EventKind::ButtonRelease => {
if button_press { // if button_press {
done = 1; // done = 1;
} // }
button_press = false; // button_press = false;
} // }
_ => (), // _ => (),
} // }
// }
use gl;
use glutin::{
dpi::LogicalSize, ElementState, Event, EventsLoop, GlContext, GlWindow, KeyboardInput,
MouseButton, VirtualKeyCode, WindowBuilder, WindowEvent,
};
use nanovg::{Color, Image, ImagePattern, PathOptions, StrokeOptions};
use std::{f32::consts, slice};
let attr = window.get_attributes()?;
let width = attr.get_width();
let height = attr.get_height();
let root = attr.get_root();
println!("{} {}", width, height);
let (x, y, _) = self.display.translate_coordinates(window, 0, 0, root)?;
let mut evl = EventsLoop::new();
let mon = evl.get_primary_monitor();
// TODO: handle error
let wb = WindowBuilder::new()
.with_decorations(false)
.with_always_on_top(true)
.with_dimensions(LogicalSize::new(width.into(), height.into()))
.with_fullscreen(Some(mon));
let ctx = glutin::ContextBuilder::new()
.with_vsync(false)
.with_multisampling(4)
.with_srgb(true);
let win = GlWindow::new(wb, ctx, &evl).expect("couldn't make window");
let f = win.get_hidpi_factor() as f64;
unsafe {
win.make_current().expect("couldn't make window");
gl::load_with(|sym| win.get_proc_address(sym) as *const _);
}
// win.set_inner_size((width, height).into());
// println!("size={:?} pos={:?} outer={:?}", win.get_inner_size(), win.get_inner_position(), win.get_outer_size());
// println!("{:?}", win.get_hidpi_factor());
imlib2::context_set_display(&self.display);
let visual = Visual::default(&self.display, 0);
imlib2::context_set_visual(&visual);
let img = Image2::create_from_drawable(window, 0, x, y, width as i32, height as i32, true)?;
imlib2::context_set_image(&img);
let len = (width * height) as usize;
let raw_data = unsafe { slice::from_raw_parts(imlib2::image_get_data(), len) };
// convert ARGB to RGBA
let mut data = vec![0u32; raw_data.len()];
data.copy_from_slice(raw_data);
for i in &mut data {
// fix the colors
*i = (*i & 0xff00ff00) | ((*i & 0xff) << 16) | ((*i >> 16) & 0xff);
}
let ctx = nanovg::ContextBuilder::new()
.build()
.expect("couldn't init nanovg");
let image = Image::new(&ctx)
.build_from_rgba(width as usize, height as usize, data.as_slice())
.expect("couldn't create image");
let mut running = true;
let mut down = false;
// drag start
let mut dx = -1.0f64;
let mut dy = -1.0f64;
// curr mouse
let mut mx = -1.0f64;
let mut my = -1.0f64;
// rect
let mut rectw = 0.0f64;
let mut recth = 0.0f64;
let mut delayed_down = false;
while running {
let mut redraw = true;
evl.poll_events(|event| match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested | WindowEvent::Destroyed => running = false,
WindowEvent::KeyboardInput {
input:
KeyboardInput {
virtual_keycode,
state,
..
},
..
} => match (virtual_keycode, state) {
(Some(VirtualKeyCode::Escape), ElementState::Released) => {
if down {
down = false;
} else {
running = false;
}
}
_ => (),
},
WindowEvent::CursorMoved { position, .. } => {
mx = position.x;
my = position.y;
if down {
if delayed_down {
dx = mx;
dy = my;
delayed_down = false;
} else {
redraw = true;
}
rectw = mx - dx;
recth = my - dy;
}
}
WindowEvent::MouseInput { button, state, .. } => match button {
MouseButton::Left => {
down = match state {
ElementState::Pressed => {
delayed_down = true;
if mx < 0.0 || my < 0.0 {
} else {
dx = mx;
dy = my;
}
true
}
ElementState::Released => {
if down && rectw.abs() > 0.0 && recth.abs() > 0.0 {
running = false;
}
false
}
};
}
_ => (),
},
_ => (),
},
_ => (),
});
if !redraw {
// don't do anything if it's not moved
continue;
}
// let size = win.get_inner_size().unwrap();
// let (width, height) = (size.width as i32, size.height as i32);
unsafe {
gl::Viewport(0, 0, width as i32, height as i32);
gl::ClearColor(0.3, 0.3, 0.32, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT | gl::STENCIL_BUFFER_BIT);
}
let (width, height) = (width as f64, height as f64);
ctx.frame((width as f32, height as f32), f as f32, |frame| {
let path_opts = PathOptions::default();
frame.path(
|path| {
path.rect((0.0, 0.0), ((width * f) as f32, (height * f) as f32));
// path.fill(Color::from_rgba(200, 200, 200, 255), Default::default());
path.fill(
ImagePattern {
image: &image,
origin: (0.0, 0.0),
size: (width as f32, height as f32),
angle: 0.0 / 180.0 * consts::PI,
alpha: 1.0,
},
Default::default(),
)
},
path_opts,
);
if down && rectw.abs() > 0.0 && recth.abs() > 0.0 {
frame.path(
|path| {
path.rect(
((dx * f) as f32, (dy * f) as f32),
((rectw * f) as f32, (recth * f) as f32),
);
path.stroke(
Color::from_rgba(0, 0, 0, 255),
StrokeOptions {
width: 2.0,
..Default::default()
},
);
},
path_opts,
);
}
});
win.swap_buffers().expect("couldn't swap buffers");
}
if rectw.abs() > 0.0 && recth.abs() > 0.0 {
let mut x = dx;
let mut y = dy;
if rectw < 0.0 {
x += rectw;
}
if recth < 0.0 {
y += recth;
}
Ok(Rectangle::new(
(x * f) as i32,
(y * f) as i32,
(rectw.abs() * f) as u32,
(recth.abs() * f) as u32,
))
} else {
Err(ScreenshotError::Error)
} }
Err(ScreenshotError::Error)
} }
} }

View file

@ -4,22 +4,20 @@
#[macro_use] #[macro_use]
extern crate failure; extern crate failure;
extern crate imlib2_sys; extern crate gl;
extern crate libc; extern crate glutin;
extern crate imlib2;
extern crate nanovg;
extern crate png; extern crate png;
#[macro_use] #[macro_use]
extern crate structopt; extern crate structopt;
extern crate time; extern crate time;
extern crate x11; extern crate xlib;
mod capture; mod capture;
mod errors; mod errors;
mod gui; mod gui;
mod options; mod options;
mod window;
pub mod imlib2;
pub mod xlib;
use errors::ScreenshotError; use errors::ScreenshotError;
use structopt::StructOpt; use structopt::StructOpt;
@ -27,4 +25,11 @@ use xlib::Rectangle;
pub use capture::capture; pub use capture::capture;
pub use options::{Options, Region}; pub use options::{Options, Region};
pub use window::SelectWindow;
use failure::Error;
#[allow(missing_docs)]
pub fn main() -> Result<(), Error> {
let opt = Options::from_args();
capture(&opt).map(|_| ()).map_err(|err| err.into())
}

View file

@ -1,12 +0,0 @@
extern crate failure;
extern crate screenshot;
extern crate structopt;
use failure::Error;
use screenshot::{capture, Options};
use structopt::StructOpt;
pub fn main() -> Result<(), Error> {
let opt = Options::from_args();
capture(&opt).map(|_| ()).map_err(|err| err.into())
}

View file

@ -1,17 +0,0 @@
use xlib::{Display, Rectangle, Window};
use errors::ScreenshotError;
/// A window that's opened for the user to select a region
pub struct SelectWindow {
inner: Window,
}
impl SelectWindow {
/// Creates a new SelectWindow
pub fn new(display: &Display) -> Result<Self, ScreenshotError> {
// TODO: unhardcode
let window = Window::create(display, None, Rectangle::new(0, 0, 1920, 1080))?;
Ok(SelectWindow { inner: window })
}
}

View file

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

View file

@ -1,30 +0,0 @@
//! Safe-ish bindings to parts of x11's xlib module.
//!
//! I need this for my project.
mod cursor;
mod display;
mod drawable;
mod errors;
mod event;
mod gc;
mod image;
mod rect;
mod visual;
mod window;
#[allow(non_upper_case_globals)]
#[allow(missing_docs)]
mod cursorfont;
pub use self::cursor::Cursor;
pub use self::cursorfont::*;
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};

9
xlib/Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "xlib"
version = "0.1.0"
authors = ["Michael Zhang <failed.down@gmail.com>"]
[dependencies]
failure = "0.1"
libc = "0.2"
x11 = { version = "2.18", features = ["xlib"] }

View file

@ -3,7 +3,7 @@ use std::ffi::CString;
use libc; use libc;
use x11::xlib as x; use x11::xlib as x;
use xlib::{Cursor, Event, Visual, Window, X11Error}; use {Cursor, Event, Visual, Window, X11Error};
/// A connection to an X server. /// A connection to an X server.
pub struct Display { pub struct Display {

View file

@ -1,6 +1,6 @@
use x11::xlib as x; use x11::xlib as x;
use xlib::{GetDisplay, Image, Rectangle, X11Error}; use {GetDisplay, Image, Rectangle, X11Error};
/// Anything that's drawable /// Anything that's drawable
pub trait Drawable: GetDisplay { pub trait Drawable: GetDisplay {

View file

@ -1,7 +1,7 @@
use libc; use libc;
use x11::xlib as x; use x11::xlib as x;
use xlib::X11Error; use X11Error;
/// An x11 Event /// An x11 Event
pub struct Event { pub struct Event {

View file

@ -1,6 +1,6 @@
use x11::xlib as x; use x11::xlib as x;
use xlib::X11Error; use X11Error;
/// A handle to an XImage. /// A handle to an XImage.
pub struct Image { pub struct Image {
@ -17,8 +17,10 @@ pub enum ImageByteOrder {
/// The buffer pointed to by an XImage. /// The buffer pointed to by an XImage.
pub struct PixBuffer { pub struct PixBuffer {
pub(self) buf: *mut u8, /// The raw pointer to the buffer
pub(self) size: usize, pub buf: *mut u8,
/// The size of the buffer
pub size: usize,
} }
impl Image { impl Image {

33
xlib/src/lib.rs Normal file
View file

@ -0,0 +1,33 @@
//! Safe-ish bindings to parts of x11's xlib module.
//!
//! I need this for my project.
#[macro_use]
extern crate failure;
extern crate libc;
extern crate x11;
mod cursor;
mod display;
mod drawable;
mod errors;
mod event;
mod image;
mod rect;
mod visual;
mod window;
#[allow(non_upper_case_globals)]
#[allow(missing_docs)]
mod cursorfont;
pub use cursor::Cursor;
pub use cursorfont::*;
pub use display::{Display, GetDisplay};
pub use drawable::Drawable;
pub use errors::X11Error;
pub use event::{Event, EventKind};
pub use image::{Image, ImageByteOrder, PixBuffer};
pub use rect::Rectangle;
pub use visual::Visual;
pub use window::{Window, WindowAttributes};

View file

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

View file

@ -4,7 +4,7 @@ use std::mem;
use libc; use libc;
use x11::xlib as x; use x11::xlib as x;
use xlib::{Display, Drawable, GetDisplay, Image, Rectangle, X11Error}; use {Display, Drawable, GetDisplay, Image, Rectangle, X11Error};
/// A wrapper around a window handle. /// A wrapper around a window handle.
#[derive(Copy, Clone, PartialEq, Eq)] #[derive(Copy, Clone, PartialEq, Eq)]
@ -15,6 +15,7 @@ pub struct Window {
/// Window Attributes /// Window Attributes
pub struct WindowAttributes { pub struct WindowAttributes {
pub(super) display: *mut x::Display,
pub(self) inner: *mut x::XWindowAttributes, pub(self) inner: *mut x::XWindowAttributes,
} }
@ -60,7 +61,10 @@ impl Window {
let result = unsafe { x::XGetWindowAttributes(self.display, self.inner, attr) }; let result = unsafe { x::XGetWindowAttributes(self.display, self.inner, attr) };
match result { match result {
0 => Err(X11Error::GetAttributesError), 0 => Err(X11Error::GetAttributesError),
_ => Ok(WindowAttributes { inner: attr }), _ => Ok(WindowAttributes {
display: self.display,
inner: attr,
}),
} }
} }
@ -122,6 +126,14 @@ impl WindowAttributes {
pub fn get_height(&self) -> u32 { pub fn get_height(&self) -> u32 {
unsafe { (*self.inner).height as u32 } unsafe { (*self.inner).height as u32 }
} }
/// Get the root window of this window
pub fn get_root(&self) -> Window {
Window {
display: self.display,
inner: unsafe { (*self.inner).root },
}
}
} }
impl Drop for WindowAttributes { impl Drop for WindowAttributes {