diff --git a/src/gui.rs b/src/gui.rs index 9f8a668..a8eb183 100644 --- a/src/gui.rs +++ b/src/gui.rs @@ -88,11 +88,14 @@ impl GUI { use gl; use glutin::{ - self, dpi::LogicalSize, ElementState, Event, EventsLoop, GlContext, GlWindow, - KeyboardInput, MouseButton, MouseCursor, VirtualKeyCode, WindowBuilder, WindowEvent, + self, + dpi::LogicalSize, + os::unix::{WindowBuilderExt, WindowExt, XWindowType}, + ElementState, Event, EventsLoop, GlContext, GlWindow, KeyboardInput, MouseButton, + MouseCursor, VirtualKeyCode, WindowBuilder, WindowEvent, }; - use nanovg::{self, Color, Image, ImagePattern, PathOptions, StrokeOptions}; - use std::{f32::consts, slice}; + use nanovg::{self, Image, ImagePattern, PathOptions, StrokeOptions}; + use std::{f32::consts, mem, slice}; // let attr = window.get_attributes()?; // let width = attr.get_width(); @@ -107,6 +110,7 @@ impl GUI { // TODO: handle error let wb = WindowBuilder::new() + .with_x11_window_type(XWindowType::Splash) .with_decorations(false) .with_always_on_top(true) .with_dimensions(LogicalSize::new(width.into(), height.into())) @@ -114,41 +118,39 @@ impl GUI { let ctx = glutin::ContextBuilder::new() .with_vsync(false) .with_multisampling(4) + .with_double_buffer(Some(true)) .with_srgb(true); let win = GlWindow::new(wb, ctx, &evl).expect("couldn't make window"); + win.set_position((0.0, 0.0).into()); + let f = win.get_hidpi_factor() as f64; // crosshair win.set_cursor(MouseCursor::Crosshair); - - // change window type - { - use glutin::os::unix::WindowExt; - use xlib::Atom; - match win.get_xlib_window() { - Some(id) => { - let w = Window::create_from_handle(&self.display, id)?; - let key = Atom::new(&self.display, "_NET_WM_WINDOW_TYPE", false)?; - let val = Atom::new(&self.display, "_NET_WM_WINDOW_TYPE_SPLASH", false)?; - w.change_property(&key, &val); - } - _ => (), - } - } - - 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()); - // let img = Image2::create_from_drawable(window, 0, 0, 0, width as i32, height as i32, true)?; - imlib2::context_set_image(&capture); - let len = (width * height) as usize; - // println!("{}", window.as_raw()); - let raw_data = unsafe { slice::from_raw_parts(imlib2::image_get_data(), len) }; + let x = Display::from_handle(win.get_xlib_display().unwrap() as u64); + let len; + let raw_data; + { + let _g = x.grab(); + println!("grabbed"); + // let img = Image2::create_from_drawable(window, 0, 0, 0, width as i32, height as i32, true)?; + imlib2::context_set_image(&capture); + println!("set contexted"); + len = (width * height) as usize; + // println!("{}", window.as_raw()); + raw_data = unsafe { slice::from_raw_parts(imlib2::image_get_data(), len) }; + println!("captured"); + + unsafe { + win.make_current().expect("couldn't make window"); + gl::load_with(|sym| win.get_proc_address(sym) as *const _); + } + println!("maked"); + } + mem::forget(x); // convert ARGB to RGBA let mut data = vec![0u32; raw_data.len()]; @@ -158,6 +160,14 @@ impl GUI { *i = (*i & 0xff00ff00) | ((*i & 0xff) << 16) | ((*i >> 16) & 0xff); } + // invert image + let mut inverted = vec![0u32; raw_data.len()]; + inverted.copy_from_slice(raw_data); + for i in &mut inverted { + // fix the colors + *i = (*i & 0xff000000) | !(*i & 0xffffff); + } + let ctx = nanovg::ContextBuilder::new() .build() .expect("couldn't init nanovg"); @@ -166,6 +176,10 @@ impl GUI { .build_from_rgba(width as usize, height as usize, data.as_slice()) .expect("couldn't create image"); + let inverted_image = Image::new(&ctx) + .build_from_rgba(width as usize, height as usize, inverted.as_slice()) + .expect("couldn't create image"); + let mut running = true; let mut down = false; // drag start @@ -178,8 +192,66 @@ impl GUI { let mut rectw = 0.0f64; let mut recth = 0.0f64; let mut delayed_down = false; + let mut redraw = true; while running { - let mut redraw = true; + if redraw { + // 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), + ImagePattern { + image: &inverted_image, + origin: (0.0, 0.0), + size: (width as f32, height as f32), + angle: 0.0 / 180.0 * consts::PI, + alpha: 1.0, + }, + StrokeOptions { + width: 1.0, + ..Default::default() + }, + ); + }, + path_opts, + ); + } + }); + } + evl.poll_events(|event| match event { Event::WindowEvent { event, .. } => match event { WindowEvent::CloseRequested | WindowEvent::Destroyed => running = false, @@ -243,60 +315,6 @@ impl GUI { _ => (), }); - 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 { diff --git a/xlib/src/display.rs b/xlib/src/display.rs index d47896d..9ae7576 100644 --- a/xlib/src/display.rs +++ b/xlib/src/display.rs @@ -10,6 +10,8 @@ pub struct Display { inner: *mut x::Display, } +pub struct Grab(pub(crate) *mut x::Display); + /// Something that's part of a display. pub trait GetDisplay { /// Get the current display @@ -30,6 +32,19 @@ impl Display { Ok(Display { inner }) } + /// Create a Display for an existing connection + pub fn from_handle(handle: u64) -> Self { + Display { + inner: handle as *mut x::Display, + } + } + + /// Grab + pub fn grab(&self) -> Grab { + unsafe { x::XGrabServer(self.inner) }; + Grab(self.inner) + } + /// Wrapper around XCreateFontCursor pub fn create_font_cursor(&self, shape: u32) -> Result { let cursor = unsafe { x::XCreateFontCursor(self.inner, shape) as x::Cursor }; @@ -152,3 +167,9 @@ impl Drop for Display { unsafe { x::XCloseDisplay(self.inner) }; } } + +impl Drop for Grab { + fn drop(&mut self) { + unsafe { x::XUngrabServer(self.0) }; + } +} diff --git a/xlib/src/lib.rs b/xlib/src/lib.rs index a0d566e..e058b3d 100644 --- a/xlib/src/lib.rs +++ b/xlib/src/lib.rs @@ -25,7 +25,7 @@ mod cursorfont; pub use atom::Atom; pub use cursor::Cursor; pub use cursorfont::*; -pub use display::{Display, GetDisplay}; +pub use display::{Display, GetDisplay, Grab}; pub use drawable::Drawable; pub use errors::X11Error; pub use event::{Event, EventKind};