From 73813b63f48a8f0a1449d34cddf03f2177b811b5 Mon Sep 17 00:00:00 2001 From: Daniel Collin Date: Sun, 31 Jan 2016 18:34:05 +0100 Subject: [PATCH] Merged window-opts to master commit 53e9cd45567a1308fdbd2e46763e15b2a3fa3d4c Author: Daniel Collin Date: Sun Jan 31 18:31:38 2016 +0100 Correct header for v0.4.0 commit fcf64d5dfad0796fee16ce8985e66d1b3e82c5a4 Author: Daniel Collin Date: Sun Jan 31 18:30:12 2016 +0100 More cleanup commit b7f4b187569a753656f19a74b78d8ada3fd95b70 Author: Daniel Collin Date: Sun Jan 31 18:29:23 2016 +0100 Minor cleanup commit 7392cd4a5aaad7f0d8332082c75d6cbc41d50ca6 Author: Daniel Collin Date: Sun Jan 31 18:28:06 2016 +0100 Updated example added Changelog link commit 236a82883a68e576ceb1e38a54b0a18fdc2e4465 Author: Daniel Collin Date: Sun Jan 31 18:24:58 2016 +0100 Updated readme commit e6bc68721513ca66c5566a19e6bfad33875b3280 Author: Daniel Collin Date: Sun Jan 31 18:20:42 2016 +0100 Doc fixes commit edfd688f045764b66c944d4aa616c6d48246816d Author: Daniel Collin Date: Sun Jan 31 18:20:35 2016 +0100 Updated with 0.4.0 release info commit 784628fa9a1de93280592e634b522fd916a7588a Author: Daniel Collin Date: Sun Jan 31 15:45:37 2016 +0100 Fixed bad comment commit 2c6d8730b566193b573afb5dc95a82987d1c4ce4 Author: Daniel Collin Date: Sun Jan 31 15:37:52 2016 +0100 Linux support for WindowOptions commit cbf7c17c3a92d676f5707095781071016e8b90e1 Author: Daniel Collin Date: Sun Jan 31 15:05:10 2016 +0100 Updated Windows version with WindowOptions commit ed1254245384e3e64c082a8368cbbe4a9f679efa Author: Daniel Collin Date: Sun Jan 31 14:32:04 2016 +0100 Added get_window_handle commit e4a15f98c70facda7e7b2f30ba95a42091fa078c Author: Daniel Collin Date: Sun Jan 31 14:30:34 2016 +0100 Cleanup + links commit 7dadb090d1037eade525093e2a541c99940e6a3a Author: Daniel Collin Date: Sun Jan 31 14:25:41 2016 +0100 And again commit 70bdb0f88812e12bf9ca9adc55c1e52cc36c3ef9 Author: Daniel Collin Date: Sun Jan 31 14:24:44 2016 +0100 Try link again commit b4b7b3c4cda1d958e8f9cf6a2418db68ac32bcc5 Author: Daniel Collin Date: Sun Jan 31 14:21:54 2016 +0100 Some cleanup commit fb9845bae37f6ce9ba309b8a57128ce8c426fbca Author: Daniel Collin Date: Sun Jan 31 13:16:23 2016 +0100 Renamed resizeable to resize commit 89c5af826612dbd887855dca3937e99856c9fcf2 Author: Daniel Collin Date: Sun Jan 31 12:59:57 2016 +0100 Working on making Windows a bit more generic * Added WindowOptions that can configure how the Window should look and behave better (resize, title, borderless) * Renamed update -> update_with_buffer * Added update which doesn't take a buffer (used to updated the window without buffers) --- CHANGELOG.md | 20 ++++-- Cargo.toml | 6 +- README.md | 13 ++-- examples/mouse.rs | 10 ++- examples/noise.rs | 11 ++- src/lib.rs | 124 +++++++++++++++++++++++++++++----- src/native/macosx/MacMiniFB.m | 45 ++++++++++-- src/native/x11/X11MiniFB.c | 42 ++++++++---- src/os/macos/mod.rs | 35 +++++++--- src/os/unix/mod.rs | 38 ++++++++--- src/os/windows/mod.rs | 83 +++++++++++++++++------ src/window_flags.rs | 30 ++++++++ 12 files changed, 366 insertions(+), 91 deletions(-) create mode 100644 src/window_flags.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index aab1bf5..75f0233 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,24 @@ This project follows semantic versioning. +### v0.4.0 (2016-01-31) + +This release breaks some of the API by changing names and parameters to some functions. + +- [changed] ```Window::new(...)``` now takes WindowOptions struct to configure the creation of the Window. [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.new) +- [changed] ```window.update()``` Doesn't take a buffer anymore. See ```window.update_with_buffer``` [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.update) +- [added] ```window.update_with_buffer()``` Old update version that takes buffer as input parameter [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.update_with_buffer) +- [added] ```window.get_window_handle()``` Returns the native handle (os dependant) [doc](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_window_handle) + ### v0.3.1 (2016-01-29) -- [fixed] ```get_mouse_pos(MouseMode::Clamp)``` now is in the region [(0, 0) - (width - 1, height - 1)] instead of (width, height) +- [fixed] ```get_mouse_pos(Clamp)``` clamps to ```[(0, 0) - (width - 1, height - 1)]``` instead of ```(width, height)``` ### v0.3.0 (2016-01-29) -- [added] ```get_mouse_pos``` -- [added] ```get_mouse_down``` -- [added] ```get_scroll_wheel``` +This release adds support for mouse input. See the documentation and the examples for usage + +- [added] [get_mouse_pos](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_mouse_pos) +- [added] [get_mouse_down](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_mouse_down) +- [added] [get_scroll_wheel](http://prodbg.com/minifb/minifb/struct.Window.html#method.get_scroll_wheel) -This relase adds support for mouse input. See the documentation and the examples for usage diff --git a/Cargo.toml b/Cargo.toml index 0f4effb..f561122 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "minifb" -version = "0.3.1" +version = "0.4.0" license = "MIT/Apache-2.0" authors = ["Daniel Collin "] -description = "Cross-platform window setup for bitmap rendering" -keywords = ["windowing", "framebuffer"] +description = "Cross-platform window setup with optional bitmap rendering" +keywords = ["windowing", "window", "framebuffer"] repository = "https://github.com/emoon/rust_minifb" homepage = "https://github.com/emoon/rust_minifb" documentation = "http://prodbg.com/minifb/minifb/index.html" diff --git a/README.md b/README.md index 1fec935..34748ff 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ [![Build Status](https://travis-ci.org/emoon/rust_minifb.svg)](https://travis-ci.org/emoon/rust_minifb) [![Build Status](https://ci.appveyor.com/api/projects/status/sfvgqq4d4sjulkbx?svg=true)](https://ci.appveyor.com/project/emoon/rust-minifb) -minifb (Mini FrameBuffer) is a small cross platform library written in [Rust](https://www.rust-lang.org) and that makes it easy to render (32-bit) pixels in a window. An example is the best way to show how it works: +minifb is a cross platform library written in [Rust](https://www.rust-lang.org) and that makes it easy to setup a window and to (optional) display 32-bit a pixel buffer. It also makes it easy to get input from keyboard and mouse. +An example is the best way to show how it works: [Documentation](http://prodbg.com/minifb/minifb/index.html) +[Changelog](https://github.com/emoon/rust_minifb/blob/window-opts/CHANGELOG.md) Usage ----- @@ -12,7 +14,7 @@ Usage ```toml # Cargo.toml [dependencies] -minifb = "0.3.1" +minifb = "0.4.0" ``` Example @@ -21,7 +23,7 @@ Example ```rust extern crate minifb; -use minifb::{Key, Scale}; +use minifb::{Key, Scale, WindowOptions}; const WIDTH: usize = 640; const HEIGHT: usize = 360; @@ -29,7 +31,8 @@ const HEIGHT: usize = 360; fn main() { let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; - let mut window = match minifb::Window::new("Test - ESC to exit", WIDTH, HEIGHT, Scale::X1) { + let mut window = match minifb::Window::new("Test - ESC to exit", WIDTH, HEIGHT, + WindowOptions::default()) { Ok(win) => win, Err(err) => { println!("Unable to create window {}", err); @@ -42,7 +45,7 @@ fn main() { *i = 0; // write something more funny here! } - window.update(&buffer); + window.update_with_buffer(&buffer); } } ``` diff --git a/examples/mouse.rs b/examples/mouse.rs index 5c42878..8e9d785 100644 --- a/examples/mouse.rs +++ b/examples/mouse.rs @@ -1,6 +1,6 @@ extern crate minifb; -use minifb::{MouseButton, MouseMode, Window, Key, Scale}; +use minifb::{MouseButton, MouseMode, Window, Key, Scale, WindowOptions}; const WIDTH: usize = 640; const HEIGHT: usize = 360; @@ -8,7 +8,11 @@ const HEIGHT: usize = 360; fn main() { let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; - let mut window = match Window::new("Mouse Draw - Press ESC to exit", WIDTH, HEIGHT, Scale::X2) { + let mut window = match Window::new("Mouse Draw - Press ESC to exit", WIDTH, HEIGHT, + WindowOptions { + scale: Scale::X2, + ..WindowOptions::default() + }) { Ok(win) => win, Err(err) => { println!("Unable to create window {}", err); @@ -33,6 +37,6 @@ fn main() { println!("Scrolling {} - {}", scroll.0, scroll.1); }); - window.update(&buffer); + window.update_with_buffer(&buffer); } } diff --git a/examples/noise.rs b/examples/noise.rs index edde38a..69edf97 100644 --- a/examples/noise.rs +++ b/examples/noise.rs @@ -1,6 +1,6 @@ extern crate minifb; -use minifb::{Window, Key, Scale}; +use minifb::{Window, Key, Scale, WindowOptions}; const WIDTH: usize = 640; const HEIGHT: usize = 360; @@ -12,7 +12,12 @@ fn main() { let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; - let mut window = match Window::new("Noise Test - Press ESC to exit", WIDTH, HEIGHT, Scale::X2) { + let mut window = match Window::new("Noise Test - Press ESC to exit", WIDTH, HEIGHT, + WindowOptions { + resize: true, + scale: Scale::X2, + ..WindowOptions::default() + }) { Ok(win) => win, Err(err) => { println!("Unable to create window {}", err); @@ -43,6 +48,6 @@ fn main() { } }); - window.update(&buffer); + window.update_with_buffer(&buffer); } } diff --git a/src/lib.rs b/src/lib.rs index 60136d3..737f341 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -183,10 +183,13 @@ pub enum MouseMode { extern crate libc; +use std::os::raw; + #[doc(hidden)] pub mod os; mod mouse_handler; mod key_handler; +mod window_flags; #[cfg(target_os = "macos")] use self::os::macos as imp; @@ -199,36 +202,58 @@ use self::os::windows as imp; target_os="openbsd"))] use self::os::unix as imp; +pub struct Window(imp::Window); + /// -/// Window used for displaying a 32-bit RGB buffer. Here is a small example on how to use it: -/// (without error checking +/// WindowOptions is creation settings for the window. By default the settings are defined for +/// displayng a 32-bit buffer (no scaling of window is possible) +/// +pub struct WindowOptions { + /// If the window should be borderless (default: false) + pub borderless: bool, + /// If the window should have a title (default: true) + pub title: bool, + /// If it should be possible to resize the window (default: false) + pub resize: bool, + /// Scale of the window that used in conjunction with update_with_buffer (default: X1) + pub scale: Scale +} + +/// +/// Window is used to open up a window. It's possible to optionally display a 32-bit buffer when +/// the widow is set as non-resizable. +/// +/// # Examples +/// +/// Open up a window and display a 32-bit RGB buffer (without error checking) /// /// ```ignore -/// /// const WIDTH: usize = 640; /// const HEIGHT: usize = 360; /// /// let mut buffer: Vec = vec![0; WIDTH * HEIGHT]; /// -/// let mut window = match Window::new("Test - Press ESC to exit", WIDTH, HEIGHT, Scale::X1).unwrap() +/// let mut window = match Window::new("Test - Press ESC to exit", WIDTH, HEIGHT, +/// WindowOptions::default()).unwrap() /// /// while window.is_open() && !window.is_key_down(Key::Escape) { /// for i in buffer.iter_mut() { /// *i = 0; // write something interesting here /// } -/// window.update(&buffer); +/// window.update_with_buffer(&buffer); /// } /// ``` /// - -pub struct Window(imp::Window); - impl Window { /// /// Opens up a new window /// + /// # Examples + /// + /// Open up a window with default settings + /// /// ```ignore - /// let mut window = match Window::new("Test", 640, 400, Scale::X1) { + /// let mut window = match Window::new("Test", 640, 400, WindowOptions::default()) { /// Ok(win) => win, /// Err(err) => { /// println!("Unable to create window {}", err); @@ -236,8 +261,39 @@ impl Window { /// } ///}; /// ``` - pub fn new(name: &str, width: usize, height: usize, scale: Scale) -> Result { - imp::Window::new(name, width, height, scale).map(Window) + /// + /// Open up a window that is resizeable + /// + /// ```ignore + /// let mut window = match Window::new("Test", 640, 400, + /// WindowOptions { + /// resize: true, + /// ..WindowOptions::default() + /// }) { + /// Ok(win) => win, + /// Err(err) => { + /// println!("Unable to create window {}", err); + /// return; + /// } + ///}; + /// ``` + pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result { + imp::Window::new(name, width, height, opts).map(Window) + } + + /// + /// Returns the native handle for a window which is an opaque pointer/handle which + /// dependens on the current operating system: + /// + /// ```ignore + /// Windows HWND + /// MacOS NSWindow + /// X11 XWindow + /// ``` + /// + #[inline] + pub fn get_window_handle(&self) -> *mut raw::c_void { + self.0.get_window_handle() } /// @@ -249,12 +305,30 @@ impl Window { /// ```ignore /// let mut buffer: Vec = vec![0; 640 * 400]; /// - /// let mut window = match Window::new("Test", 640, 400, Scale::X1).unwrap(); + /// let mut window = match Window::new("Test", 640, 400, WindowOptions::default()).unwrap(); /// - /// window.update(&buffer); + /// window.update_with_buffer(&buffer); /// ``` - pub fn update(&mut self, buffer: &[u32]) { - self.0.update(buffer) + #[inline] + pub fn update_with_buffer(&mut self, buffer: &[u32]) { + self.0.update_with_buffer(buffer) + } + + /// + /// Updates the window (this is required to call in order to get keyboard/mouse input, etc) + /// + /// # Examples + /// + /// ```ignore + /// let mut buffer: Vec = vec![0; 640 * 400]; + /// + /// let mut window = match Window::new("Test", 640, 400, WindowOptions::default()).unwrap(); + /// + /// window.update(); + /// ``` + #[inline] + pub fn update(&mut self) { + self.0.update() } /// @@ -281,7 +355,7 @@ impl Window { /// # Examples /// /// ```ignore - /// // Moves the window to pixel postion 20, 20 on the screen + /// // Moves the window to pixel position 20, 20 on the screen /// window.set_position(20, 20); /// ``` /// @@ -435,7 +509,7 @@ impl Window { } /// - /// Sets the rate in between when the keys has passed the intital repeat_delay. The default + /// Sets the rate in between when the keys has passed the initial repeat_delay. The default /// value is 0.05 sec /// /// # Examples @@ -449,3 +523,19 @@ impl Window { self.0.set_key_repeat_rate(rate) } } + +// Impl for WindowOptions + +#[doc(hidden)] +impl Default for WindowOptions { + fn default() -> WindowOptions { + WindowOptions { + borderless: false, + title: true, + resize: false, + scale: Scale::X1, + } + } +} + + diff --git a/src/native/macosx/MacMiniFB.m b/src/native/macosx/MacMiniFB.m index cdb6829..fda0dfa 100644 --- a/src/native/macosx/MacMiniFB.m +++ b/src/native/macosx/MacMiniFB.m @@ -6,6 +6,11 @@ static bool s_init = false; +// window_handler.rs +const uint32_t WINDOW_BORDERLESS = 1 << 1; +const uint32_t WINDOW_RESIZE = 1 << 2; +const uint32_t WINDOW_TITLE = 1 << 3; + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef __clang__ @@ -14,7 +19,7 @@ static bool s_init = false; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void* mfb_open(const char* name, int width, int height, int scale) +void* mfb_open(const char* name, int width, int height, uint32_t flags, int scale) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; @@ -23,8 +28,18 @@ void* mfb_open(const char* name, int width, int height, int scale) [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; s_init = true; } + + uint32_t styles = NSClosableWindowMask | NSMiniaturizableWindowMask; + + if (flags & WINDOW_BORDERLESS) + styles |= NSBorderlessWindowMask; + + if (flags & WINDOW_RESIZE) + styles |= NSResizableWindowMask; + + if (flags & WINDOW_TITLE) + styles |= NSTitledWindowMask; - unsigned int styles = NSClosableWindowMask | NSTitledWindowMask; NSRect rectangle = NSMakeRect(0, 0, width * scale, (height * scale)); OSXWindow* window = [[OSXWindow alloc] initWithContentRect:rectangle styleMask:styles backing:NSBackingStoreBuffered defer:NO]; @@ -88,11 +103,7 @@ static int update_events() /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -int mfb_update(void* window, void* buffer) -{ - OSXWindow* win = (OSXWindow*)window; - memcpy(win->draw_buffer, buffer, win->width * win->height * 4); - +static int generic_update(OSXWindow* win) { int state = update_events(); if (win->shared_data) { @@ -103,6 +114,26 @@ int mfb_update(void* window, void* buffer) win->shared_data->mouse_y = contentRect.size.height - p.y; } + return state; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_update(void* window, void* buffer) +{ + OSXWindow* win = (OSXWindow*)window; + return generic_update(win); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +int mfb_update_with_buffer(void* window, void* buffer) +{ + OSXWindow* win = (OSXWindow*)window; + memcpy(win->draw_buffer, buffer, win->width * win->height * 4); + + int state = generic_update(win); + [[win contentView] setNeedsDisplay:YES]; return state; } diff --git a/src/native/x11/X11MiniFB.c b/src/native/x11/X11MiniFB.c index c69d393..467ed5b 100644 --- a/src/native/x11/X11MiniFB.c +++ b/src/native/x11/X11MiniFB.c @@ -13,6 +13,11 @@ #define Button6 6 #define Button7 7 +// window_handler.rs +const uint32_t WINDOW_BORDERLESS = 1 << 1; +const uint32_t WINDOW_RESIZE = 1 << 2; +const uint32_t WINDOW_TITLE = 1 << 3; + void mfb_close(void* window_info); /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -113,7 +118,7 @@ static int setup_display() { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void* mfb_open(const char* title, int width, int height, int scale) +void* mfb_open(const char* title, int width, int height, unsigned int flags, int scale) { XSetWindowAttributes windowAttributes; XSizeHints sizeHints; @@ -125,6 +130,9 @@ void* mfb_open(const char* title, int width, int height, int scale) return 0; } + //TODO: Handle no title/borderless + (void)flags; + width *= scale; height *= scale; @@ -146,16 +154,19 @@ void* mfb_open(const char* title, int width, int height, int scale) //XSelectInput(s_display, s_window, KeyPressMask | KeyReleaseMask); XStoreName(s_display, window, title); - sizeHints.flags = PPosition | PMinSize | PMaxSize; - sizeHints.x = 0; - sizeHints.y = 0; - sizeHints.min_width = width; - sizeHints.max_width = width; - sizeHints.min_height = height; - sizeHints.max_height = height; - XSelectInput(s_display, window, ButtonPressMask | KeyPressMask | KeyReleaseMask | ButtonReleaseMask); - XSetWMNormalHints(s_display, window, &sizeHints); + + if (!(flags & WINDOW_RESIZE)) { + sizeHints.flags = PPosition | PMinSize | PMaxSize; + sizeHints.x = 0; + sizeHints.y = 0; + sizeHints.min_width = width; + sizeHints.max_width = width; + sizeHints.min_height = height; + sizeHints.max_height = height; + XSetWMNormalHints(s_display, window, &sizeHints); + } + XClearWindow(s_display, window); XMapRaised(s_display, window); XFlush(s_display); @@ -376,14 +387,14 @@ static void scale_4x(unsigned int* dest, unsigned int* source, int width, int he /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -void mfb_update(void* window_info, void* buffer) +void mfb_update_with_buffer(void* window_info, void* buffer) { WindowInfo* info = (WindowInfo*)window_info; int width = info->width; int height = info->height; int scale = info->scale; - if (info->update) { + if (info->update && buffer) { switch (scale) { case 1: { memcpy(info->draw_buffer, buffer, width * height * 4); @@ -417,6 +428,13 @@ void mfb_update(void* window_info, void* buffer) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void mfb_update(void* window_info, void* buffer) +{ + mfb_update_with_buffer(window_info, 0); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void mfb_set_position(void* window, int x, int y) { WindowInfo* info = (WindowInfo*)window; diff --git a/src/os/macos/mod.rs b/src/os/macos/mod.rs index 93965f5..5847fa4 100644 --- a/src/os/macos/mod.rs +++ b/src/os/macos/mod.rs @@ -1,13 +1,15 @@ #![cfg(target_os = "macos")] -use {MouseButton, MouseMode, Scale, Key, KeyRepeat}; +use {MouseButton, MouseMode, Scale, Key, KeyRepeat, WindowOptions}; use key_handler::KeyHandler; use mouse_handler; +use window_flags; use libc::{c_void, c_char, c_uchar}; use std::ffi::{CString}; use std::ptr; use std::mem; +use std::os::raw; // Table taken from GLFW and slightly modified @@ -144,9 +146,10 @@ static KEY_MAPPINGS: [Key; 128] = [ #[link(name = "Cocoa", kind = "framework")] extern { - fn mfb_open(name: *const c_char, width: u32, height: u32, scale: i32) -> *mut c_void; + fn mfb_open(name: *const c_char, width: u32, height: u32, flags: u32, scale: i32) -> *mut c_void; fn mfb_close(window: *mut c_void); - fn mfb_update(window: *mut c_void, buffer: *const c_uchar); + fn mfb_update(window: *mut c_void); + fn mfb_update_with_buffer(window: *mut c_void, buffer: *const c_uchar); fn mfb_set_position(window: *mut c_void, x: i32, y: i32); fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32)); fn mfb_set_mouse_data(window_handle: *mut c_void, shared_data: *mut SharedData); @@ -187,7 +190,7 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, state: i32) { } impl Window { - pub fn new(name: &str, width: usize, height: usize, scale: Scale) -> Result { + pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result { let n = match CString::new(name) { Err(_) => { println!("Unable to convert {} to c_string", name); @@ -197,8 +200,8 @@ impl Window { }; unsafe { - let scale_factor = Self::get_scale_factor(width, height, scale) as usize; - let handle = mfb_open(n.as_ptr(), width as u32, height as u32, scale_factor as i32); + let scale_factor = Self::get_scale_factor(width, height, opts.scale) as usize; + let handle = mfb_open(n.as_ptr(), width as u32, height as u32, window_flags::get_flags(opts), scale_factor as i32); if handle == ptr::null_mut() { return Err("Unable to open Window"); @@ -218,15 +221,31 @@ impl Window { } } + #[inline] + pub fn get_window_handle(&self) -> *mut raw::c_void { + self.window_handle as *mut raw::c_void + } + + #[inline] unsafe fn set_mouse_data(&mut self) { mfb_set_mouse_data(self.window_handle, &mut self.shared_data); } - pub fn update(&mut self, buffer: &[u32]) { + pub fn update_with_buffer(&mut self, buffer: &[u32]) { self.key_handler.update(); unsafe { - mfb_update(self.window_handle, buffer.as_ptr() as *const u8); + mfb_update_with_buffer(self.window_handle, buffer.as_ptr() as *const u8); + Self::set_mouse_data(self); + mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback); + } + } + + pub fn update(&mut self) { + self.key_handler.update(); + + unsafe { + mfb_update(self.window_handle); Self::set_mouse_data(self); mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback); } diff --git a/src/os/unix/mod.rs b/src/os/unix/mod.rs index 8fe070a..5c7710b 100644 --- a/src/os/unix/mod.rs +++ b/src/os/unix/mod.rs @@ -6,7 +6,7 @@ extern crate x11_dl; -use {MouseMode, MouseButton, Scale, Key, KeyRepeat}; +use {MouseMode, MouseButton, Scale, Key, KeyRepeat, WindowOptions}; use key_handler::KeyHandler; use self::x11_dl::keysym::*; @@ -14,13 +14,16 @@ use libc::{c_void, c_char, c_uchar}; use std::ffi::{CString}; use std::ptr; use std::mem; +use std::os::raw; use mouse_handler; +use window_flags; #[link(name = "X11")] extern { - fn mfb_open(name: *const c_char, width: u32, height: u32, scale: i32) -> *mut c_void; + fn mfb_open(name: *const c_char, width: u32, height: u32, flags: u32, scale: i32) -> *mut c_void; fn mfb_close(window: *mut c_void); - fn mfb_update(window: *mut c_void, buffer: *const c_uchar); + fn mfb_update(window: *mut c_void); + fn mfb_update_with_buffer(window: *mut c_void, buffer: *const c_uchar); fn mfb_set_position(window: *mut c_void, x: i32, y: i32); fn mfb_set_key_callback(window: *mut c_void, target: *mut c_void, cb: unsafe extern fn(*mut c_void, i32, i32)); fn mfb_set_shared_data(window: *mut c_void, target: *mut SharedData); @@ -160,7 +163,7 @@ unsafe extern "C" fn key_callback(window: *mut c_void, key: i32, s: i32) { } impl Window { - pub fn new(name: &str, width: usize, height: usize, scale: Scale) -> Result { + pub fn new(name: &str, width: usize, height: usize, opts: WindowOptions) -> Result { let n = match CString::new(name) { Err(_) => { println!("Unable to convert {} to c_string", name); @@ -170,8 +173,12 @@ impl Window { }; unsafe { - let scale = Self::get_scale_factor(width, height, scale); - let handle = mfb_open(n.as_ptr(), width as u32, height as u32, scale); + let scale = Self::get_scale_factor(width, height, opts.scale); + let handle = mfb_open(n.as_ptr(), + width as u32, + height as u32, + window_flags::get_flags(opts), + scale); if handle == ptr::null_mut() { return Err("Unable to open Window"); @@ -192,16 +199,31 @@ impl Window { mfb_set_shared_data(self.window_handle, &mut self.shared_data); } - pub fn update(&mut self, buffer: &[u32]) { + pub fn update_with_buffer(&mut self, buffer: &[u32]) { self.key_handler.update(); unsafe { Self::set_shared_data(self); - mfb_update(self.window_handle, buffer.as_ptr() as *const u8); + mfb_update_with_buffer(self.window_handle, buffer.as_ptr() as *const u8); mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback); } } + pub fn update(&mut self) { + self.key_handler.update(); + + unsafe { + Self::set_shared_data(self); + mfb_update(self.window_handle); + mfb_set_key_callback(self.window_handle, mem::transmute(self), key_callback); + } + } + + #[inline] + pub fn get_window_handle(&self) -> *mut raw::c_void { + self.window_handle as *mut raw::c_void + } + #[inline] pub fn set_position(&mut self, x: isize, y: isize) { unsafe { mfb_set_position(self.window_handle, x as i32, y as i32) } diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index a2dc7ce..06b3d53 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -6,7 +6,7 @@ extern crate winapi; extern crate gdi32; extern crate time; -use {Scale, Key, KeyRepeat, MouseButton, MouseMode}; +use {Scale, Key, KeyRepeat, MouseButton, MouseMode, WindowOptions}; use key_handler::KeyHandler; @@ -14,6 +14,7 @@ use std::ptr; use std::os::windows::ffi::OsStrExt; use std::ffi::OsStr; use std::mem; +use std::os::raw; use mouse_handler; use self::winapi::windef::HWND; @@ -226,6 +227,12 @@ unsafe extern "system" fn wnd_proc(window: winapi::HWND, } winapi::winuser::WM_PAINT => { + + // if we have nothing to draw here we return the default function + if wnd.buffer.len() == 0 { + return user32::DefWindowProcW(window, msg, wparam, lparam); + } + let mut bitmap_info: BitmapInfo = mem::zeroed(); bitmap_info.bmi_header.biSize = mem::size_of::() as u32; @@ -294,7 +301,7 @@ pub struct Window { } impl Window { - fn open_window(name: &str, width: usize, height: usize, scale_factor: i32) -> Option { + fn open_window(name: &str, width: usize, height: usize, opts: WindowOptions, scale_factor: i32) -> Option { unsafe { let class_name = to_wstring("minifb_window"); let class = WNDCLASSW { @@ -337,12 +344,28 @@ impl Window { let window_name = to_wstring(name); + let mut flags = 0; + + if opts.title { + flags |= winapi::WS_OVERLAPPEDWINDOW as u32; + } + + if opts.resize { + flags |= winapi::WS_THICKFRAME as u32 | winapi::WS_MAXIMIZEBOX as u32 ; + + } else { + flags &= !winapi::WS_MAXIMIZEBOX; + flags &= !winapi::WS_THICKFRAME; + } + + if opts.borderless { + flags &= !winapi::WS_THICKFRAME; + } + let handle = user32::CreateWindowExW(0, class_name.as_ptr(), window_name.as_ptr(), - winapi::WS_OVERLAPPEDWINDOW & - !winapi::WS_MAXIMIZEBOX & - !winapi::WS_THICKFRAME, + flags, winapi::CW_USEDEFAULT, winapi::CW_USEDEFAULT, rect.right, @@ -365,12 +388,12 @@ impl Window { pub fn new(name: &str, width: usize, height: usize, - scale: Scale) + opts: WindowOptions) -> Result { unsafe { - let scale_factor = Self::get_scale_factor(width, height, scale); + let scale_factor = Self::get_scale_factor(width, height, opts.scale); - let handle = Self::open_window(name, width, height, scale_factor); + let handle = Self::open_window(name, width, height, opts, scale_factor); if handle.is_none() { return Err("Unable to create Window"); @@ -392,6 +415,11 @@ impl Window { } } + #[inline] + pub fn get_window_handle(&self) -> *mut raw::c_void { + self.window.unwrap() as *mut raw::c_void + } + #[inline] pub fn set_position(&mut self, x: isize, y: isize) { unsafe { @@ -461,10 +489,8 @@ impl Window { return self.is_open } - pub fn update(&mut self, buffer: &[u32]) { + fn generic_update(&mut self, window: HWND) { unsafe { - let mut msg = mem::uninitialized(); - let window = self.window.unwrap(); let mut point: winapi::POINT = mem::uninitialized(); user32::GetCursorPos(&mut point); @@ -474,18 +500,15 @@ impl Window { self.mouse.y = point.y as f32; self.mouse.scroll = 0.0; - //self.mouse_data.x - - //println!("{} {}", point.x, point.y); - self.key_handler.update(); - // TODO: Optimize - - self.buffer = buffer.iter().cloned().collect(); - set_window_long(window, mem::transmute(self)); - user32::InvalidateRect(window, ptr::null_mut(), winapi::TRUE); + } + } + + fn message_loop(&mut self, window: HWND) { + unsafe { + let mut msg = mem::uninitialized(); while user32::PeekMessageW(&mut msg, window, 0, 0, winapi::winuser::PM_REMOVE) != 0 { user32::TranslateMessage(&mut msg); @@ -494,6 +517,26 @@ impl Window { } } + pub fn update_with_buffer(&mut self, buffer: &[u32]) { + let window = self.window.unwrap(); + + Self::generic_update(self, window); + + self.buffer = buffer.iter().cloned().collect(); + unsafe { + user32::InvalidateRect(window, ptr::null_mut(), winapi::TRUE); + } + + Self::message_loop(self, window); + } + + pub fn update(&mut self) { + let window = self.window.unwrap(); + + Self::generic_update(self, window); + Self::message_loop(self, window); + } + unsafe fn get_scale_factor(width: usize, height: usize, scale: Scale) -> i32 { let factor: i32 = match scale { Scale::X1 => 1, diff --git a/src/window_flags.rs b/src/window_flags.rs new file mode 100644 index 0000000..7ef59a4 --- /dev/null +++ b/src/window_flags.rs @@ -0,0 +1,30 @@ +#[allow(dead_code)] +const WINDOW_BORDERLESS: u32 = 1 << 1; +#[allow(dead_code)] +const WINDOW_RESIZE: u32 = 1 << 2; +#[allow(dead_code)] +const WINDOW_TITLE: u32 = 1 << 3; + +use WindowOptions; + +// +// Construct a bitmask of flags (sent to backends) from WindowOpts +// +#[allow(dead_code)] +pub fn get_flags(opts: WindowOptions) -> u32 { + let mut flags = 0u32; + + if opts.borderless { + flags |= WINDOW_BORDERLESS; + } + + if opts.title { + flags |= WINDOW_TITLE; + } + + if opts.resize { + flags |= WINDOW_RESIZE; + } + + flags +}