From 0e34bffc86ffd3991f6533d3c9211115bbec76d4 Mon Sep 17 00:00:00 2001 From: darkgallium Date: Sat, 2 Jan 2021 18:26:04 +0100 Subject: [PATCH] fix RGBA/BGRA bug, working selection screenshot, code cleanup --- src/main.rs | 171 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 52 deletions(-) diff --git a/src/main.rs b/src/main.rs index 522c4fa..4b3c019 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,85 +1,152 @@ -use x11::xlib::{XGrabPointer, XCreateFontCursor, XOpenDisplay, Display, XDefaultRootWindow, XAllPlanes, ZPixmap, XGetImage, ButtonMotionMask, ButtonPressMask, ButtonReleaseMask, CurrentTime, GrabModeAsync, GrabSuccess, XNextEvent, XEvent, XPending, ButtonPress, ButtonRelease, XButtonEvent, XGrabKeyboard, KeyPress, XKeyEvent}; +use x11::xlib; use std::mem::MaybeUninit; -use image::RgbaImage; +use image::{RgbaImage}; use std::convert::TryInto; #[derive(Debug)] struct Position { - origin_x: u32, - origin_y: u32, + origin_x: i32, + origin_y: i32, height: u32, width: u32, } fn screenshot(pos: &Position) { - unsafe { - let display: *mut Display = XOpenDisplay(std::ptr::null()); - let root_window = XDefaultRootWindow(display); + let len: usize = (pos.height as usize)*(pos.width as usize)*4; + let mut data: Vec = unsafe { + let display: *mut xlib::Display = xlib::XOpenDisplay(std::ptr::null()); + let root_window = xlib::XDefaultRootWindow(display); - let ximg = XGetImage(display, root_window, pos.origin_x.try_into().unwrap(), pos.origin_y.try_into().unwrap(), pos.width.try_into().unwrap(), pos.height.try_into().unwrap(), XAllPlanes(), ZPixmap); - let len = pos.height*pos.width*4; - let v = Vec::::from_raw_parts((*ximg).data as *mut _, len.try_into().unwrap(), len.try_into().unwrap()); - //println!("{:?}", v); - let img = RgbaImage::from_raw(pos.width, pos.height, v).unwrap(); - - img.save("empty.jpg").unwrap(); - } + let ximg = xlib::XGetImage(display, + root_window, + pos.origin_x, + pos.origin_y, + pos.width, + pos.height, + xlib::XAllPlanes(), + xlib::ZPixmap); + Vec::::from_raw_parts((*ximg).data as *mut _, len, len) + }; + + let mut c = 0; + while c < len { + data.swap(c,c+2); + c+=4; + } + + let img = RgbaImage::from_raw(pos.width, pos.height, data).unwrap(); + + img.save("empty.png").unwrap(); } // https://bbs.archlinux.org/viewtopic.php?id=85378 -fn trigger_selection() -> Option { +fn select_zone() -> Option { unsafe { - let display: *mut Display = XOpenDisplay(std::ptr::null()); - let root_window = XDefaultRootWindow(display); + let display: *mut xlib::Display = xlib::XOpenDisplay(std::ptr::null()); + let root_window = xlib::XDefaultRootWindow(display); - let c = XCreateFontCursor(display, 130); // XC_tcross = 130 - let button_mask = ButtonMotionMask as u32 | ButtonPressMask as u32 | ButtonReleaseMask as u32; + let c = xlib::XCreateFontCursor(display, 130); // xlib::XC_tcross = 130 + + let button_mask = xlib::ButtonMotionMask as u32 | xlib::ButtonPressMask as u32 | xlib::ButtonReleaseMask as u32; - if XGrabPointer(display, root_window, 0, button_mask, GrabModeAsync, GrabModeAsync, root_window, c, CurrentTime) != GrabSuccess { + if xlib::XGrabPointer(display, root_window, 0, button_mask, xlib::GrabModeAsync, xlib::GrabModeAsync, root_window, c, xlib::CurrentTime) != xlib::GrabSuccess { panic!("could not grab"); } - if XGrabKeyboard(display, root_window, 0, GrabModeAsync, GrabModeAsync, CurrentTime) != GrabSuccess { + if xlib::XGrabKeyboard(display, root_window, 0, xlib::GrabModeAsync, xlib::GrabModeAsync, xlib::CurrentTime) != xlib::GrabSuccess { panic!("could not grab"); } let mut pos = Position { origin_x: 0, origin_y: 0, width: 0, height: 0}; - 'main: loop { - while XPending(display) > 0 { - let mut e: MaybeUninit = MaybeUninit::uninit(); - XNextEvent(display, e.as_mut_ptr()); + let mut gcv = xlib::XGCValues { + foreground: (255<<16), + subwindow_mode: xlib::IncludeInferiors, + plane_mask: 0, + function: xlib::GXxor, + background: 0, + line_width: 2, + line_style: 0, + cap_style: 0, + join_style: 0, + fill_style: 0, + fill_rule: 0, + arc_mode: 0, + tile: 0, + stipple: 0, + ts_x_origin: 0, + ts_y_origin: 0, + font: 0, + graphics_exposures: 0, + clip_x_origin: 0, + clip_y_origin: 0, + clip_mask: 0, + dash_offset: 0, + dashes: 0, + }; + let gcv_mask = xlib::GCSubwindowMode | xlib::GCLineWidth | xlib::GCForeground | xlib::GCFunction; - let event = unsafe { e.assume_init() }; + let mut old_coord = (0,0); + let gc = xlib::XCreateGC(display, root_window, gcv_mask.into(), &mut gcv); + + // https://stackoverflow.com/questions/38996916/x11-draw-overlay-remove-drawings-from-overlay + + loop { + while xlib::XPending(display) > 0 { + let mut e: MaybeUninit = MaybeUninit::uninit(); + xlib::XNextEvent(display, e.as_mut_ptr()); + + let event = e.assume_init(); + match event.type_ { - KeyPress => { - let event = XKeyEvent::from(event); - if event.keycode == 9 { // escape keycode (xev) - return None; - } - }, - ButtonPress => { - let event = XButtonEvent::from(event); - println!("origin = ({},{})", event.x, event.y); - pos.origin_x = event.x_root.try_into().unwrap(); - pos.origin_y = event.y_root.try_into().unwrap(); - }, - ButtonRelease => { - // assuming that the upper left corner is the origin - let event = XButtonEvent::from(event); - let x: u32 = event.x_root.try_into().unwrap(); - let y: u32 = event.y_root.try_into().unwrap(); + xlib::MotionNotify => { + let event = xlib::XMotionEvent::from(event); - pos.width = x - pos.origin_x; - pos.height = y - pos.origin_y; - - if pos.height == 0 || pos.width == 0 { - return None - } + let width = event.x_root - pos.origin_x; + let height = event.y_root - pos.origin_y; - return Some(pos); + if height < 0 || width < 0 { + return None; + } + + xlib::XDrawRectangle(display, root_window, gc, pos.origin_x, pos.origin_y, old_coord.0, old_coord.1); + xlib::XDrawRectangle(display, root_window, gc, pos.origin_x, pos.origin_y, width.try_into().unwrap(), height.try_into().unwrap()); + + old_coord = (width.try_into().unwrap(), height.try_into().unwrap()); + }, + xlib::KeyPress => { + let event = xlib::XKeyEvent::from(event); + + if event.keycode == 9 { // escape keycode (xev) + return None; + } + }, + xlib::ButtonPress => { + let event = xlib::XButtonEvent::from(event); + //println!("origin = ({},{})", event.x, event.y); + + pos.origin_x = event.x_root.try_into().unwrap(); + pos.origin_y = event.y_root.try_into().unwrap(); + }, + xlib::ButtonRelease => { + // assuming that the upper left corner is the origin + let event = xlib::XButtonEvent::from(event); + + let x: u32 = event.x_root.try_into().unwrap(); + let y: u32 = event.y_root.try_into().unwrap(); + + pos.width = x - pos.origin_x as u32; + pos.height = y - pos.origin_y as u32; + + if pos.height == 0 || pos.width == 0 { + return None + } + + xlib::XDrawRectangle(display, root_window, gc, pos.origin_x, pos.origin_y, pos.width, pos.height); + xlib::XFlush(display); + return Some(pos); } _ => { println!("type unknown: {}", event.type_); } } @@ -92,7 +159,7 @@ fn trigger_selection() -> Option { } fn main() { - let s = trigger_selection(); + let s = select_zone(); println!("{:?}", s); if let Some(select) = s { screenshot(&select);