From e51dd82478c0f0eb3e8b54ce6439f6e0d7bb92dc Mon Sep 17 00:00:00 2001 From: Nathaniel Theis Date: Wed, 1 Apr 2015 10:04:43 -0700 Subject: [PATCH] cursor state on w32 --- src/win32/callback.rs | 69 +++++++++++++++++++++++++++++++++++-------- src/win32/init.rs | 21 +++++++++---- src/win32/mod.rs | 7 +++-- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/win32/callback.rs b/src/win32/callback.rs index 1cfb640f..66d88e7a 100644 --- a/src/win32/callback.rs +++ b/src/win32/callback.rs @@ -1,30 +1,41 @@ use std::mem; +use std::ptr; use std::rc::Rc; use std::cell::RefCell; use std::sync::mpsc::Sender; +use std::sync::{ + Arc, + Mutex +}; +use CursorState; use Event; use super::event; use user32; use winapi; -/// Stores the current window and its events dispatcher. -/// -/// We only have one window per thread. We still store the HWND in case where we -/// receive an event for another window. -thread_local!(pub static WINDOW: Rc)>>> = Rc::new(RefCell::new(None))); +/// There's no parameters passed to the callback function, so it needs to get +/// its context (the HWND, the Sender for events, etc.) stashed in +/// a thread-local variable. +thread_local!(pub static CONTEXT_STASH: RefCell> = RefCell::new(None)); + +pub struct ThreadLocalData { + pub win: winapi::HWND, + pub sender: Sender, + pub cursor_state: Arc> +} /// Checks that the window is the good one, and if so send the event to it. fn send_event(input_window: winapi::HWND, event: Event) { - WINDOW.with(|window| { - let window = window.borrow(); - let stored = match *window { + CONTEXT_STASH.with(|context_stash| { + let context_stash = context_stash.borrow(); + let stored = match *context_stash { None => return, Some(ref v) => v }; - let &(ref win, ref sender) = stored; + let &ThreadLocalData { ref win, ref sender, .. } = stored; if win != &input_window { return; @@ -45,13 +56,15 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, winapi::WM_DESTROY => { use events::Event::Closed; - WINDOW.with(|w| { - let w = w.borrow(); - let &(ref win, _) = match *w { + CONTEXT_STASH.with(|context_stash| { + let context_stash = context_stash.borrow(); + let stored = match *context_stash { None => return, Some(ref v) => v }; + let &ThreadLocalData { ref win, .. } = stored; + if win == &window { user32::PostQuitMessage(0); } @@ -209,6 +222,38 @@ pub unsafe extern "system" fn callback(window: winapi::HWND, msg: winapi::UINT, 0 }, + winapi::WM_SETCURSOR => { + CONTEXT_STASH.with(|context_stash| { + let cstash = context_stash.borrow(); + let cstash = cstash.as_ref(); + // there's a very bizarre borrow checker bug + // possibly related to rust-lang/rust/#23338 + let cursor_state = if let Some(cstash) = cstash { + if let Ok(cursor_state) = cstash.cursor_state.lock() { + match *cursor_state { + CursorState::Normal => { + unsafe { + user32::SetCursor(user32::LoadCursorW( + ptr::null_mut(), + winapi::IDC_ARROW)); + } + }, + CursorState::Grab | CursorState::Hide => { + unsafe { + user32::SetCursor(ptr::null_mut()); + } + } + } + } + } else { + return + }; + +// let &ThreadLocalData { ref cursor_state, .. } = stored; + }); + 0 + }, + _ => { user32::DefWindowProcW(window, msg, wparam, lparam) } diff --git a/src/win32/init.rs b/src/win32/init.rs index c5e18ccf..08fb3b37 100644 --- a/src/win32/init.rs +++ b/src/win32/init.rs @@ -1,4 +1,8 @@ use std::sync::atomic::AtomicBool; +use std::sync::{ + Arc, + Mutex +}; use std::ptr; use std::mem; use std::os; @@ -21,7 +25,6 @@ use PixelFormat; use std::ffi::CString; use std::sync::mpsc::channel; -use std::sync::Mutex; use libc; use super::gl; @@ -221,12 +224,20 @@ unsafe fn init(title: Vec, builder: BuilderAttribs<'static>, user32::SetForegroundWindow(real_window.0); } - // filling the WINDOW task-local storage so that we can start receiving events + // Creating a mutex to track the current cursor state + let cursor_state = Arc::new(Mutex::new(CursorState::Normal)); + + // filling the CONTEXT_STASH task-local storage so that we can start receiving events let events_receiver = { let (tx, rx) = channel(); let mut tx = Some(tx); - callback::WINDOW.with(|window| { - (*window.borrow_mut()) = Some((real_window.0, tx.take().unwrap())); + callback::CONTEXT_STASH.with(|context_stash| { + let data = callback::ThreadLocalData { + win: real_window.0, + sender: tx.take().unwrap(), + cursor_state: cursor_state.clone() + }; + (*context_stash.borrow_mut()) = Some(data); }); rx }; @@ -252,7 +263,7 @@ unsafe fn init(title: Vec, builder: BuilderAttribs<'static>, gl_library: gl_library, events_receiver: events_receiver, is_closed: AtomicBool::new(false), - cursor_state: Mutex::new(CursorState::Normal), + cursor_state: cursor_state, }) } diff --git a/src/win32/mod.rs b/src/win32/mod.rs index e20d8b7c..2769bf17 100644 --- a/src/win32/mod.rs +++ b/src/win32/mod.rs @@ -2,7 +2,10 @@ use std::sync::atomic::AtomicBool; use std::mem; use std::ptr; use std::ffi::CString; -use std::sync::Mutex; +use std::sync::{ + Arc, + Mutex +}; use std::sync::mpsc::Receiver; use libc; use {CreationError, Event, MouseCursor}; @@ -47,7 +50,7 @@ pub struct Window { is_closed: AtomicBool, /// The current cursor state. - cursor_state: Mutex, + cursor_state: Arc>, } unsafe impl Send for Window {}