From 2b8094cc6ce7fefeb322a8b4df09e0c978efd5e2 Mon Sep 17 00:00:00 2001 From: Chris West Date: Mon, 1 Apr 2019 09:19:23 +0100 Subject: [PATCH] x11 and examples: resize (#72) * warnings / clippy * x11: remove deprecated, ignored position hints * x11: only non-resizable windows have fixed size * x11: handle resizes of ximage --- examples/mouse.rs | 25 ++++++++- examples/multi.rs | 10 ++-- examples/noise.rs | 15 +++++- examples/title_cursor.rs | 1 - src/os/unix/key_mapping.rs | 8 ++- src/os/unix/mod.rs | 107 ++++++++++++++++++++----------------- 6 files changed, 101 insertions(+), 65 deletions(-) diff --git a/examples/mouse.rs b/examples/mouse.rs index e3ff6b0..1f675f7 100644 --- a/examples/mouse.rs +++ b/examples/mouse.rs @@ -10,6 +10,7 @@ fn main() { let mut window = match Window::new("Mouse Draw - Press ESC to exit", WIDTH, HEIGHT, WindowOptions { + resize: true, scale: Scale::X2, ..WindowOptions::default() }) { @@ -20,9 +21,29 @@ fn main() { } }; + let (mut width, mut height) = (WIDTH, HEIGHT); + while window.is_open() && !window.is_key_down(Key::Escape) { - window.get_mouse_pos(MouseMode::Discard).map(|mouse| { - let screen_pos = ((mouse.1 as usize) * WIDTH) + mouse.0 as usize; + { + let (new_width, new_height) = window.get_size(); + if new_width != width || new_height != height { + + // copy valid bits of old buffer to new buffer + let mut new_buffer = vec![0; new_width * new_height / 2 / 2]; + for y in 0..(height / 2).min(new_height / 2) { + for x in 0..(width / 2).min(new_width / 2) { + new_buffer[y * (new_width / 2) + x] = buffer[y * (width / 2) + x]; + } + } + buffer = new_buffer; + width = new_width; + height = new_height; + + } + } + + window.get_mouse_pos(MouseMode::Discard).map(|(x, y)| { + let screen_pos = ((y as usize) * width / 2) + x as usize; println!("{:?}", window.get_unscaled_mouse_pos(MouseMode::Discard).unwrap()); if window.get_mouse_down(MouseButton::Left) { diff --git a/examples/multi.rs b/examples/multi.rs index a58f839..5eb67dd 100644 --- a/examples/multi.rs +++ b/examples/multi.rs @@ -6,16 +6,16 @@ fn main() { let width = 640; let height = 320; let mut buffer = vec![0u32; width * height]; - let mut orig = Window::new("Smaller", width, height, WindowOptions { - resize: true, - ..WindowOptions::default() - }).unwrap(); let mut double = Window::new("Larger", width, height, WindowOptions { - resize: true, scale: Scale::X2, ..WindowOptions::default() }).unwrap(); + let mut orig = Window::new("Smaller", width, height, WindowOptions { + ..WindowOptions::default() + }).unwrap(); + + let mut pos = 13; while orig.is_open() && double.is_open() diff --git a/examples/noise.rs b/examples/noise.rs index 89199d6..2d5541a 100644 --- a/examples/noise.rs +++ b/examples/noise.rs @@ -2,7 +2,7 @@ extern crate minifb; use minifb::{Window, Key, Scale, WindowOptions}; -const WIDTH: usize = 640; +const WIDTH: usize = 2560; const HEIGHT: usize = 360; fn main() { @@ -10,7 +10,6 @@ fn main() { let mut carry; let mut seed = 0xbeefu32; - let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; let mut window = match Window::new("Noise Test - Press ESC to exit", WIDTH, HEIGHT, WindowOptions { @@ -25,7 +24,19 @@ fn main() { } }; + let mut buffer: Vec = Vec::with_capacity(WIDTH * HEIGHT); + + let mut size = (0, 0); + while window.is_open() && !window.is_key_down(Key::Escape) { + { + let new_size = window.get_size(); + if new_size != size { + size = new_size; + buffer.resize(size.0 * size.1 / 2 / 2, 0); + } + } + for i in buffer.iter_mut() { noise = seed; noise >>= 3; diff --git a/examples/title_cursor.rs b/examples/title_cursor.rs index 571ba12..b3e7070 100644 --- a/examples/title_cursor.rs +++ b/examples/title_cursor.rs @@ -45,7 +45,6 @@ fn main() { WIDTH, HEIGHT, WindowOptions { - resize: true, scale: Scale::X2, ..WindowOptions::default() }) diff --git a/src/os/unix/key_mapping.rs b/src/os/unix/key_mapping.rs index b3c4fc0..e2da734 100644 --- a/src/os/unix/key_mapping.rs +++ b/src/os/unix/key_mapping.rs @@ -881,8 +881,8 @@ pub fn keysym_to_unicode(keysym: u32) -> Option { } // Also check for directly encoded 24-bit UCS characters - if (keysym & 0xff000000) == 0x01000000 { - return Some(keysym & 0x00ffffff); + if (keysym & 0xff00_0000) == 0x0100_0000 { + return Some(keysym & 0x00ff_ffff); } // Binary search in table @@ -905,9 +905,7 @@ pub fn test_it() { } // check ability to find every value in the table - for i in 0..LENGTH { - let p = keysymtab[i]; - + for p in keysymtab.iter() { assert_eq!(keysym_to_unicode(p.0), Some(p.1)); } } diff --git a/src/os/unix/mod.rs b/src/os/unix/mod.rs index f3f793c..2e0b42a 100644 --- a/src/os/unix/mod.rs +++ b/src/os/unix/mod.rs @@ -45,7 +45,7 @@ struct DisplayInfo { depth: i32, screen_width: usize, screen_height: usize, - context: xlib::XContext, + _context: xlib::XContext, cursor_lib: x11_dl::xcursor::Xcursor, cursors: [xlib::Cursor; 8], keyb_ext: bool, @@ -66,20 +66,11 @@ impl DisplayInfo { fn setup() -> Result { unsafe { - // load the Xlib library - let lib = match xlib::Xlib::open() { - Err(_) => { - return Err(Error::WindowCreate("failed to load Xlib".to_owned())); - } - Ok(v) => v, - }; + let lib = xlib::Xlib::open() + .map_err(|e| Error::WindowCreate(format!("failed to load Xlib: {:?}", e)))?; - let cursor_lib = match xcursor::Xcursor::open() { - Err(_) => { - return Err(Error::WindowCreate("failed to load Xcursor".to_owned())); - } - Ok(v) => v, - }; + let cursor_lib = xcursor::Xcursor::open() + .map_err(|e| Error::WindowCreate(format!("failed to load XCursor: {:?}", e)))?; let display = (lib.XOpenDisplay)(ptr::null()); @@ -110,7 +101,7 @@ impl DisplayInfo { depth, screen_width, screen_height, - context, + _context: context, cursor_lib, // the following are determined later... cursors: [0 as xlib::Cursor; 8], @@ -174,9 +165,6 @@ impl DisplayInfo { } fn init_cursors(&mut self) { - // andrewj: TODO: consider using the XCreateFontCursor() API, since - // some of these names are not working for me (they return zero). - self.cursors[0] = self.load_cursor("arrow"); self.cursors[1] = self.load_cursor("xterm"); self.cursors[2] = self.load_cursor("crosshair"); @@ -320,12 +308,10 @@ impl Window { | xlib::ButtonReleaseMask, ); - if opts.resize { + if !opts.resize { let mut size_hints: xlib::XSizeHints = mem::zeroed(); - size_hints.flags = xlib::PPosition | xlib::PMinSize | xlib::PMaxSize; - size_hints.x = 0; - size_hints.y = 0; + size_hints.flags = xlib::PMinSize | xlib::PMaxSize; size_hints.min_width = width as i32; size_hints.max_width = width as i32; size_hints.min_height = height as i32; @@ -342,32 +328,17 @@ impl Window { (d.lib.XMapRaised)(d.display, handle); (d.lib.XFlush)(d.display); - let bytes_per_line = (width as i32) * 4; - - let ximage = (d.lib.XCreateImage)( - d.display, - d.visual, /* TODO: this was CopyFromParent in the C code */ - d.depth as u32, - xlib::ZPixmap, - 0, - ptr::null_mut(), - width as u32, - height as u32, - 32, - bytes_per_line, - ); - - if ximage == ptr::null_mut() { - (d.lib.XDestroyWindow)(d.display, handle); - return Err(Error::WindowCreate( - "Unable to create pixel buffer".to_owned(), - )); - } - let mut draw_buffer: Vec = Vec::new(); - draw_buffer.resize(width * height, 0); - (*ximage).data = draw_buffer[..].as_mut_ptr() as *mut c_char; + let ximage = match Self::alloc_image(&d, width, height, &mut draw_buffer) { + Some(ximage) => ximage, + None => { + (d.lib.XDestroyWindow)(d.display, handle); + return Err(Error::WindowCreate( + "Unable to create pixel buffer".to_owned(), + )); + } + }; Ok(Window { d, @@ -391,6 +362,37 @@ impl Window { } } + unsafe fn alloc_image(d: &DisplayInfo, width: usize, height: usize, draw_buffer: &mut Vec) -> Option<*mut xlib::XImage> { + let bytes_per_line = (width as i32) * 4; + + draw_buffer.resize(width * height, 0); + + let image = (d.lib.XCreateImage)( + d.display, + d.visual, /* TODO: this was CopyFromParent in the C code */ + d.depth as u32, + xlib::ZPixmap, + 0, + draw_buffer[..].as_mut_ptr() as *mut c_char, + width as u32, + height as u32, + 32, + bytes_per_line, + ); + + if image.is_null() { + None + } else { + Some(image) + } + } + + unsafe fn free_image(&mut self) { + (*self.ximage).data = ptr::null_mut(); + (self.d.lib.XDestroyImage)(self.ximage); + self.ximage = ptr::null_mut(); + } + pub fn set_title(&mut self, title: &str) { match CString::new(title) { Err(_) => { @@ -434,7 +436,7 @@ impl Window { #[inline] pub fn get_window_handle(&self) -> *mut raw::c_void { - unsafe { mem::transmute(self.handle as usize) } + self.handle as *mut raw::c_void } #[inline] @@ -765,6 +767,12 @@ impl Window { // TODO : pass this onto the application self.width = ev.configure.width as u32; self.height = ev.configure.height as u32; + self.free_image(); + self.ximage = Self::alloc_image( + &self.d, + cast::usize(self.width), + cast::usize(self.height), + &mut self.draw_buffer).expect("todo"); } _ => {} @@ -992,13 +1000,12 @@ impl Window { impl Drop for Window { fn drop(&mut self) { unsafe { - (*self.ximage).data = ptr::null_mut(); + self.free_image(); // TODO [ andrewj: right now DisplayInfo is not shared, so doing this is // probably pointless ] // XSaveContext(s_display, info->window, s_context, (XPointer)0); - (self.d.lib.XDestroyImage)(self.ximage); (self.d.lib.XDestroyWindow)(self.d.display, self.handle); } } @@ -1024,7 +1031,7 @@ impl Menu { let handle = self.next_item_handle(); self.internal.items.push(UnixMenuItem { label: name.to_owned(), - handle: handle, + handle, sub_menu: Some(Box::new(sub_menu.internal.clone())), id: 0, enabled: true,