From dcdf13594a5991f91564cdcb6b4f1e41b9a0a36a Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Thu, 24 Dec 2020 12:28:13 -0600 Subject: [PATCH] ouais --- Cargo.lock | 39 +++-------------------------- src/gui.rs | 71 ++++++++++++++++++++++++++++++----------------------- src/main.rs | 8 +++--- 3 files changed, 48 insertions(+), 70 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d92540..28678ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,12 +29,12 @@ checksum = "68803225a7b13e47191bab76f2687382b60d259e8cf37f6e1893658b84bb9479" [[package]] name = "atty" -version = "0.2.11" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ + "hermit-abi", "libc", - "termion", "winapi", ] @@ -355,12 +355,6 @@ dependencies = [ "libc", ] -[[package]] -name = "numtoa" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" - [[package]] name = "png" version = "0.16.8" @@ -440,21 +434,6 @@ dependencies = [ "num_cpus", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -dependencies = [ - "redox_syscall", -] - [[package]] name = "scoped_threadpool" version = "0.1.9" @@ -530,18 +509,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "termion" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" -dependencies = [ - "libc", - "numtoa", - "redox_syscall", - "redox_termios", -] - [[package]] name = "textwrap" version = "0.11.0" diff --git a/src/gui.rs b/src/gui.rs index a793e07..751c3d5 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -4,8 +4,7 @@ use anyhow::Result; use image::{Bgra, DynamicImage, ImageBuffer}; use xcb::{ base::Connection, - xproto::{self, Rectangle}, - Screen, + xproto::{self, Rectangle, Screen}, }; use xcb_util::image as xcb_image; @@ -47,7 +46,7 @@ impl Gui { } pub fn interactive_select(&self, image: &ScreenCapture) -> Result> { - let id = self.conn.generate_id(); + let window_id = self.conn.generate_id(); let screen = self.get_default_screen(); let root_window = screen.root(); let (width, height) = (screen.width_in_pixels(), screen.height_in_pixels()); @@ -60,7 +59,7 @@ impl Gui { xproto::create_window( &self.conn, xcb::COPY_FROM_PARENT as u8, - id, + window_id, root_window, 0, 0, @@ -71,14 +70,13 @@ impl Gui { screen.root_visual(), &[ (xcb::CW_OVERRIDE_REDIRECT, 1), - // (xcb::CW_BACK_PIXEL, screen.white_pixel()), (xcb::CW_EVENT_MASK, evt_mask), (xcb::CW_CURSOR, cursor), ], ) .request_check()?; - xproto::map_window(&self.conn, id).request_check()?; + xproto::map_window(&self.conn, window_id).request_check()?; self.conn.flush(); let wm_state = xproto::intern_atom(&self.conn, true, "_NET_WM_STATE") @@ -90,7 +88,7 @@ impl Gui { xproto::change_property( &self.conn, xcb::PROP_MODE_REPLACE as u8, - id, + window_id, wm_state, 4, 32, @@ -101,7 +99,7 @@ impl Gui { xproto::set_input_focus( &self.conn, xcb::INPUT_FOCUS_POINTER_ROOT as u8, - id, + window_id, xcb::CURRENT_TIME, ) .request_check()?; @@ -109,8 +107,8 @@ impl Gui { info!("Grabbing keyboard..."); xproto::grab_keyboard( &self.conn, - false, - id, + true, + window_id, xcb::CURRENT_TIME, xcb::GRAB_MODE_ASYNC as u8, xcb::GRAB_MODE_ASYNC as u8, @@ -121,7 +119,7 @@ impl Gui { xproto::grab_pointer( &self.conn, false, - id, + window_id, evt_mask as u16, xcb::GRAB_MODE_ASYNC as u8, xcb::GRAB_MODE_ASYNC as u8, @@ -131,11 +129,11 @@ impl Gui { ) .get_reply()?; - let gc = self.conn.generate_id(); + let window_gc = self.conn.generate_id(); xproto::create_gc( &self.conn, - gc, - id, + window_gc, + window_id, &[ (xcb::GC_FOREGROUND, screen.white_pixel()), (xcb::GC_BACKGROUND, screen.white_pixel()), @@ -146,9 +144,12 @@ impl Gui { #[derive(Default)] struct State { dragging: bool, + + // where did we start dragging from dx: i16, dy: i16, + // where is the mouse right now mx: i16, my: i16, } @@ -172,11 +173,11 @@ impl Gui { let mut cancelled = false; let redraw = |state: &State| { - xcb_image::put(&self.conn, id, gc, &image.image, 0, 0); + xcb_image::put(&self.conn, window_id, window_gc, &image.image, 0, 0); if state.dragging { let rect = state.rect(); - xproto::poly_rectangle(&self.conn, id, gc, &[rect]); + xproto::poly_rectangle(&self.conn, window_id, window_gc, &[rect]); } self.conn.flush(); @@ -188,15 +189,21 @@ impl Gui { match evt.response_type() { xcb::KEY_RELEASE => { let key_evt = unsafe { xcb::cast_event::(&evt) }; + info!("released key {:?}", key_evt.detail()); + if key_evt.detail() == 9 { - cancelled = true; - break; + if state.dragging { + state.dragging = false; + } else { + cancelled = true; + break; + } } } xcb::KEY_PRESS => {} xcb::BUTTON_PRESS => { let button_evt = unsafe { xcb::cast_event::(&evt) }; - info!("pressed {:?}", button_evt.detail()); + info!("pressed mouse button {:?}", button_evt.detail()); state.dx = button_evt.root_x(); state.dy = button_evt.root_y(); @@ -207,7 +214,7 @@ impl Gui { } xcb::BUTTON_RELEASE => { let button_evt = unsafe { xcb::cast_event::(&evt) }; - info!("released {:?}", button_evt.detail()); + info!("released mouse button {:?}", button_evt.detail()); // left mouse button if state.dragging && button_evt.detail() == 1 { @@ -241,11 +248,10 @@ pub struct ScreenCapture { impl ScreenCapture { pub fn save_to(&self, to: impl AsRef) -> Result<()> { - let section = Rectangle::new(0, 0, self.image.width(), self.image.height()); - self.save_cropped_to(to, section) + self.save_cropped_to(to, None) } - pub fn save_cropped_to(&self, to: impl AsRef, section: Rectangle) -> Result<()> { + pub fn save_cropped_to(&self, to: impl AsRef, section: Option) -> Result<()> { let to = to.as_ref(); let image = ImageBuffer::, _>::from_raw( self.image.width() as u32, @@ -256,14 +262,17 @@ impl ScreenCapture { let image = DynamicImage::ImageBgra8(image); let mut image = DynamicImage::ImageRgb8(image.into_rgb8()); - // TODO: compare the rectangles to see if we can skip the crop - // crop the image - let image = image.crop( - section.x() as u32, - section.y() as u32, - section.width() as u32, - section.height() as u32, - ); + 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/main.rs b/src/main.rs index 594f92c..a38b2e4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ mod gui; use std::path::PathBuf; use std::process; +use std::str::FromStr; use anyhow::Result; use structopt::StructOpt; @@ -31,7 +32,7 @@ fn main() -> Result<()> { } Region::Selection => { if let Some(rectangle) = gui.interactive_select(&capture)? { - capture.save_cropped_to(&opt.outfile, rectangle)?; + capture.save_cropped_to(&opt.outfile, Some(rectangle))?; } else { info!("Cancelled by user."); process::exit(1); @@ -65,8 +66,9 @@ pub enum Region { Selection, } -impl Region { - pub fn from_str(x: &str) -> Result { +impl FromStr for Region { + type Err = anyhow::Error; + fn from_str(x: &str) -> Result { match x { "fullscreen" => Ok(Region::Fullscreen), "select" | "selection" => Ok(Region::Selection),