mirror of
https://github.com/rust-windowing/winit.git
synced 2026-09-01 06:10:07 -04:00
Remove second thread from win32 backend
This commit is contained in:
@@ -39,6 +39,7 @@ core-graphics = "0.17.3"
|
|||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
features = [
|
features = [
|
||||||
"combaseapi",
|
"combaseapi",
|
||||||
|
"commctrl",
|
||||||
"dwmapi",
|
"dwmapi",
|
||||||
"errhandlingapi",
|
"errhandlingapi",
|
||||||
"hidusage",
|
"hidusage",
|
||||||
|
|||||||
@@ -240,15 +240,6 @@ impl EventLoop {
|
|||||||
MonitorId { inner: self.events_loop.get_primary_monitor() }
|
MonitorId { inner: self.events_loop.get_primary_monitor() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetches all the events that are pending, calls the callback function for each of them,
|
|
||||||
/// and returns.
|
|
||||||
#[inline]
|
|
||||||
pub fn poll_events<F>(&mut self, callback: F)
|
|
||||||
where F: FnMut(Event)
|
|
||||||
{
|
|
||||||
self.events_loop.poll_events(callback)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calls `callback` every time an event is received. If no event is available, sleeps the
|
/// Calls `callback` every time an event is received. If no event is available, sleeps the
|
||||||
/// current thread and waits for an event. If the callback returns `ControlFlow::Break` then
|
/// current thread and waits for an event. If the callback returns `ControlFlow::Break` then
|
||||||
/// `run_forever` will immediately return.
|
/// `run_forever` will immediately return.
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use std::os::windows::ffi::OsStringExt;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::{mem, ptr};
|
use std::{mem, ptr};
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use winapi::ctypes::c_void;
|
use winapi::ctypes::c_void;
|
||||||
use winapi::shared::guiddef::REFIID;
|
use winapi::shared::guiddef::REFIID;
|
||||||
@@ -14,7 +16,6 @@ use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl};
|
|||||||
use winapi::um::winnt::HRESULT;
|
use winapi::um::winnt::HRESULT;
|
||||||
use winapi::um::{shellapi, unknwnbase};
|
use winapi::um::{shellapi, unknwnbase};
|
||||||
|
|
||||||
use platform::platform::events_loop::send_event;
|
|
||||||
use platform::platform::WindowId;
|
use platform::platform::WindowId;
|
||||||
|
|
||||||
use {Event, WindowId as SuperWindowId};
|
use {Event, WindowId as SuperWindowId};
|
||||||
@@ -24,6 +25,7 @@ pub struct FileDropHandlerData {
|
|||||||
pub interface: IDropTarget,
|
pub interface: IDropTarget,
|
||||||
refcount: AtomicUsize,
|
refcount: AtomicUsize,
|
||||||
window: HWND,
|
window: HWND,
|
||||||
|
event_queue: Rc<RefCell<Vec<Event>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FileDropHandler {
|
pub struct FileDropHandler {
|
||||||
@@ -32,13 +34,14 @@ pub struct FileDropHandler {
|
|||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl FileDropHandler {
|
impl FileDropHandler {
|
||||||
pub fn new(window: HWND) -> FileDropHandler {
|
pub fn new(window: HWND, event_queue: Rc<RefCell<Vec<Event>>>) -> FileDropHandler {
|
||||||
let data = Box::new(FileDropHandlerData {
|
let data = Box::new(FileDropHandlerData {
|
||||||
interface: IDropTarget {
|
interface: IDropTarget {
|
||||||
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
|
lpVtbl: &DROP_TARGET_VTBL as *const IDropTargetVtbl,
|
||||||
},
|
},
|
||||||
refcount: AtomicUsize::new(1),
|
refcount: AtomicUsize::new(1),
|
||||||
window,
|
window,
|
||||||
|
event_queue,
|
||||||
});
|
});
|
||||||
FileDropHandler {
|
FileDropHandler {
|
||||||
data: Box::into_raw(data),
|
data: Box::into_raw(data),
|
||||||
@@ -82,7 +85,7 @@ impl FileDropHandler {
|
|||||||
use events::WindowEvent::HoveredFile;
|
use events::WindowEvent::HoveredFile;
|
||||||
let drop_handler = Self::from_interface(this);
|
let drop_handler = Self::from_interface(this);
|
||||||
Self::iterate_filenames(pDataObj, |filename| {
|
Self::iterate_filenames(pDataObj, |filename| {
|
||||||
send_event(Event::WindowEvent {
|
drop_handler.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
||||||
event: HoveredFile(filename),
|
event: HoveredFile(filename),
|
||||||
});
|
});
|
||||||
@@ -103,7 +106,7 @@ impl FileDropHandler {
|
|||||||
pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT {
|
pub unsafe extern "system" fn DragLeave(this: *mut IDropTarget) -> HRESULT {
|
||||||
use events::WindowEvent::HoveredFileCancelled;
|
use events::WindowEvent::HoveredFileCancelled;
|
||||||
let drop_handler = Self::from_interface(this);
|
let drop_handler = Self::from_interface(this);
|
||||||
send_event(Event::WindowEvent {
|
drop_handler.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
||||||
event: HoveredFileCancelled,
|
event: HoveredFileCancelled,
|
||||||
});
|
});
|
||||||
@@ -121,7 +124,7 @@ impl FileDropHandler {
|
|||||||
use events::WindowEvent::DroppedFile;
|
use events::WindowEvent::DroppedFile;
|
||||||
let drop_handler = Self::from_interface(this);
|
let drop_handler = Self::from_interface(this);
|
||||||
let hdrop = Self::iterate_filenames(pDataObj, |filename| {
|
let hdrop = Self::iterate_filenames(pDataObj, |filename| {
|
||||||
send_event(Event::WindowEvent {
|
drop_handler.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
window_id: SuperWindowId(WindowId(drop_handler.window)),
|
||||||
event: DroppedFile(filename),
|
event: DroppedFile(filename),
|
||||||
});
|
});
|
||||||
@@ -182,6 +185,12 @@ impl FileDropHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FileDropHandlerData {
|
||||||
|
fn send_event(&self, event: Event) {
|
||||||
|
self.event_queue.borrow_mut().push(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for FileDropHandler {
|
impl Drop for FileDropHandler {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@@ -12,11 +12,14 @@
|
|||||||
//! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to
|
//! The closure passed to the `execute_in_thread` method takes an `Inserter` that you can use to
|
||||||
//! add a `WindowState` entry to a list of window to be used by the callback.
|
//! add a `WindowState` entry to a list of window to be used by the callback.
|
||||||
|
|
||||||
use std::{mem, ptr, thread};
|
use winapi::shared::basetsd::DWORD_PTR;
|
||||||
|
use winapi::shared::basetsd::UINT_PTR;
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::{mem, ptr};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::ffi::OsString;
|
||||||
use std::os::windows::io::AsRawHandle;
|
use std::os::windows::ffi::OsStringExt;
|
||||||
use std::sync::{Arc, Barrier, mpsc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use winapi::ctypes::c_int;
|
use winapi::ctypes::c_int;
|
||||||
use winapi::shared::minwindef::{
|
use winapi::shared::minwindef::{
|
||||||
@@ -33,7 +36,7 @@ use winapi::shared::minwindef::{
|
|||||||
use winapi::shared::windef::{HWND, POINT, RECT};
|
use winapi::shared::windef::{HWND, POINT, RECT};
|
||||||
use winapi::shared::windowsx;
|
use winapi::shared::windowsx;
|
||||||
use winapi::shared::winerror::S_OK;
|
use winapi::shared::winerror::S_OK;
|
||||||
use winapi::um::{winuser, processthreadsapi, ole2};
|
use winapi::um::{winuser, processthreadsapi, ole2, shellapi, commctrl};
|
||||||
use winapi::um::oleidl::LPDROPTARGET;
|
use winapi::um::oleidl::LPDROPTARGET;
|
||||||
use winapi::um::winnt::{LONG, LPCSTR, SHORT};
|
use winapi::um::winnt::{LONG, LPCSTR, SHORT};
|
||||||
|
|
||||||
@@ -102,6 +105,19 @@ pub struct WindowState {
|
|||||||
pub always_on_top: bool,
|
pub always_on_top: bool,
|
||||||
pub maximized: bool,
|
pub maximized: bool,
|
||||||
pub resizable: bool,
|
pub resizable: bool,
|
||||||
|
pub mouse_buttons_down: u32
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct SubclassInput {
|
||||||
|
pub window_state: Arc<Mutex<WindowState>>,
|
||||||
|
pub event_queue: Rc<RefCell<Vec<Event>>>,
|
||||||
|
pub file_drop_handler: FileDropHandler
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SubclassInput {
|
||||||
|
fn send_event(&self, event: Event) {
|
||||||
|
self.event_queue.borrow_mut().push(event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowState {
|
impl WindowState {
|
||||||
@@ -117,27 +133,10 @@ impl WindowState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dummy object that allows inserting a window's state.
|
|
||||||
// We store a pointer in order to !impl Send and Sync.
|
|
||||||
pub struct Inserter(*mut u8);
|
|
||||||
|
|
||||||
impl Inserter {
|
|
||||||
/// Inserts a window's state for the callback to use. The state is removed automatically if the
|
|
||||||
/// callback receives a `WM_CLOSE` message for the window.
|
|
||||||
pub fn insert(&self, window: HWND, state: Arc<Mutex<WindowState>>) {
|
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
|
||||||
let was_in = context_stash.as_mut().unwrap().windows.insert(window, state);
|
|
||||||
assert!(was_in.is_none());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EventLoop {
|
pub struct EventLoop {
|
||||||
// Id of the background thread from the Win32 API.
|
// Id of the background thread from the Win32 API.
|
||||||
thread_id: DWORD,
|
thread_id: DWORD,
|
||||||
// Receiver for the events. The sender is in the background thread.
|
pub(crate) event_queue: Rc<RefCell<Vec<Event>>>
|
||||||
receiver: mpsc::Receiver<Event>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EventLoop {
|
impl EventLoop {
|
||||||
@@ -148,101 +147,55 @@ impl EventLoop {
|
|||||||
pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop {
|
pub fn with_dpi_awareness(dpi_aware: bool) -> EventLoop {
|
||||||
become_dpi_aware(dpi_aware);
|
become_dpi_aware(dpi_aware);
|
||||||
|
|
||||||
// The main events transfer channel.
|
let thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
||||||
let (tx, rx) = mpsc::channel();
|
|
||||||
|
|
||||||
// Local barrier in order to block the `new()` function until the background thread has
|
|
||||||
// an events queue.
|
|
||||||
let barrier = Arc::new(Barrier::new(2));
|
|
||||||
let barrier_clone = barrier.clone();
|
|
||||||
|
|
||||||
let thread = thread::spawn(move || {
|
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
|
||||||
*context_stash.borrow_mut() = Some(ThreadLocalData {
|
|
||||||
sender: tx,
|
|
||||||
windows: HashMap::with_capacity(4),
|
|
||||||
file_drop_handlers: HashMap::with_capacity(4),
|
|
||||||
mouse_buttons_down: 0,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
// Calling `PostThreadMessageA` on a thread that does not have an events queue yet
|
|
||||||
// will fail. In order to avoid this situation, we call `IsGuiThread` to initialize
|
|
||||||
// it.
|
|
||||||
winuser::IsGUIThread(1);
|
|
||||||
// Then only we unblock the `new()` function. We are sure that we don't call
|
|
||||||
// `PostThreadMessageA()` before `new()` returns.
|
|
||||||
barrier_clone.wait();
|
|
||||||
drop(barrier_clone);
|
|
||||||
|
|
||||||
let mut msg = mem::uninitialized();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 {
|
|
||||||
// Only happens if the message is `WM_QUIT`.
|
|
||||||
debug_assert_eq!(msg.message, winuser::WM_QUIT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
match msg.message {
|
|
||||||
x if x == *EXEC_MSG_ID => {
|
|
||||||
let mut function: Box<Box<FnMut(Inserter)>> = Box::from_raw(msg.wParam as usize as *mut _);
|
|
||||||
function(Inserter(ptr::null_mut()));
|
|
||||||
},
|
|
||||||
x if x == *WAKEUP_MSG_ID => {
|
|
||||||
send_event(Event::Awakened);
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
// Calls `callback` below.
|
|
||||||
winuser::TranslateMessage(&msg);
|
|
||||||
winuser::DispatchMessageW(&msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Blocks this function until the background thread has an events loop. See other comments.
|
|
||||||
barrier.wait();
|
|
||||||
|
|
||||||
let thread_id = unsafe {
|
|
||||||
let handle = mem::transmute(thread.as_raw_handle());
|
|
||||||
processthreadsapi::GetThreadId(handle)
|
|
||||||
};
|
|
||||||
|
|
||||||
EventLoop {
|
EventLoop {
|
||||||
thread_id,
|
thread_id,
|
||||||
receiver: rx,
|
event_queue: Rc::new(RefCell::new(Vec::new()))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn poll_events<F>(&mut self, mut callback: F)
|
|
||||||
where F: FnMut(Event)
|
|
||||||
{
|
|
||||||
loop {
|
|
||||||
let event = match self.receiver.try_recv() {
|
|
||||||
Ok(e) => e,
|
|
||||||
Err(_) => return
|
|
||||||
};
|
|
||||||
|
|
||||||
callback(event);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_forever<F>(&mut self, mut callback: F)
|
pub fn run_forever<F>(&mut self, mut callback: F)
|
||||||
where F: FnMut(Event) -> ControlFlow
|
where F: FnMut(Event) -> ControlFlow
|
||||||
{
|
{
|
||||||
loop {
|
unsafe {
|
||||||
let event = match self.receiver.recv() {
|
// Calling `PostThreadMessageA` on a thread that does not have an events queue yet
|
||||||
Ok(e) => e,
|
// will fail. In order to avoid this situation, we call `IsGuiThread` to initialize
|
||||||
Err(_) => return
|
// it.
|
||||||
};
|
winuser::IsGUIThread(1);
|
||||||
|
|
||||||
let flow = callback(event);
|
let mut msg = mem::uninitialized();
|
||||||
match flow {
|
|
||||||
ControlFlow::Continue => continue,
|
loop {
|
||||||
ControlFlow::Break => break,
|
if winuser::GetMessageW(&mut msg, ptr::null_mut(), 0, 0) == 0 {
|
||||||
|
// Only happens if the message is `WM_QUIT`.
|
||||||
|
debug_assert_eq!(msg.message, winuser::WM_QUIT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match msg.message {
|
||||||
|
x if x == *WAKEUP_MSG_ID => {
|
||||||
|
if ControlFlow::Break == callback(Event::Awakened) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
x if x == *EXEC_MSG_ID => {
|
||||||
|
let mut function: Box<Box<FnMut()>> = Box::from_raw(msg.wParam as usize as *mut _);
|
||||||
|
function()
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// Calls `callback` below.
|
||||||
|
winuser::TranslateMessage(&msg);
|
||||||
|
winuser::DispatchMessageW(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut event_queue = self.event_queue.borrow_mut();
|
||||||
|
for event in event_queue.drain(..) {
|
||||||
|
if ControlFlow::Break == callback(event) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,19 +205,6 @@ impl EventLoop {
|
|||||||
thread_id: self.thread_id,
|
thread_id: self.thread_id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a function in the background thread.
|
|
||||||
///
|
|
||||||
/// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent
|
|
||||||
/// to the unstable FnBox.
|
|
||||||
///
|
|
||||||
/// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is
|
|
||||||
/// removed automatically if the callback receives a `WM_CLOSE` message for the window.
|
|
||||||
pub(super) fn execute_in_thread<F>(&self, function: F)
|
|
||||||
where F: FnMut(Inserter) + Send + 'static
|
|
||||||
{
|
|
||||||
self.create_proxy().execute_in_thread(function)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for EventLoop {
|
impl Drop for EventLoop {
|
||||||
@@ -299,11 +239,14 @@ impl EventLoopProxy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes a function in the background thread.
|
/// Check to see if we're in the parent event loop's thread.
|
||||||
///
|
pub(super) fn in_event_loop_thread(&self) -> bool {
|
||||||
/// Note that we use FnMut instead of FnOnce because boxing FnOnce won't work on stable Rust
|
let cur_thread_id = unsafe { processthreadsapi::GetCurrentThreadId() };
|
||||||
/// until 2030 when the design of Box is finally complete.
|
self.thread_id == cur_thread_id
|
||||||
/// https://github.com/rust-lang/rust/issues/28796
|
}
|
||||||
|
|
||||||
|
/// Executes a function in the event loop thread. If we're already in the event loop thread,
|
||||||
|
/// we just call the function directly.
|
||||||
///
|
///
|
||||||
/// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is
|
/// The `Inserted` can be used to inject a `WindowState` for the callback to use. The state is
|
||||||
/// removed automatically if the callback receives a `WM_CLOSE` message for the window.
|
/// removed automatically if the callback receives a `WM_CLOSE` message for the window.
|
||||||
@@ -312,25 +255,29 @@ impl EventLoopProxy {
|
|||||||
/// `WindowState` then you should call this within the lock of `WindowState`. Otherwise the
|
/// `WindowState` then you should call this within the lock of `WindowState`. Otherwise the
|
||||||
/// events may be sent to the other thread in different order to the one in which you set
|
/// events may be sent to the other thread in different order to the one in which you set
|
||||||
/// `WindowState`, leaving them out of sync.
|
/// `WindowState`, leaving them out of sync.
|
||||||
pub fn execute_in_thread<F>(&self, function: F)
|
///
|
||||||
where
|
/// Note that we use a FnMut instead of a FnOnce because we're too lazy to create an equivalent
|
||||||
F: FnMut(Inserter) + Send + 'static,
|
/// to the unstable FnBox.
|
||||||
|
pub(super) fn execute_in_thread<F>(&self, mut function: F)
|
||||||
|
where F: FnMut() + Send + 'static
|
||||||
{
|
{
|
||||||
// We are using double-boxing here because it make casting back much easier
|
unsafe {
|
||||||
let double_box = Box::new(Box::new(function) as Box<FnMut(_)>);
|
if self.in_event_loop_thread() {
|
||||||
let raw = Box::into_raw(double_box);
|
function();
|
||||||
|
} else {
|
||||||
|
// We double-box because the first box is a fat pointer.
|
||||||
|
let boxed = Box::new(function) as Box<FnMut()>;
|
||||||
|
let boxed2 = Box::new(boxed);
|
||||||
|
|
||||||
let res = unsafe {
|
let raw = Box::into_raw(boxed2);
|
||||||
winuser::PostThreadMessageA(
|
|
||||||
self.thread_id,
|
let res = winuser::PostThreadMessageA(self.thread_id, *EXEC_MSG_ID,
|
||||||
*EXEC_MSG_ID,
|
raw as *mut () as usize as WPARAM, 0);
|
||||||
raw as *mut () as usize as WPARAM,
|
// PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen
|
||||||
0,
|
// as the events loop is still alive) or if the queue is full.
|
||||||
)
|
assert!(res != 0, "PostThreadMessage failed ; is the messages queue full?");
|
||||||
};
|
}
|
||||||
// PostThreadMessage can only fail if the thread ID is invalid (which shouldn't happen as
|
}
|
||||||
// the events loop is still alive) or if the queue is full.
|
|
||||||
assert!(res != 0, "PostThreadMessage failed; is the messages queue full?");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +294,7 @@ lazy_static! {
|
|||||||
// and LPARAM is unused.
|
// and LPARAM is unused.
|
||||||
static ref EXEC_MSG_ID: u32 = {
|
static ref EXEC_MSG_ID: u32 = {
|
||||||
unsafe {
|
unsafe {
|
||||||
winuser::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as LPCSTR)
|
winuser::RegisterWindowMessageA("Winit::ExecMsg\0".as_ptr() as *const i8)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Message sent by a `Window` when it wants to be destroyed by the main thread.
|
// Message sent by a `Window` when it wants to be destroyed by the main thread.
|
||||||
@@ -366,49 +313,32 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's no parameters passed to the callback function, so it needs to get its context stashed
|
|
||||||
// in a thread-local variable.
|
|
||||||
thread_local!(static CONTEXT_STASH: RefCell<Option<ThreadLocalData>> = RefCell::new(None));
|
|
||||||
struct ThreadLocalData {
|
|
||||||
sender: mpsc::Sender<Event>,
|
|
||||||
windows: HashMap<HWND, Arc<Mutex<WindowState>>>,
|
|
||||||
file_drop_handlers: HashMap<HWND, FileDropHandler>, // Each window has its own drop handler.
|
|
||||||
mouse_buttons_down: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility function that dispatches an event on the current thread.
|
|
||||||
pub fn send_event(event: Event) {
|
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
|
||||||
let context_stash = context_stash.borrow();
|
|
||||||
|
|
||||||
let _ = context_stash.as_ref().unwrap().sender.send(event); // Ignoring if closed
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of
|
/// Capture mouse input, allowing `window` to receive mouse events when the cursor is outside of
|
||||||
/// the window.
|
/// the window.
|
||||||
unsafe fn capture_mouse(window: HWND) {
|
unsafe fn capture_mouse(window: HWND, window_state: &mut WindowState) {
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
window_state.mouse_buttons_down += 1;
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
winuser::SetCapture(window);
|
||||||
if let Some(context_stash) = context_stash.as_mut() {
|
|
||||||
context_stash.mouse_buttons_down += 1;
|
|
||||||
winuser::SetCapture(window);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Release mouse input, stopping windows on this thread from receiving mouse input when the cursor
|
/// Release mouse input, stopping windows on this thread from receiving mouse input when the cursor
|
||||||
/// is outside the window.
|
/// is outside the window.
|
||||||
unsafe fn release_mouse() {
|
unsafe fn release_mouse(window_state: &mut WindowState) {
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
window_state.mouse_buttons_down = window_state.mouse_buttons_down.saturating_sub(1);
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
if window_state.mouse_buttons_down == 0 {
|
||||||
if let Some(context_stash) = context_stash.as_mut() {
|
winuser::ReleaseCapture();
|
||||||
context_stash.mouse_buttons_down = context_stash.mouse_buttons_down.saturating_sub(1);
|
}
|
||||||
if context_stash.mouse_buttons_down == 0 {
|
}
|
||||||
winuser::ReleaseCapture();
|
|
||||||
}
|
const WINDOW_SUBCLASS_ID: UINT_PTR = 0;
|
||||||
}
|
pub(crate) fn subclass_window(window: HWND, subclass_input: SubclassInput) {
|
||||||
});
|
let input_ptr = Box::into_raw(Box::new(subclass_input));
|
||||||
|
let subclass_result = unsafe{ commctrl::SetWindowSubclass(
|
||||||
|
window,
|
||||||
|
Some(callback),
|
||||||
|
WINDOW_SUBCLASS_ID,
|
||||||
|
input_ptr as DWORD_PTR
|
||||||
|
) };
|
||||||
|
assert_eq!(subclass_result, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Any window whose callback is configured to this function will have its events propagated
|
/// Any window whose callback is configured to this function will have its events propagated
|
||||||
@@ -423,40 +353,20 @@ pub unsafe extern "system" fn callback(
|
|||||||
msg: UINT,
|
msg: UINT,
|
||||||
wparam: WPARAM,
|
wparam: WPARAM,
|
||||||
lparam: LPARAM,
|
lparam: LPARAM,
|
||||||
|
_: UINT_PTR,
|
||||||
|
subclass_input_ptr: DWORD_PTR
|
||||||
) -> LRESULT {
|
) -> LRESULT {
|
||||||
|
let subclass_input = &mut*(subclass_input_ptr as *mut SubclassInput);
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
winuser::WM_CREATE => {
|
|
||||||
use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE};
|
|
||||||
let ole_init_result = ole2::OleInitialize(ptr::null_mut());
|
|
||||||
// It is ok if the initialize result is `S_FALSE` because it might happen that
|
|
||||||
// multiple windows are created on the same thread.
|
|
||||||
if ole_init_result == OLE_E_WRONGCOMPOBJ {
|
|
||||||
panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`");
|
|
||||||
} else if ole_init_result == RPC_E_CHANGED_MODE {
|
|
||||||
panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`");
|
|
||||||
}
|
|
||||||
|
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
|
||||||
|
|
||||||
let drop_handlers = &mut context_stash.as_mut().unwrap().file_drop_handlers;
|
|
||||||
let new_handler = FileDropHandler::new(window);
|
|
||||||
let handler_interface_ptr = &mut (*new_handler.data).interface as LPDROPTARGET;
|
|
||||||
drop_handlers.insert(window, new_handler);
|
|
||||||
|
|
||||||
assert_eq!(ole2::RegisterDragDrop(window, handler_interface_ptr), S_OK);
|
|
||||||
});
|
|
||||||
0
|
|
||||||
},
|
|
||||||
|
|
||||||
winuser::WM_NCCREATE => {
|
winuser::WM_NCCREATE => {
|
||||||
enable_non_client_dpi_scaling(window);
|
enable_non_client_dpi_scaling(window);
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
},
|
},
|
||||||
|
|
||||||
winuser::WM_CLOSE => {
|
winuser::WM_CLOSE => {
|
||||||
use events::WindowEvent::CloseRequested;
|
use events::WindowEvent::CloseRequested;
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: CloseRequested
|
event: CloseRequested
|
||||||
});
|
});
|
||||||
@@ -465,27 +375,24 @@ pub unsafe extern "system" fn callback(
|
|||||||
|
|
||||||
winuser::WM_DESTROY => {
|
winuser::WM_DESTROY => {
|
||||||
use events::WindowEvent::Destroyed;
|
use events::WindowEvent::Destroyed;
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
ole2::RevokeDragDrop(window);
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
ole2::RevokeDragDrop(window);
|
|
||||||
let context_stash_mut = context_stash.as_mut().unwrap();
|
|
||||||
context_stash_mut.file_drop_handlers.remove(&window);
|
|
||||||
context_stash_mut.windows.remove(&window);
|
|
||||||
});
|
|
||||||
send_event(Event::WindowEvent {
|
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: Destroyed
|
event: Destroyed
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Box::from_raw(subclass_input);
|
||||||
|
drop(subclass_input);
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
|
|
||||||
winuser::WM_PAINT => {
|
winuser::WM_PAINT => {
|
||||||
use events::WindowEvent::Redraw;
|
use events::WindowEvent::Redraw;
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: Redraw,
|
event: Redraw,
|
||||||
});
|
});
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
},
|
},
|
||||||
|
|
||||||
// WM_MOVE supplies client area positions, so we send Moved here instead.
|
// WM_MOVE supplies client area positions, so we send Moved here instead.
|
||||||
@@ -499,14 +406,14 @@ pub unsafe extern "system" fn callback(
|
|||||||
((*windowpos).x, (*windowpos).y),
|
((*windowpos).x, (*windowpos).y),
|
||||||
dpi_factor,
|
dpi_factor,
|
||||||
);
|
);
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: Moved(logical_position),
|
event: Moved(logical_position),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is necessary for us to still get sent WM_SIZE.
|
// This is necessary for us to still get sent WM_SIZE.
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
},
|
},
|
||||||
|
|
||||||
winuser::WM_SIZE => {
|
winuser::WM_SIZE => {
|
||||||
@@ -514,21 +421,14 @@ pub unsafe extern "system" fn callback(
|
|||||||
let w = LOWORD(lparam as DWORD) as u32;
|
let w = LOWORD(lparam as DWORD) as u32;
|
||||||
let h = HIWORD(lparam as DWORD) as u32;
|
let h = HIWORD(lparam as DWORD) as u32;
|
||||||
|
|
||||||
// Wait for the parent thread to process the resize event before returning from the
|
let dpi_factor = get_hwnd_scale_factor(window);
|
||||||
// callback.
|
let logical_size = LogicalSize::from_physical((w, h), dpi_factor);
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
let event = Event::WindowEvent {
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
let cstash = context_stash.as_mut().unwrap();
|
event: Resized(logical_size),
|
||||||
|
};
|
||||||
|
|
||||||
let dpi_factor = get_hwnd_scale_factor(window);
|
subclass_input.send_event(event);
|
||||||
let logical_size = LogicalSize::from_physical((w, h), dpi_factor);
|
|
||||||
let event = Event::WindowEvent {
|
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
|
||||||
event: Resized(logical_size),
|
|
||||||
};
|
|
||||||
|
|
||||||
cstash.sender.send(event).ok();
|
|
||||||
});
|
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -536,7 +436,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
use events::WindowEvent::ReceivedCharacter;
|
use events::WindowEvent::ReceivedCharacter;
|
||||||
let chr: char = mem::transmute(wparam as u32);
|
let chr: char = mem::transmute(wparam as u32);
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: ReceivedCharacter(chr),
|
event: ReceivedCharacter(chr),
|
||||||
});
|
});
|
||||||
@@ -553,23 +453,18 @@ pub unsafe extern "system" fn callback(
|
|||||||
|
|
||||||
winuser::WM_MOUSEMOVE => {
|
winuser::WM_MOUSEMOVE => {
|
||||||
use events::WindowEvent::{CursorEntered, CursorMoved};
|
use events::WindowEvent::{CursorEntered, CursorMoved};
|
||||||
let mouse_outside_window = CONTEXT_STASH.with(|context_stash| {
|
let mouse_outside_window = {
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
let mut window = subclass_input.window_state.lock().unwrap();
|
||||||
if let Some(context_stash) = context_stash.as_mut() {
|
if !window.mouse_in_window {
|
||||||
if let Some(w) = context_stash.windows.get_mut(&window) {
|
window.mouse_in_window = true;
|
||||||
let mut w = w.lock().unwrap();
|
true
|
||||||
if !w.mouse_in_window {
|
} else {
|
||||||
w.mouse_in_window = true;
|
false
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
false
|
|
||||||
});
|
|
||||||
|
|
||||||
if mouse_outside_window {
|
if mouse_outside_window {
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: CursorEntered { device_id: DEVICE_ID },
|
event: CursorEntered { device_id: DEVICE_ID },
|
||||||
});
|
});
|
||||||
@@ -588,7 +483,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
let dpi_factor = get_hwnd_scale_factor(window);
|
let dpi_factor = get_hwnd_scale_factor(window);
|
||||||
let position = LogicalPosition::from_physical((x, y), dpi_factor);
|
let position = LogicalPosition::from_physical((x, y), dpi_factor);
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() },
|
event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() },
|
||||||
});
|
});
|
||||||
@@ -598,23 +493,18 @@ pub unsafe extern "system" fn callback(
|
|||||||
|
|
||||||
winuser::WM_MOUSELEAVE => {
|
winuser::WM_MOUSELEAVE => {
|
||||||
use events::WindowEvent::CursorLeft;
|
use events::WindowEvent::CursorLeft;
|
||||||
let mouse_in_window = CONTEXT_STASH.with(|context_stash| {
|
let mouse_in_window = {
|
||||||
let mut context_stash = context_stash.borrow_mut();
|
let mut window = subclass_input.window_state.lock().unwrap();
|
||||||
if let Some(context_stash) = context_stash.as_mut() {
|
if window.mouse_in_window {
|
||||||
if let Some(w) = context_stash.windows.get_mut(&window) {
|
window.mouse_in_window = false;
|
||||||
let mut w = w.lock().unwrap();
|
true
|
||||||
if w.mouse_in_window {
|
} else {
|
||||||
w.mouse_in_window = false;
|
false
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
false
|
|
||||||
});
|
|
||||||
|
|
||||||
if mouse_in_window {
|
if mouse_in_window {
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: CursorLeft { device_id: DEVICE_ID }
|
event: CursorLeft { device_id: DEVICE_ID }
|
||||||
});
|
});
|
||||||
@@ -631,7 +521,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
let value = value as i32;
|
let value = value as i32;
|
||||||
let value = value as f32 / winuser::WHEEL_DELTA as f32;
|
let value = value as f32 / winuser::WHEEL_DELTA as f32;
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, modifiers: event::get_key_mods() },
|
event: WindowEvent::MouseWheel { device_id: DEVICE_ID, delta: LineDelta(0.0, value), phase: TouchPhase::Moved, modifiers: event::get_key_mods() },
|
||||||
});
|
});
|
||||||
@@ -643,10 +533,10 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::ElementState::Pressed;
|
use events::ElementState::Pressed;
|
||||||
use events::VirtualKeyCode;
|
use events::VirtualKeyCode;
|
||||||
if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 {
|
if msg == winuser::WM_SYSKEYDOWN && wparam as i32 == winuser::VK_F4 {
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
} else {
|
} else {
|
||||||
if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
|
if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: WindowEvent::KeyboardInput {
|
event: WindowEvent::KeyboardInput {
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
@@ -661,7 +551,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
// Windows doesn't emit a delete character by default, but in order to make it
|
// Windows doesn't emit a delete character by default, but in order to make it
|
||||||
// consistent with the other platforms we'll emit a delete character here.
|
// consistent with the other platforms we'll emit a delete character here.
|
||||||
if vkey == Some(VirtualKeyCode::Delete) {
|
if vkey == Some(VirtualKeyCode::Delete) {
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: WindowEvent::ReceivedCharacter('\u{7F}'),
|
event: WindowEvent::ReceivedCharacter('\u{7F}'),
|
||||||
});
|
});
|
||||||
@@ -674,7 +564,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
winuser::WM_KEYUP | winuser::WM_SYSKEYUP => {
|
winuser::WM_KEYUP | winuser::WM_SYSKEYUP => {
|
||||||
use events::ElementState::Released;
|
use events::ElementState::Released;
|
||||||
if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
|
if let Some((scancode, vkey)) = process_key_params(wparam, lparam) {
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: WindowEvent::KeyboardInput {
|
event: WindowEvent::KeyboardInput {
|
||||||
device_id: DEVICE_ID,
|
device_id: DEVICE_ID,
|
||||||
@@ -695,9 +585,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::MouseButton::Left;
|
use events::MouseButton::Left;
|
||||||
use events::ElementState::Pressed;
|
use events::ElementState::Pressed;
|
||||||
|
|
||||||
capture_mouse(window);
|
capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Left, modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -709,9 +599,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::MouseButton::Left;
|
use events::MouseButton::Left;
|
||||||
use events::ElementState::Released;
|
use events::ElementState::Released;
|
||||||
|
|
||||||
release_mouse();
|
release_mouse(&mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Left, modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -723,9 +613,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::MouseButton::Right;
|
use events::MouseButton::Right;
|
||||||
use events::ElementState::Pressed;
|
use events::ElementState::Pressed;
|
||||||
|
|
||||||
capture_mouse(window);
|
capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Right, modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -737,9 +627,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::MouseButton::Right;
|
use events::MouseButton::Right;
|
||||||
use events::ElementState::Released;
|
use events::ElementState::Released;
|
||||||
|
|
||||||
release_mouse();
|
release_mouse(&mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Right, modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -751,9 +641,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::MouseButton::Middle;
|
use events::MouseButton::Middle;
|
||||||
use events::ElementState::Pressed;
|
use events::ElementState::Pressed;
|
||||||
|
|
||||||
capture_mouse(window);
|
capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Middle, modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -765,9 +655,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::MouseButton::Middle;
|
use events::MouseButton::Middle;
|
||||||
use events::ElementState::Released;
|
use events::ElementState::Released;
|
||||||
|
|
||||||
release_mouse();
|
release_mouse(&mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Middle, modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -780,9 +670,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::ElementState::Pressed;
|
use events::ElementState::Pressed;
|
||||||
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
|
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
|
||||||
|
|
||||||
capture_mouse(window);
|
capture_mouse(window, &mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Pressed, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -795,9 +685,9 @@ pub unsafe extern "system" fn callback(
|
|||||||
use events::ElementState::Released;
|
use events::ElementState::Released;
|
||||||
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
|
let xbutton = winuser::GET_XBUTTON_WPARAM(wparam);
|
||||||
|
|
||||||
release_mouse();
|
release_mouse(&mut *subclass_input.window_state.lock().unwrap());
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
|
event: MouseInput { device_id: DEVICE_ID, state: Released, button: Other(xbutton as u8), modifiers: event::get_key_mods() }
|
||||||
});
|
});
|
||||||
@@ -811,12 +701,12 @@ pub unsafe extern "system" fn callback(
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
send_event(Event::DeviceEvent {
|
subclass_input.send_event(Event::DeviceEvent {
|
||||||
device_id: wrap_device_id(lparam as _),
|
device_id: wrap_device_id(lparam as _),
|
||||||
event,
|
event,
|
||||||
});
|
});
|
||||||
|
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
},
|
},
|
||||||
|
|
||||||
winuser::WM_INPUT => {
|
winuser::WM_INPUT => {
|
||||||
@@ -835,21 +725,21 @@ pub unsafe extern "system" fn callback(
|
|||||||
let y = mouse.lLastY as f64;
|
let y = mouse.lLastY as f64;
|
||||||
|
|
||||||
if x != 0.0 {
|
if x != 0.0 {
|
||||||
send_event(Event::DeviceEvent {
|
subclass_input.send_event(Event::DeviceEvent {
|
||||||
device_id,
|
device_id,
|
||||||
event: Motion { axis: 0, value: x }
|
event: Motion { axis: 0, value: x }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if y != 0.0 {
|
if y != 0.0 {
|
||||||
send_event(Event::DeviceEvent {
|
subclass_input.send_event(Event::DeviceEvent {
|
||||||
device_id,
|
device_id,
|
||||||
event: Motion { axis: 1, value: y }
|
event: Motion { axis: 1, value: y }
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if x != 0.0 || y != 0.0 {
|
if x != 0.0 || y != 0.0 {
|
||||||
send_event(Event::DeviceEvent {
|
subclass_input.send_event(Event::DeviceEvent {
|
||||||
device_id,
|
device_id,
|
||||||
event: MouseMotion { delta: (x, y) }
|
event: MouseMotion { delta: (x, y) }
|
||||||
});
|
});
|
||||||
@@ -858,7 +748,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
|
|
||||||
if util::has_flag(mouse.usButtonFlags, winuser::RI_MOUSE_WHEEL) {
|
if util::has_flag(mouse.usButtonFlags, winuser::RI_MOUSE_WHEEL) {
|
||||||
let delta = mouse.usButtonData as SHORT / winuser::WHEEL_DELTA;
|
let delta = mouse.usButtonData as SHORT / winuser::WHEEL_DELTA;
|
||||||
send_event(Event::DeviceEvent {
|
subclass_input.send_event(Event::DeviceEvent {
|
||||||
device_id,
|
device_id,
|
||||||
event: MouseWheel { delta: LineDelta(0.0, delta as f32) }
|
event: MouseWheel { delta: LineDelta(0.0, delta as f32) }
|
||||||
});
|
});
|
||||||
@@ -872,7 +762,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
// seem to be anything else reasonable to do for a mouse
|
// seem to be anything else reasonable to do for a mouse
|
||||||
// button ID.
|
// button ID.
|
||||||
let button = (index + 1) as _;
|
let button = (index + 1) as _;
|
||||||
send_event(Event::DeviceEvent {
|
subclass_input.send_event(Event::DeviceEvent {
|
||||||
device_id,
|
device_id,
|
||||||
event: Button {
|
event: Button {
|
||||||
button,
|
button,
|
||||||
@@ -906,7 +796,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
) {
|
) {
|
||||||
let virtual_keycode = vkey_to_winit_vkey(vkey);
|
let virtual_keycode = vkey_to_winit_vkey(vkey);
|
||||||
|
|
||||||
send_event(Event::DeviceEvent {
|
subclass_input.send_event(Event::DeviceEvent {
|
||||||
device_id,
|
device_id,
|
||||||
event: Key(KeyboardInput {
|
event: Key(KeyboardInput {
|
||||||
scancode,
|
scancode,
|
||||||
@@ -920,7 +810,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
},
|
},
|
||||||
|
|
||||||
winuser::WM_TOUCH => {
|
winuser::WM_TOUCH => {
|
||||||
@@ -939,7 +829,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
let x = (input.x as f64) / 100f64;
|
let x = (input.x as f64) / 100f64;
|
||||||
let y = (input.y as f64) / 100f64;
|
let y = (input.y as f64) / 100f64;
|
||||||
let location = LogicalPosition::from_physical((x, y), dpi_factor);
|
let location = LogicalPosition::from_physical((x, y), dpi_factor);
|
||||||
send_event( Event::WindowEvent {
|
subclass_input.send_event( Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: WindowEvent::Touch(Touch {
|
event: WindowEvent::Touch(Touch {
|
||||||
phase:
|
phase:
|
||||||
@@ -965,7 +855,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
|
|
||||||
winuser::WM_SETFOCUS => {
|
winuser::WM_SETFOCUS => {
|
||||||
use events::WindowEvent::{Focused, CursorMoved};
|
use events::WindowEvent::{Focused, CursorMoved};
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: Focused(true)
|
event: Focused(true)
|
||||||
});
|
});
|
||||||
@@ -975,7 +865,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
let dpi_factor = get_hwnd_scale_factor(window);
|
let dpi_factor = get_hwnd_scale_factor(window);
|
||||||
let position = LogicalPosition::from_physical((x, y), dpi_factor);
|
let position = LogicalPosition::from_physical((x, y), dpi_factor);
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() },
|
event: CursorMoved { device_id: DEVICE_ID, position, modifiers: event::get_key_mods() },
|
||||||
});
|
});
|
||||||
@@ -985,7 +875,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
|
|
||||||
winuser::WM_KILLFOCUS => {
|
winuser::WM_KILLFOCUS => {
|
||||||
use events::WindowEvent::Focused;
|
use events::WindowEvent::Focused;
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: Focused(false)
|
event: Focused(false)
|
||||||
});
|
});
|
||||||
@@ -993,29 +883,22 @@ pub unsafe extern "system" fn callback(
|
|||||||
},
|
},
|
||||||
|
|
||||||
winuser::WM_SETCURSOR => {
|
winuser::WM_SETCURSOR => {
|
||||||
let call_def_window_proc = CONTEXT_STASH.with(|context_stash| {
|
let call_def_window_proc = {
|
||||||
context_stash
|
let window_state = subclass_input.window_state.lock().unwrap();
|
||||||
.borrow()
|
if window_state.mouse_in_window {
|
||||||
.as_ref()
|
let cursor = winuser::LoadCursorW(
|
||||||
.and_then(|cstash| cstash.windows.get(&window))
|
ptr::null_mut(),
|
||||||
.map(|window_state_mutex| {
|
window_state.cursor.0,
|
||||||
let window_state = window_state_mutex.lock().unwrap();
|
);
|
||||||
if window_state.mouse_in_window {
|
winuser::SetCursor(cursor);
|
||||||
let cursor = winuser::LoadCursorW(
|
false
|
||||||
ptr::null_mut(),
|
} else {
|
||||||
window_state.cursor.0,
|
true
|
||||||
);
|
}
|
||||||
winuser::SetCursor(cursor);
|
};
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(true)
|
|
||||||
});
|
|
||||||
|
|
||||||
if call_def_window_proc {
|
if call_def_window_proc {
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
@@ -1028,29 +911,21 @@ pub unsafe extern "system" fn callback(
|
|||||||
|
|
||||||
winuser::WM_GETMINMAXINFO => {
|
winuser::WM_GETMINMAXINFO => {
|
||||||
let mmi = lparam as *mut winuser::MINMAXINFO;
|
let mmi = lparam as *mut winuser::MINMAXINFO;
|
||||||
//(*mmi).max_position = winapi::shared::windef::POINT { x: -8, y: -8 }; // The upper left corner of the window if it were maximized on the primary monitor.
|
|
||||||
//(*mmi).max_size = winapi::shared::windef::POINT { x: .., y: .. }; // The dimensions of the primary monitor.
|
|
||||||
|
|
||||||
CONTEXT_STASH.with(|context_stash| {
|
let window_state = subclass_input.window_state.lock().unwrap();
|
||||||
if let Some(cstash) = context_stash.borrow().as_ref() {
|
|
||||||
if let Some(wstash) = cstash.windows.get(&window) {
|
|
||||||
let window_state = wstash.lock().unwrap();
|
|
||||||
|
|
||||||
if window_state.min_size.is_some() || window_state.max_size.is_some() {
|
if window_state.min_size.is_some() || window_state.max_size.is_some() {
|
||||||
let style = winuser::GetWindowLongA(window, winuser::GWL_STYLE) as DWORD;
|
let style = winuser::GetWindowLongA(window, winuser::GWL_STYLE) as DWORD;
|
||||||
let ex_style = winuser::GetWindowLongA(window, winuser::GWL_EXSTYLE) as DWORD;
|
let ex_style = winuser::GetWindowLongA(window, winuser::GWL_EXSTYLE) as DWORD;
|
||||||
if let Some(min_size) = window_state.min_size {
|
if let Some(min_size) = window_state.min_size {
|
||||||
let (width, height) = adjust_size(min_size, style, ex_style);
|
let (width, height) = adjust_size(min_size, style, ex_style);
|
||||||
(*mmi).ptMinTrackSize = POINT { x: width as i32, y: height as i32 };
|
(*mmi).ptMinTrackSize = POINT { x: width as i32, y: height as i32 };
|
||||||
}
|
|
||||||
if let Some(max_size) = window_state.max_size {
|
|
||||||
let (width, height) = adjust_size(max_size, style, ex_style);
|
|
||||||
(*mmi).ptMaxTrackSize = POINT { x: width as i32, y: height as i32 };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
if let Some(max_size) = window_state.max_size {
|
||||||
|
let (width, height) = adjust_size(max_size, style, ex_style);
|
||||||
|
(*mmi).ptMaxTrackSize = POINT { x: width as i32, y: height as i32 };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
0
|
0
|
||||||
},
|
},
|
||||||
@@ -1067,34 +942,27 @@ pub unsafe extern "system" fn callback(
|
|||||||
let new_dpi_x = u32::from(LOWORD(wparam as DWORD));
|
let new_dpi_x = u32::from(LOWORD(wparam as DWORD));
|
||||||
let new_dpi_factor = dpi_to_scale_factor(new_dpi_x);
|
let new_dpi_factor = dpi_to_scale_factor(new_dpi_x);
|
||||||
|
|
||||||
let suppress_resize = CONTEXT_STASH.with(|context_stash| {
|
let suppress_resize = {
|
||||||
context_stash
|
let mut window_state = subclass_input.window_state.lock().unwrap();
|
||||||
.borrow()
|
let suppress_resize = window_state.saved_window_info
|
||||||
.as_ref()
|
.as_mut()
|
||||||
.and_then(|cstash| cstash.windows.get(&window))
|
.map(|saved_window_info| {
|
||||||
.map(|window_state_mutex| {
|
let dpi_changed = if !saved_window_info.is_fullscreen {
|
||||||
let mut window_state = window_state_mutex.lock().unwrap();
|
saved_window_info.dpi_factor.take() != Some(new_dpi_factor)
|
||||||
let suppress_resize = window_state.saved_window_info
|
} else {
|
||||||
.as_mut()
|
false
|
||||||
.map(|saved_window_info| {
|
};
|
||||||
let dpi_changed = if !saved_window_info.is_fullscreen {
|
!dpi_changed || saved_window_info.is_fullscreen
|
||||||
saved_window_info.dpi_factor.take() != Some(new_dpi_factor)
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
};
|
|
||||||
!dpi_changed || saved_window_info.is_fullscreen
|
|
||||||
})
|
|
||||||
.unwrap_or(false);
|
|
||||||
// Now we adjust the min/max dimensions for the new DPI.
|
|
||||||
if !suppress_resize {
|
|
||||||
let old_dpi_factor = window_state.dpi_factor;
|
|
||||||
window_state.update_min_max(old_dpi_factor, new_dpi_factor);
|
|
||||||
}
|
|
||||||
window_state.dpi_factor = new_dpi_factor;
|
|
||||||
suppress_resize
|
|
||||||
})
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false);
|
||||||
});
|
// Now we adjust the min/max dimensions for the new DPI.
|
||||||
|
if !suppress_resize {
|
||||||
|
let old_dpi_factor = window_state.dpi_factor;
|
||||||
|
window_state.update_min_max(old_dpi_factor, new_dpi_factor);
|
||||||
|
}
|
||||||
|
window_state.dpi_factor = new_dpi_factor;
|
||||||
|
suppress_resize
|
||||||
|
};
|
||||||
|
|
||||||
// This prevents us from re-applying DPI adjustment to the restored size after exiting
|
// This prevents us from re-applying DPI adjustment to the restored size after exiting
|
||||||
// fullscreen (the restored size is already DPI adjusted).
|
// fullscreen (the restored size is already DPI adjusted).
|
||||||
@@ -1112,7 +980,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: HiDpiFactorChanged(new_dpi_factor),
|
event: HiDpiFactorChanged(new_dpi_factor),
|
||||||
});
|
});
|
||||||
@@ -1127,7 +995,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
} else if msg == *INITIAL_DPI_MSG_ID {
|
} else if msg == *INITIAL_DPI_MSG_ID {
|
||||||
use events::WindowEvent::HiDpiFactorChanged;
|
use events::WindowEvent::HiDpiFactorChanged;
|
||||||
let scale_factor = dpi_to_scale_factor(wparam as u32);
|
let scale_factor = dpi_to_scale_factor(wparam as u32);
|
||||||
send_event(Event::WindowEvent {
|
subclass_input.send_event(Event::WindowEvent {
|
||||||
window_id: SuperWindowId(WindowId(window)),
|
window_id: SuperWindowId(WindowId(window)),
|
||||||
event: HiDpiFactorChanged(scale_factor),
|
event: HiDpiFactorChanged(scale_factor),
|
||||||
});
|
});
|
||||||
@@ -1165,7 +1033,7 @@ pub unsafe extern "system" fn callback(
|
|||||||
);
|
);
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
winuser::DefWindowProcW(window, msg, wparam, lparam)
|
commctrl::DefSubclassProc(window, msg, wparam, lparam)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ use std::sync::mpsc::channel;
|
|||||||
use winapi::ctypes::c_int;
|
use winapi::ctypes::c_int;
|
||||||
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, LPARAM, TRUE, UINT, WORD, WPARAM};
|
use winapi::shared::minwindef::{BOOL, DWORD, FALSE, LPARAM, TRUE, UINT, WORD, WPARAM};
|
||||||
use winapi::shared::windef::{HWND, LPPOINT, POINT, RECT};
|
use winapi::shared::windef::{HWND, LPPOINT, POINT, RECT};
|
||||||
use winapi::um::{combaseapi, dwmapi, libloaderapi, winuser};
|
use winapi::um::{combaseapi, dwmapi, libloaderapi, winuser, ole2};
|
||||||
use winapi::um::objbase::COINIT_MULTITHREADED;
|
use winapi::um::objbase::COINIT_MULTITHREADED;
|
||||||
use winapi::um::shobjidl_core::{CLSID_TaskbarList, ITaskbarList2};
|
use winapi::um::shobjidl_core::{CLSID_TaskbarList, ITaskbarList2};
|
||||||
use winapi::um::wingdi::{CreateRectRgn, DeleteObject};
|
use winapi::um::wingdi::{CreateRectRgn, DeleteObject};
|
||||||
|
use winapi::um::oleidl::LPDROPTARGET;
|
||||||
use winapi::um::winnt::{LONG, LPCWSTR};
|
use winapi::um::winnt::{LONG, LPCWSTR};
|
||||||
|
|
||||||
use {
|
use {
|
||||||
@@ -32,6 +33,7 @@ use platform::platform::events_loop::{self, DESTROY_MSG_ID, EventLoop, INITIAL_D
|
|||||||
use platform::platform::icon::{self, IconType, WinIcon};
|
use platform::platform::icon::{self, IconType, WinIcon};
|
||||||
use platform::platform::monitor::get_available_monitors;
|
use platform::platform::monitor::get_available_monitors;
|
||||||
use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input;
|
use platform::platform::raw_input::register_all_mice_and_keyboards_for_raw_input;
|
||||||
|
use platform::platform::drop_handler::FileDropHandler;
|
||||||
use platform::platform::util;
|
use platform::platform::util;
|
||||||
|
|
||||||
const WS_RESIZABLE: DWORD = winuser::WS_SIZEBOX | winuser::WS_MAXIMIZEBOX;
|
const WS_RESIZABLE: DWORD = winuser::WS_SIZEBOX | winuser::WS_MAXIMIZEBOX;
|
||||||
@@ -76,15 +78,11 @@ impl Window {
|
|||||||
w_attr: WindowAttributes,
|
w_attr: WindowAttributes,
|
||||||
pl_attr: PlatformSpecificWindowBuilderAttributes,
|
pl_attr: PlatformSpecificWindowBuilderAttributes,
|
||||||
) -> Result<Window, CreationError> {
|
) -> Result<Window, CreationError> {
|
||||||
let (tx, rx) = channel();
|
// We dispatch an `init` function because of code style.
|
||||||
let proxy = events_loop.create_proxy();
|
// First person to remove the need for cloning here gets a cookie!
|
||||||
events_loop.execute_in_thread(move |inserter| {
|
//
|
||||||
// We dispatch an `init` function because of code style.
|
// done. you owe me -- ossi
|
||||||
// First person to remove the need for cloning here gets a cookie!
|
unsafe { init(w_attr, pl_attr, events_loop) }
|
||||||
let win = unsafe { init(w_attr.clone(), pl_attr.clone(), inserter, proxy.clone()) };
|
|
||||||
let _ = tx.send(win);
|
|
||||||
});
|
|
||||||
rx.recv().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_title(&self, text: &str) {
|
pub fn set_title(&self, text: &str) {
|
||||||
@@ -323,7 +321,7 @@ impl Window {
|
|||||||
_ => winuser::IDC_ARROW, // use arrow for the missing cases.
|
_ => winuser::IDC_ARROW, // use arrow for the missing cases.
|
||||||
});
|
});
|
||||||
self.window_state.lock().unwrap().cursor = cursor_id;
|
self.window_state.lock().unwrap().cursor = cursor_id;
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| unsafe {
|
self.events_loop_proxy.execute_in_thread(move || unsafe {
|
||||||
let cursor = winuser::LoadCursorW(
|
let cursor = winuser::LoadCursorW(
|
||||||
ptr::null_mut(),
|
ptr::null_mut(),
|
||||||
cursor_id.0,
|
cursor_id.0,
|
||||||
@@ -385,7 +383,7 @@ impl Window {
|
|||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
let window_state = Arc::clone(&self.window_state);
|
let window_state = Arc::clone(&self.window_state);
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move || {
|
||||||
let result = unsafe { Self::grab_cursor_inner(&window, grab) };
|
let result = unsafe { Self::grab_cursor_inner(&window, grab) };
|
||||||
if result.is_ok() {
|
if result.is_ok() {
|
||||||
window_state.lock().unwrap().cursor_grabbed = grab;
|
window_state.lock().unwrap().cursor_grabbed = grab;
|
||||||
@@ -411,7 +409,7 @@ impl Window {
|
|||||||
if hide == window_state_lock.cursor_hidden { return; }
|
if hide == window_state_lock.cursor_hidden { return; }
|
||||||
let (tx, rx) = channel();
|
let (tx, rx) = channel();
|
||||||
let window_state = Arc::clone(&self.window_state);
|
let window_state = Arc::clone(&self.window_state);
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move || {
|
||||||
unsafe { Self::hide_cursor_inner(hide) };
|
unsafe { Self::hide_cursor_inner(hide) };
|
||||||
window_state.lock().unwrap().cursor_hidden = hide;
|
window_state.lock().unwrap().cursor_hidden = hide;
|
||||||
let _ = tx.send(());
|
let _ = tx.send(());
|
||||||
@@ -459,7 +457,7 @@ impl Window {
|
|||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
unsafe {
|
unsafe {
|
||||||
// `ShowWindow` resizes the window, so it must be called from the main thread.
|
// `ShowWindow` resizes the window, so it must be called from the main thread.
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move || {
|
||||||
winuser::ShowWindow(
|
winuser::ShowWindow(
|
||||||
window.0,
|
window.0,
|
||||||
if maximized {
|
if maximized {
|
||||||
@@ -524,7 +522,7 @@ impl Window {
|
|||||||
|
|
||||||
// We're restoring the window to its size and position from before being fullscreened.
|
// We're restoring the window to its size and position from before being fullscreened.
|
||||||
// `ShowWindow` resizes the window, so it must be called from the main thread.
|
// `ShowWindow` resizes the window, so it must be called from the main thread.
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move || {
|
||||||
let _ = Self::grab_cursor_inner(&window, false);
|
let _ = Self::grab_cursor_inner(&window, false);
|
||||||
|
|
||||||
if resizable {
|
if resizable {
|
||||||
@@ -577,7 +575,7 @@ impl Window {
|
|||||||
let window_state = Arc::clone(&self.window_state);
|
let window_state = Arc::clone(&self.window_state);
|
||||||
|
|
||||||
let (style, ex_style) = self.set_fullscreen_style(&mut window_state_lock);
|
let (style, ex_style) = self.set_fullscreen_style(&mut window_state_lock);
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move || {
|
||||||
let _ = Self::grab_cursor_inner(&window, false);
|
let _ = Self::grab_cursor_inner(&window, false);
|
||||||
|
|
||||||
winuser::SetWindowLongW(
|
winuser::SetWindowLongW(
|
||||||
@@ -674,7 +672,7 @@ impl Window {
|
|||||||
|
|
||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
|
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move || {
|
||||||
winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style);
|
winuser::SetWindowLongW(window.0, winuser::GWL_STYLE, style);
|
||||||
winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style);
|
winuser::SetWindowLongW(window.0, winuser::GWL_EXSTYLE, ex_style);
|
||||||
winuser::AdjustWindowRectEx(&mut rect, style as _, 0, ex_style as _);
|
winuser::AdjustWindowRectEx(&mut rect, style as _, 0, ex_style as _);
|
||||||
@@ -702,7 +700,7 @@ impl Window {
|
|||||||
let mut window_state = self.window_state.lock().unwrap();
|
let mut window_state = self.window_state.lock().unwrap();
|
||||||
if mem::replace(&mut window_state.always_on_top, always_on_top) != always_on_top {
|
if mem::replace(&mut window_state.always_on_top, always_on_top) != always_on_top {
|
||||||
let window = self.window.clone();
|
let window = self.window.clone();
|
||||||
self.events_loop_proxy.execute_in_thread(move |_| {
|
self.events_loop_proxy.execute_in_thread(move || {
|
||||||
let insert_after = if always_on_top {
|
let insert_after = if always_on_top {
|
||||||
winuser::HWND_TOPMOST
|
winuser::HWND_TOPMOST
|
||||||
} else {
|
} else {
|
||||||
@@ -805,8 +803,7 @@ pub unsafe fn adjust_size(
|
|||||||
unsafe fn init(
|
unsafe fn init(
|
||||||
mut attributes: WindowAttributes,
|
mut attributes: WindowAttributes,
|
||||||
mut pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
mut pl_attribs: PlatformSpecificWindowBuilderAttributes,
|
||||||
inserter: events_loop::Inserter,
|
event_loop: &events_loop::EventLoop,
|
||||||
events_loop_proxy: events_loop::EventLoopProxy,
|
|
||||||
) -> Result<Window, CreationError> {
|
) -> Result<Window, CreationError> {
|
||||||
let title = OsStr::new(&attributes.title)
|
let title = OsStr::new(&attributes.title)
|
||||||
.encode_wide()
|
.encode_wide()
|
||||||
@@ -1013,6 +1010,7 @@ unsafe fn init(
|
|||||||
maximized: attributes.maximized,
|
maximized: attributes.maximized,
|
||||||
resizable: attributes.resizable,
|
resizable: attributes.resizable,
|
||||||
always_on_top: attributes.always_on_top,
|
always_on_top: attributes.always_on_top,
|
||||||
|
mouse_buttons_down: 0
|
||||||
};
|
};
|
||||||
// Creating a mutex to track the current window state
|
// Creating a mutex to track the current window state
|
||||||
Arc::new(Mutex::new(window_state))
|
Arc::new(Mutex::new(window_state))
|
||||||
@@ -1048,7 +1046,7 @@ unsafe fn init(
|
|||||||
let win = Window {
|
let win = Window {
|
||||||
window: real_window,
|
window: real_window,
|
||||||
window_state,
|
window_state,
|
||||||
events_loop_proxy,
|
events_loop_proxy: event_loop.create_proxy(),
|
||||||
};
|
};
|
||||||
|
|
||||||
win.set_maximized(attributes.maximized);
|
win.set_maximized(attributes.maximized);
|
||||||
@@ -1057,7 +1055,31 @@ unsafe fn init(
|
|||||||
force_window_active(win.window.0);
|
force_window_active(win.window.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inserter.insert(win.window.0, win.window_state.clone());
|
let file_drop_handler = {
|
||||||
|
use winapi::shared::winerror::{OLE_E_WRONGCOMPOBJ, RPC_E_CHANGED_MODE, S_OK};
|
||||||
|
let ole_init_result = ole2::OleInitialize(ptr::null_mut());
|
||||||
|
// It is ok if the initialize result is `S_FALSE` because it might happen that
|
||||||
|
// multiple windows are created on the same thread.
|
||||||
|
if ole_init_result == OLE_E_WRONGCOMPOBJ {
|
||||||
|
panic!("OleInitialize failed! Result was: `OLE_E_WRONGCOMPOBJ`");
|
||||||
|
} else if ole_init_result == RPC_E_CHANGED_MODE {
|
||||||
|
panic!("OleInitialize failed! Result was: `RPC_E_CHANGED_MODE`");
|
||||||
|
}
|
||||||
|
|
||||||
|
let file_drop_handler = FileDropHandler::new(win.window.0, event_loop.event_queue.clone());
|
||||||
|
let handler_interface_ptr = &mut (*file_drop_handler.data).interface as LPDROPTARGET;
|
||||||
|
|
||||||
|
assert_eq!(ole2::RegisterDragDrop(win.window.0, handler_interface_ptr), S_OK);
|
||||||
|
file_drop_handler
|
||||||
|
};
|
||||||
|
|
||||||
|
let subclass_input = events_loop::SubclassInput {
|
||||||
|
window_state: win.window_state.clone(),
|
||||||
|
event_queue: event_loop.event_queue.clone(),
|
||||||
|
file_drop_handler
|
||||||
|
};
|
||||||
|
|
||||||
|
events_loop::subclass_window(win.window.0, subclass_input);
|
||||||
|
|
||||||
Ok(win)
|
Ok(win)
|
||||||
}
|
}
|
||||||
@@ -1083,7 +1105,7 @@ unsafe fn register_window_class(
|
|||||||
let class = winuser::WNDCLASSEXW {
|
let class = winuser::WNDCLASSEXW {
|
||||||
cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
|
cbSize: mem::size_of::<winuser::WNDCLASSEXW>() as UINT,
|
||||||
style: winuser::CS_HREDRAW | winuser::CS_VREDRAW | winuser::CS_OWNDC,
|
style: winuser::CS_HREDRAW | winuser::CS_VREDRAW | winuser::CS_OWNDC,
|
||||||
lpfnWndProc: Some(events_loop::callback),
|
lpfnWndProc: Some(winuser::DefWindowProcW),
|
||||||
cbClsExtra: 0,
|
cbClsExtra: 0,
|
||||||
cbWndExtra: 0,
|
cbWndExtra: 0,
|
||||||
hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
|
hInstance: libloaderapi::GetModuleHandleW(ptr::null()),
|
||||||
|
|||||||
Reference in New Issue
Block a user