forked from michael/leanshot
update
This commit is contained in:
parent
505f56766a
commit
6be5db5e57
6 changed files with 93 additions and 71 deletions
87
src/main.rs
87
src/main.rs
|
@ -31,52 +31,51 @@ pub fn main() -> Result<()> {
|
||||||
Region::Fullscreen | Region::Selection => {
|
Region::Fullscreen | Region::Selection => {
|
||||||
let mut image = gui.capture_full_screen()?;
|
let mut image = gui.capture_full_screen()?;
|
||||||
|
|
||||||
if let Region::Fullscreen = opt.region {
|
// calculate the full size of the image
|
||||||
// calculate the full size of the image
|
let mut min_x = 0;
|
||||||
let mut min_x = 0;
|
let mut min_y = 0;
|
||||||
let mut min_y = 0;
|
let mut max_x = 0;
|
||||||
let mut max_x = 0;
|
let mut max_y = 0;
|
||||||
let mut max_y = 0;
|
for (i, (_, screen)) in screen_layout.iter().enumerate() {
|
||||||
for (i, (_, screen)) in screen_layout.iter().enumerate() {
|
let left = screen.x;
|
||||||
let left = screen.x;
|
let right = screen.x + screen.width as i16;
|
||||||
let right = screen.x + screen.width as i16;
|
let top = screen.y;
|
||||||
let top = screen.y;
|
let bottom = screen.y + screen.height as i16;
|
||||||
let bottom = screen.y + screen.height as i16;
|
if i == 0 {
|
||||||
if i == 0 {
|
min_x = left;
|
||||||
min_x = left;
|
min_y = top;
|
||||||
min_y = top;
|
max_x = right;
|
||||||
max_x = right;
|
max_y = bottom;
|
||||||
max_y = bottom;
|
} else {
|
||||||
} else {
|
min_x = min_x.min(left);
|
||||||
min_x = min_x.min(left);
|
min_y = min_y.min(top);
|
||||||
min_y = min_y.min(top);
|
max_x = max_x.max(right);
|
||||||
max_x = max_x.max(right);
|
max_y = max_y.max(bottom);
|
||||||
max_y = max_y.max(bottom);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
|
||||||
"full virtual screen rect : ({}, {}) to ({}, {})",
|
|
||||||
min_x, min_y, max_x, max_y
|
|
||||||
);
|
|
||||||
|
|
||||||
// make a new image
|
|
||||||
let width = (max_x - min_x) as u32;
|
|
||||||
let height = (max_y - min_y) as u32;
|
|
||||||
let mut base_image = RgbImage::new(width, height);
|
|
||||||
|
|
||||||
// copy all of the images into it
|
|
||||||
for (id, image) in gui.capture_full_screen()? {
|
|
||||||
let screen = screen_layout.get(&id).expect("shouldn't fail");
|
|
||||||
let x = (screen.x + min_x) as u32;
|
|
||||||
let y = (screen.y + min_y) as u32;
|
|
||||||
let image = image.into_rgb_image();
|
|
||||||
imageops::overlay(&mut base_image, &image, x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the image
|
|
||||||
base_image.save(&opt.outfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make a new image
|
||||||
|
let width = (max_x - min_x) as u32;
|
||||||
|
let height = (max_y - min_y) as u32;
|
||||||
|
let mut base_image = RgbImage::new(width, height);
|
||||||
|
|
||||||
|
// copy all of the images into it
|
||||||
|
let images = gui.capture_full_screen()?;
|
||||||
|
for (id, image) in images.iter() {
|
||||||
|
let screen = screen_layout.get(&id).expect("shouldn't fail");
|
||||||
|
let x = (screen.x + min_x) as u32;
|
||||||
|
let y = (screen.y + min_y) as u32;
|
||||||
|
let image = image.to_rgb_image();
|
||||||
|
imageops::overlay(&mut base_image, &image, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Region::Selection = opt.region {
|
||||||
|
// bring up the interactive selection
|
||||||
|
let rect = gui.show_interactive_selection(&images)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save the image
|
||||||
|
base_image.save(&opt.outfile);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,11 +41,14 @@ pub trait Platform {
|
||||||
fn capture_full_screen(&self) -> Result<HashMap<Self::ScreenId, Self::Image>>;
|
fn capture_full_screen(&self) -> Result<HashMap<Self::ScreenId, Self::Image>>;
|
||||||
|
|
||||||
/// Open the interactive selection interface
|
/// Open the interactive selection interface
|
||||||
fn show_interactive_selection(&self, image: Self::Image) -> Result<Rectangle>;
|
fn show_interactive_selection(
|
||||||
|
&self,
|
||||||
|
image: &HashMap<Self::ScreenId, Self::Image>,
|
||||||
|
) -> Result<Rectangle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set of functions platform-specific images must implement
|
/// Set of functions platform-specific images must implement
|
||||||
pub trait Image {
|
pub trait Image {
|
||||||
/// Convert the image into an image::RgbImage
|
/// Convert the image into an image::RgbImage
|
||||||
fn into_rgb_image(self) -> RgbImage;
|
fn to_rgb_image(&self) -> RgbImage;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,13 +69,25 @@ impl Platform for X11 {
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_interactive_selection(&self, image: Self::Image) -> Result<Rectangle> {
|
fn show_interactive_selection(
|
||||||
let window = Window::create(&self.inner, None, Rectangle::new(0, 0, 500, 500))?;
|
&self,
|
||||||
|
image: &HashMap<Self::ScreenId, Self::Image>,
|
||||||
|
) -> Result<Rectangle> {
|
||||||
|
let root_window = self.inner.get_default_root_window()?;
|
||||||
|
let window = Window::create(
|
||||||
|
&self.inner,
|
||||||
|
Some(root_window),
|
||||||
|
Rectangle::new(0, 0, 500, 500),
|
||||||
|
)?;
|
||||||
window.map();
|
window.map();
|
||||||
|
|
||||||
let mut running = false;
|
while true {
|
||||||
|
let event = self.inner.next_event()?;
|
||||||
|
debug!("event: {:?}", event);
|
||||||
|
|
||||||
|
// quit
|
||||||
|
}
|
||||||
|
|
||||||
while running {}
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,7 +95,7 @@ impl Platform for X11 {
|
||||||
pub struct Image(x11::xlib::Image);
|
pub struct Image(x11::xlib::Image);
|
||||||
|
|
||||||
impl ImageT for Image {
|
impl ImageT for Image {
|
||||||
fn into_rgb_image(self) -> RgbImage {
|
fn to_rgb_image(&self) -> RgbImage {
|
||||||
let width = self.0.get_width();
|
let width = self.0.get_width();
|
||||||
let height = self.0.get_height();
|
let height = self.0.get_height();
|
||||||
let pixbuf = self.0.buffer();
|
let pixbuf = self.0.buffer();
|
||||||
|
|
|
@ -4,9 +4,12 @@ pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("invalid image byte order")]
|
#[error("invalid image byte order: {0}")]
|
||||||
InvalidByteOrder(i32),
|
InvalidByteOrder(i32),
|
||||||
|
|
||||||
|
#[error("invalid event type: {0}")]
|
||||||
|
InvalidEventType(i32),
|
||||||
|
|
||||||
#[error("failed to get attributes")]
|
#[error("failed to get attributes")]
|
||||||
GetAttributesError,
|
GetAttributesError,
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
use x11::xlib;
|
use x11::xlib;
|
||||||
|
|
||||||
|
@ -63,10 +64,10 @@ impl Display {
|
||||||
|
|
||||||
/// Get the next event, blocks until an event is reached.
|
/// Get the next event, blocks until an event is reached.
|
||||||
pub fn next_event(&self) -> Result<Event> {
|
pub fn next_event(&self) -> Result<Event> {
|
||||||
let event = unsafe {
|
let event = ptr::null_mut();
|
||||||
libc::malloc(::std::mem::size_of::<xlib::XAnyEvent>()) as *mut xlib::XAnyEvent
|
unsafe { xlib::XNextEvent(self.inner, event) };
|
||||||
};
|
// TODO: check to make sure this isn't null
|
||||||
Event::from_raw(event)
|
unsafe { Event::from_raw(event) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of events that are still pending
|
/// Returns the number of events that are still pending
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
use x11::xlib;
|
use x11::xlib;
|
||||||
|
|
||||||
use crate::errors::Result;
|
use crate::errors::{Error, Result};
|
||||||
|
|
||||||
/// An x11 Event
|
/// An x11 Event
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
inner: *mut xlib::XAnyEvent,
|
inner: *mut xlib::XEvent,
|
||||||
kind: EventKind,
|
kind: EventKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of event
|
/// Type of event
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum EventKind {
|
pub enum EventKind {
|
||||||
/// A mouse button was pressed
|
KeyPress(KeyEvent),
|
||||||
ButtonPress,
|
KeyRelease(KeyEvent),
|
||||||
|
|
||||||
/// A mouse button was released
|
|
||||||
ButtonRelease,
|
|
||||||
|
|
||||||
/// None event
|
|
||||||
None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Event {
|
impl Event {
|
||||||
|
@ -26,11 +22,16 @@ impl Event {
|
||||||
&self.kind
|
&self.kind
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn from_raw(event: *mut xlib::XAnyEvent) -> Result<Self> {
|
pub(super) unsafe fn from_raw(event: *mut xlib::XEvent) -> Result<Self> {
|
||||||
Ok(Event {
|
let inner = event;
|
||||||
inner: event,
|
let event = unsafe { *event };
|
||||||
kind: EventKind::None,
|
debug!("event type: {:?}", event.type_);
|
||||||
})
|
let kind = match event.type_ {
|
||||||
|
xlib::KeyPress => EventKind::KeyPress(KeyEvent(event.key)),
|
||||||
|
xlib::KeyRelease => EventKind::KeyRelease(KeyEvent(event.key)),
|
||||||
|
other => return Err(Error::InvalidEventType(other)),
|
||||||
|
};
|
||||||
|
Ok(Event { inner, kind })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,3 +40,6 @@ impl Drop for Event {
|
||||||
unsafe { libc::free(self.inner as *mut libc::c_void) };
|
unsafe { libc::free(self.inner as *mut libc::c_void) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KeyEvent(xlib::XKeyEvent);
|
||||||
|
|
Loading…
Reference in a new issue