add ability to close window from user code, add HostWindowHandle (#103)
* add ability to close window from user code, add HostWindowHandle * fix manual close method for Mac, rename HostWindowHandle to ChildWindowHandle * fix rustfmt.toml and run cargo format * fix merge conflict mistake * fix more merge conflict mistakes * implement requested changes (with a non-broken commit this time) * implement requested changes * slight reordering of impls
This commit is contained in:
parent
2a894c6bc9
commit
f6e99e9aa6
|
@ -33,4 +33,4 @@ objc = "0.2.7"
|
||||||
uuid = { version = "0.8", features = ["v4"] }
|
uuid = { version = "0.8", features = ["v4"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rtrb = "0.1.1"
|
rtrb = "0.2"
|
||||||
|
|
|
@ -38,7 +38,7 @@ fn main() {
|
||||||
scale: WindowScalePolicy::SystemScaleFactor,
|
scale: WindowScalePolicy::SystemScaleFactor,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mut tx, rx) = RingBuffer::new(128).split();
|
let (mut tx, rx) = RingBuffer::new(128);
|
||||||
|
|
||||||
::std::thread::spawn(move || loop {
|
::std::thread::spawn(move || loop {
|
||||||
::std::thread::sleep(Duration::from_secs(5));
|
::std::thread::sleep(Duration::from_secs(5));
|
||||||
|
|
|
@ -178,7 +178,7 @@ extern "C" fn release(this: &mut Object, _sel: Sel) {
|
||||||
let retain_count_after_build = WindowState::from_field(this).retain_count_after_build;
|
let retain_count_after_build = WindowState::from_field(this).retain_count_after_build;
|
||||||
|
|
||||||
if retain_count <= retain_count_after_build {
|
if retain_count <= retain_count_after_build {
|
||||||
WindowState::from_field(this).remove_timer();
|
WindowState::from_field(this).stop();
|
||||||
|
|
||||||
this.set_ivar(BASEVIEW_STATE_IVAR, ::std::ptr::null() as *const c_void);
|
this.set_ivar(BASEVIEW_STATE_IVAR, ::std::ptr::null() as *const c_void);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use cocoa::appkit::{
|
use cocoa::appkit::{
|
||||||
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSBackingStoreBuffered, NSWindow,
|
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSBackingStoreBuffered, NSWindow,
|
||||||
|
@ -15,21 +18,94 @@ use objc::{msg_send, runtime::Object, sel, sel_impl};
|
||||||
|
|
||||||
use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
use crate::{Event, EventStatus, WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy};
|
use crate::{
|
||||||
|
Event, EventStatus, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
|
||||||
|
WindowScalePolicy,
|
||||||
|
};
|
||||||
|
|
||||||
use super::keyboard::KeyboardState;
|
use super::keyboard::KeyboardState;
|
||||||
use super::view::{create_view, BASEVIEW_STATE_IVAR};
|
use super::view::{create_view, BASEVIEW_STATE_IVAR};
|
||||||
|
|
||||||
|
pub struct WindowHandle {
|
||||||
|
raw_window_handle: Option<RawWindowHandle>,
|
||||||
|
close_requested: Arc<AtomicBool>,
|
||||||
|
is_open: Arc<AtomicBool>,
|
||||||
|
|
||||||
|
// Ensure handle is !Send
|
||||||
|
_phantom: PhantomData<*mut ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowHandle {
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
if let Some(_) = self.raw_window_handle.take() {
|
||||||
|
self.close_requested.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_open(&self) -> bool {
|
||||||
|
self.is_open.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl HasRawWindowHandle for WindowHandle {
|
||||||
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
|
if let Some(raw_window_handle) = self.raw_window_handle {
|
||||||
|
if self.is_open.load(Ordering::Relaxed) {
|
||||||
|
return raw_window_handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RawWindowHandle::MacOS(MacOSHandle { ..MacOSHandle::empty() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParentHandle {
|
||||||
|
_close_requested: Arc<AtomicBool>,
|
||||||
|
is_open: Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParentHandle {
|
||||||
|
pub fn new(raw_window_handle: RawWindowHandle) -> (Self, WindowHandle) {
|
||||||
|
let close_requested = Arc::new(AtomicBool::new(false));
|
||||||
|
let is_open = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
let handle = WindowHandle {
|
||||||
|
raw_window_handle: Some(raw_window_handle),
|
||||||
|
close_requested: Arc::clone(&close_requested),
|
||||||
|
is_open: Arc::clone(&is_open),
|
||||||
|
_phantom: PhantomData::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(Self { _close_requested: close_requested, is_open }, handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn parent_did_drop(&self) -> bool {
|
||||||
|
self.close_requested.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ParentHandle {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.is_open.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
/// Only set if we created the parent window, i.e. we are running in
|
||||||
|
/// parentless mode
|
||||||
|
ns_app: Option<id>,
|
||||||
/// Only set if we created the parent window, i.e. we are running in
|
/// Only set if we created the parent window, i.e. we are running in
|
||||||
/// parentless mode
|
/// parentless mode
|
||||||
ns_window: Option<id>,
|
ns_window: Option<id>,
|
||||||
/// Our subclassed NSView
|
/// Our subclassed NSView
|
||||||
ns_view: id,
|
ns_view: id,
|
||||||
|
close_requested: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
P: HasRawWindowHandle,
|
P: HasRawWindowHandle,
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
|
@ -46,9 +122,9 @@ impl Window {
|
||||||
|
|
||||||
let ns_view = unsafe { create_view(&options) };
|
let ns_view = unsafe { create_view(&options) };
|
||||||
|
|
||||||
let window = Window { ns_window: None, ns_view };
|
let window = Window { ns_app: None, ns_window: None, ns_view, close_requested: false };
|
||||||
|
|
||||||
Self::init(window, build);
|
let window_handle = Self::init(true, window, build);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let _: id = msg_send![handle.ns_view as *mut Object, addSubview: ns_view];
|
let _: id = msg_send![handle.ns_view as *mut Object, addSubview: ns_view];
|
||||||
|
@ -56,9 +132,11 @@ impl Window {
|
||||||
|
|
||||||
let () = msg_send![pool, drain];
|
let () = msg_send![pool, drain];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
@ -68,17 +146,15 @@ impl Window {
|
||||||
|
|
||||||
let ns_view = unsafe { create_view(&options) };
|
let ns_view = unsafe { create_view(&options) };
|
||||||
|
|
||||||
let window = Window { ns_window: None, ns_view };
|
let window = Window { ns_app: None, ns_window: None, ns_view, close_requested: false };
|
||||||
|
|
||||||
let raw_window_handle = window.raw_window_handle();
|
let window_handle = Self::init(true, window, build);
|
||||||
|
|
||||||
Self::init(window, build);
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let () = msg_send![pool, drain];
|
let () = msg_send![pool, drain];
|
||||||
}
|
}
|
||||||
|
|
||||||
raw_window_handle
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
@ -118,7 +194,9 @@ impl Window {
|
||||||
let ns_window = unsafe {
|
let ns_window = unsafe {
|
||||||
let ns_window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
|
let ns_window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
|
||||||
rect,
|
rect,
|
||||||
NSWindowStyleMask::NSTitledWindowMask,
|
NSWindowStyleMask::NSTitledWindowMask
|
||||||
|
| NSWindowStyleMask::NSClosableWindowMask
|
||||||
|
| NSWindowStyleMask::NSMiniaturizableWindowMask,
|
||||||
NSBackingStoreBuffered,
|
NSBackingStoreBuffered,
|
||||||
NO,
|
NO,
|
||||||
);
|
);
|
||||||
|
@ -134,21 +212,26 @@ impl Window {
|
||||||
|
|
||||||
let ns_view = unsafe { create_view(&options) };
|
let ns_view = unsafe { create_view(&options) };
|
||||||
|
|
||||||
let window = Window { ns_window: Some(ns_window), ns_view };
|
let window = Window {
|
||||||
|
ns_app: Some(app),
|
||||||
|
ns_window: Some(ns_window),
|
||||||
|
ns_view,
|
||||||
|
close_requested: false,
|
||||||
|
};
|
||||||
|
|
||||||
Self::init(window, build);
|
let _ = Self::init(false, window, build);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ns_window.setContentView_(ns_view);
|
ns_window.setContentView_(ns_view);
|
||||||
let () = msg_send![ns_view as id, release];
|
|
||||||
|
|
||||||
|
let () = msg_send![ns_view as id, release];
|
||||||
let () = msg_send![pool, drain];
|
let () = msg_send![pool, drain];
|
||||||
|
|
||||||
app.run();
|
app.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init<H, B>(mut window: Window, build: B)
|
fn init<H, B>(parented: bool, mut window: Window, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
@ -156,6 +239,9 @@ impl Window {
|
||||||
{
|
{
|
||||||
let window_handler = Box::new(build(&mut crate::Window::new(&mut window)));
|
let window_handler = Box::new(build(&mut crate::Window::new(&mut window)));
|
||||||
|
|
||||||
|
let (parent_handle, window_handle) = ParentHandle::new(window.raw_window_handle());
|
||||||
|
let parent_handle = if parented { Some(parent_handle) } else { None };
|
||||||
|
|
||||||
let retain_count_after_build: usize = unsafe { msg_send![window.ns_view, retainCount] };
|
let retain_count_after_build: usize = unsafe { msg_send![window.ns_view, retainCount] };
|
||||||
|
|
||||||
let window_state_ptr = Box::into_raw(Box::new(WindowState {
|
let window_state_ptr = Box::into_raw(Box::new(WindowState {
|
||||||
|
@ -164,6 +250,7 @@ impl Window {
|
||||||
keyboard_state: KeyboardState::new(),
|
keyboard_state: KeyboardState::new(),
|
||||||
frame_timer: None,
|
frame_timer: None,
|
||||||
retain_count_after_build,
|
retain_count_after_build,
|
||||||
|
_parent_handle: parent_handle,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -172,6 +259,12 @@ impl Window {
|
||||||
|
|
||||||
WindowState::setup_timer(window_state_ptr);
|
WindowState::setup_timer(window_state_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window_handle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
self.close_requested = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +273,7 @@ pub(super) struct WindowState {
|
||||||
window_handler: Box<dyn WindowHandler>,
|
window_handler: Box<dyn WindowHandler>,
|
||||||
keyboard_state: KeyboardState,
|
keyboard_state: KeyboardState,
|
||||||
frame_timer: Option<CFRunLoopTimer>,
|
frame_timer: Option<CFRunLoopTimer>,
|
||||||
|
_parent_handle: Option<ParentHandle>,
|
||||||
pub retain_count_after_build: usize,
|
pub retain_count_after_build: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,6 +295,36 @@ impl WindowState {
|
||||||
|
|
||||||
pub(super) fn trigger_frame(&mut self) {
|
pub(super) fn trigger_frame(&mut self) {
|
||||||
self.window_handler.on_frame(&mut crate::Window::new(&mut self.window));
|
self.window_handler.on_frame(&mut crate::Window::new(&mut self.window));
|
||||||
|
|
||||||
|
let mut do_close = false;
|
||||||
|
|
||||||
|
/* FIXME: Is it even necessary to check if the parent dropped the handle
|
||||||
|
// in MacOS?
|
||||||
|
// Check if the parent handle was dropped
|
||||||
|
if let Some(parent_handle) = &self.parent_handle {
|
||||||
|
if parent_handle.parent_did_drop() {
|
||||||
|
do_close = true;
|
||||||
|
self.window.close_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Check if the user requested the window to close
|
||||||
|
if self.window.close_requested {
|
||||||
|
do_close = true;
|
||||||
|
self.window.close_requested = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if do_close {
|
||||||
|
unsafe {
|
||||||
|
if let Some(ns_window) = self.window.ns_window.take() {
|
||||||
|
ns_window.close();
|
||||||
|
} else {
|
||||||
|
// FIXME: How do we close a non-parented window? Is this even
|
||||||
|
// possible in a DAW host usecase?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn process_native_key_event(&mut self, event: *mut Object) -> Option<KeyboardEvent> {
|
pub(super) fn process_native_key_event(&mut self, event: *mut Object) -> Option<KeyboardEvent> {
|
||||||
|
@ -235,10 +359,17 @@ impl WindowState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call when freeing view
|
/// Call when freeing view
|
||||||
pub(super) unsafe fn remove_timer(&mut self) {
|
pub(super) unsafe fn stop(&mut self) {
|
||||||
if let Some(frame_timer) = self.frame_timer.take() {
|
if let Some(frame_timer) = self.frame_timer.take() {
|
||||||
CFRunLoop::get_current().remove_timer(&frame_timer, kCFRunLoopDefaultMode);
|
CFRunLoop::get_current().remove_timer(&frame_timer, kCFRunLoopDefaultMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.trigger_event(Event::Window(WindowEvent::WillClose));
|
||||||
|
|
||||||
|
// If in non-parented mode, we want to also quit the app altogether
|
||||||
|
if let Some(app) = self.window.ns_app.take() {
|
||||||
|
app.stop_(app);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,25 +4,29 @@ use winapi::shared::windef::{HWND, RECT};
|
||||||
use winapi::um::combaseapi::CoCreateGuid;
|
use winapi::um::combaseapi::CoCreateGuid;
|
||||||
use winapi::um::winuser::{
|
use winapi::um::winuser::{
|
||||||
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
|
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
|
||||||
GetCapture, GetDpiForWindow, GetMessageW, GetWindowLongPtrW, IsWindow, LoadCursorW,
|
GetDpiForWindow, GetMessageW, GetWindowLongPtrW, LoadCursorW, PostMessageW, RegisterClassW,
|
||||||
PostMessageW, RegisterClassW, ReleaseCapture, SetCapture, SetProcessDpiAwarenessContext,
|
ReleaseCapture, SetCapture, SetProcessDpiAwarenessContext, SetTimer, SetWindowLongPtrW,
|
||||||
SetTimer, SetWindowLongPtrW, SetWindowPos, TranslateMessage, UnregisterClassW, CS_OWNDC,
|
SetWindowPos, TranslateMessage, UnregisterClassW, CS_OWNDC, GET_XBUTTON_WPARAM, GWLP_USERDATA,
|
||||||
GET_XBUTTON_WPARAM, GWLP_USERDATA, IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, WHEEL_DELTA,
|
IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_CREATE,
|
||||||
WM_CHAR, WM_CLOSE, WM_CREATE, WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP,
|
WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP,
|
||||||
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL,
|
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCDESTROY, WM_RBUTTONDOWN,
|
||||||
WM_NCDESTROY, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN,
|
WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TIMER,
|
||||||
WM_SYSKEYUP, WM_TIMER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD,
|
WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS,
|
||||||
WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
|
WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE, XBUTTON1, XBUTTON2,
|
||||||
XBUTTON1, XBUTTON2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ffi::{c_void, OsStr};
|
use std::ffi::OsStr;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use raw_window_handle::{windows::WindowsHandle, HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{windows::WindowsHandle, HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
|
const BV_WINDOW_MUST_CLOSE: UINT = WM_USER + 1;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, MouseButton, MouseEvent, PhyPoint, PhySize, ScrollDelta, WindowEvent, WindowHandler,
|
Event, MouseButton, MouseEvent, PhyPoint, PhySize, ScrollDelta, WindowEvent, WindowHandler,
|
||||||
WindowInfo, WindowOpenOptions, WindowScalePolicy,
|
WindowInfo, WindowOpenOptions, WindowScalePolicy,
|
||||||
|
@ -51,6 +55,65 @@ unsafe fn generate_guid() -> String {
|
||||||
|
|
||||||
const WIN_FRAME_TIMER: usize = 4242;
|
const WIN_FRAME_TIMER: usize = 4242;
|
||||||
|
|
||||||
|
pub struct WindowHandle {
|
||||||
|
hwnd: Option<HWND>,
|
||||||
|
is_open: Arc<AtomicBool>,
|
||||||
|
|
||||||
|
// Ensure handle is !Send
|
||||||
|
_phantom: PhantomData<*mut ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowHandle {
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
if let Some(hwnd) = self.hwnd.take() {
|
||||||
|
unsafe {
|
||||||
|
PostMessageW(hwnd, BV_WINDOW_MUST_CLOSE, 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_open(&self) -> bool {
|
||||||
|
self.is_open.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl HasRawWindowHandle for WindowHandle {
|
||||||
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
|
if let Some(hwnd) = self.hwnd {
|
||||||
|
RawWindowHandle::Windows(WindowsHandle {
|
||||||
|
hwnd: hwnd as *mut std::ffi::c_void,
|
||||||
|
..WindowsHandle::empty()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
RawWindowHandle::Windows(WindowsHandle { ..WindowsHandle::empty() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParentHandle {
|
||||||
|
is_open: Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParentHandle {
|
||||||
|
pub fn new(hwnd: HWND) -> (Self, WindowHandle) {
|
||||||
|
let is_open = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
let handle = WindowHandle {
|
||||||
|
hwnd: Some(hwnd),
|
||||||
|
is_open: Arc::clone(&is_open),
|
||||||
|
_phantom: PhantomData::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(Self { is_open }, handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ParentHandle {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.is_open.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn wnd_proc(
|
unsafe extern "system" fn wnd_proc(
|
||||||
hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM,
|
hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM,
|
||||||
) -> LRESULT {
|
) -> LRESULT {
|
||||||
|
@ -247,7 +310,12 @@ unsafe extern "system" fn wnd_proc(
|
||||||
unregister_wnd_class(window_state.borrow().window_class);
|
unregister_wnd_class(window_state.borrow().window_class);
|
||||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0);
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {
|
||||||
|
if msg == BV_WINDOW_MUST_CLOSE {
|
||||||
|
DestroyWindow(hwnd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,6 +351,7 @@ unsafe fn unregister_wnd_class(wnd_class: ATOM) {
|
||||||
struct WindowState {
|
struct WindowState {
|
||||||
window_class: ATOM,
|
window_class: ATOM,
|
||||||
window_info: WindowInfo,
|
window_info: WindowInfo,
|
||||||
|
_parent_handle: Option<ParentHandle>,
|
||||||
keyboard_state: KeyboardState,
|
keyboard_state: KeyboardState,
|
||||||
mouse_button_counter: usize,
|
mouse_button_counter: usize,
|
||||||
handler: Box<dyn WindowHandler>,
|
handler: Box<dyn WindowHandler>,
|
||||||
|
@ -295,7 +364,7 @@ pub struct Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
P: HasRawWindowHandle,
|
P: HasRawWindowHandle,
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
|
@ -307,21 +376,20 @@ impl Window {
|
||||||
h => panic!("unsupported parent handle {:?}", h),
|
h => panic!("unsupported parent handle {:?}", h),
|
||||||
};
|
};
|
||||||
|
|
||||||
Self::open(true, parent, options, build);
|
let (window_handle, _) = Self::open(true, parent, options, build);
|
||||||
|
|
||||||
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
let hwnd = Self::open(true, null_mut(), options, build);
|
let (window_handle, _) = Self::open(true, null_mut(), options, build);
|
||||||
|
|
||||||
RawWindowHandle::Windows(WindowsHandle {
|
window_handle
|
||||||
hwnd: hwnd as *mut std::ffi::c_void,
|
|
||||||
..WindowsHandle::empty()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
@ -330,7 +398,7 @@ impl Window {
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
let hwnd = Self::open(false, null_mut(), options, build);
|
let (_, hwnd) = Self::open(false, null_mut(), options, build);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut msg: MSG = std::mem::zeroed();
|
let mut msg: MSG = std::mem::zeroed();
|
||||||
|
@ -348,7 +416,9 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open<H, B>(parented: bool, parent: HWND, options: WindowOpenOptions, build: B) -> HWND
|
fn open<H, B>(
|
||||||
|
parented: bool, parent: HWND, options: WindowOpenOptions, build: B,
|
||||||
|
) -> (WindowHandle, HWND)
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
@ -410,9 +480,13 @@ impl Window {
|
||||||
|
|
||||||
let handler = Box::new(build(&mut crate::Window::new(&mut Window { hwnd })));
|
let handler = Box::new(build(&mut crate::Window::new(&mut Window { hwnd })));
|
||||||
|
|
||||||
|
let (parent_handle, window_handle) = ParentHandle::new(hwnd);
|
||||||
|
let parent_handle = if parented { Some(parent_handle) } else { None };
|
||||||
|
|
||||||
let mut window_state = Box::new(RefCell::new(WindowState {
|
let mut window_state = Box::new(RefCell::new(WindowState {
|
||||||
window_class,
|
window_class,
|
||||||
window_info,
|
window_info,
|
||||||
|
_parent_handle: parent_handle,
|
||||||
keyboard_state: KeyboardState::new(),
|
keyboard_state: KeyboardState::new(),
|
||||||
mouse_button_counter: 0,
|
mouse_button_counter: 0,
|
||||||
handler,
|
handler,
|
||||||
|
@ -473,7 +547,13 @@ impl Window {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
hwnd
|
(window_handle, hwnd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
PostMessageW(self.hwnd, BV_WINDOW_MUST_CLOSE, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,35 @@ use crate::win as platform;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use crate::x11 as platform;
|
use crate::x11 as platform;
|
||||||
|
|
||||||
|
pub struct WindowHandle {
|
||||||
|
window_handle: platform::WindowHandle,
|
||||||
|
// so that WindowHandle is !Send on all platforms
|
||||||
|
phantom: PhantomData<*mut ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowHandle {
|
||||||
|
fn new(window_handle: platform::WindowHandle) -> Self {
|
||||||
|
Self { window_handle, phantom: PhantomData::default() }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Close the window
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
self.window_handle.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the window is still open, and returns `false`
|
||||||
|
/// if the window was closed/dropped.
|
||||||
|
pub fn is_open(&self) -> bool {
|
||||||
|
self.window_handle.is_open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl HasRawWindowHandle for WindowHandle {
|
||||||
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
|
self.window_handle.raw_window_handle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub trait WindowHandler {
|
pub trait WindowHandler {
|
||||||
fn on_frame(&mut self, window: &mut Window);
|
fn on_frame(&mut self, window: &mut Window);
|
||||||
fn on_event(&mut self, window: &mut Window, event: Event) -> EventStatus;
|
fn on_event(&mut self, window: &mut Window, event: Event) -> EventStatus;
|
||||||
|
@ -28,23 +57,25 @@ impl<'a> Window<'a> {
|
||||||
Window { window, phantom: PhantomData }
|
Window { window, phantom: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
P: HasRawWindowHandle,
|
P: HasRawWindowHandle,
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut Window) -> H,
|
B: FnOnce(&mut Window) -> H,
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
platform::Window::open_parented::<P, H, B>(parent, options, build)
|
let window_handle = platform::Window::open_parented::<P, H, B>(parent, options, build);
|
||||||
|
WindowHandle::new(window_handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut Window) -> H,
|
B: FnOnce(&mut Window) -> H,
|
||||||
B: Send + 'static,
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
platform::Window::open_as_if_parented::<H, B>(options, build)
|
let window_handle = platform::Window::open_as_if_parented::<H, B>(options, build);
|
||||||
|
WindowHandle::new(window_handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
@ -55,6 +86,11 @@ impl<'a> Window<'a> {
|
||||||
{
|
{
|
||||||
platform::Window::open_blocking::<H, B>(options, build)
|
platform::Window::open_blocking::<H, B>(options, build)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Close the window
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
self.window.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl<'a> HasRawWindowHandle for Window<'a> {
|
unsafe impl<'a> HasRawWindowHandle for Window<'a> {
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::os::raw::{c_ulong, c_void};
|
use std::os::raw::{c_ulong, c_void};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::*;
|
use std::time::*;
|
||||||
|
|
||||||
|
@ -13,6 +16,74 @@ use crate::{
|
||||||
|
|
||||||
use super::keyboard::{convert_key_press_event, convert_key_release_event};
|
use super::keyboard::{convert_key_press_event, convert_key_release_event};
|
||||||
|
|
||||||
|
pub struct WindowHandle {
|
||||||
|
raw_window_handle: Option<RawWindowHandle>,
|
||||||
|
close_requested: Arc<AtomicBool>,
|
||||||
|
is_open: Arc<AtomicBool>,
|
||||||
|
|
||||||
|
// Ensure handle is !Send
|
||||||
|
_phantom: PhantomData<*mut ()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowHandle {
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
if let Some(_) = self.raw_window_handle.take() {
|
||||||
|
// FIXME: This will need to be changed from just setting an atomic to somehow
|
||||||
|
// synchronizing with the window being closed (using a synchronous channel, or
|
||||||
|
// by joining on the event loop thread).
|
||||||
|
|
||||||
|
self.close_requested.store(true, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_open(&self) -> bool {
|
||||||
|
self.is_open.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl HasRawWindowHandle for WindowHandle {
|
||||||
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
|
if let Some(raw_window_handle) = self.raw_window_handle {
|
||||||
|
if self.is_open.load(Ordering::Relaxed) {
|
||||||
|
return raw_window_handle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RawWindowHandle::Xlib(XlibHandle { ..raw_window_handle::unix::XlibHandle::empty() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ParentHandle {
|
||||||
|
close_requested: Arc<AtomicBool>,
|
||||||
|
is_open: Arc<AtomicBool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParentHandle {
|
||||||
|
pub fn new() -> (Self, WindowHandle) {
|
||||||
|
let close_requested = Arc::new(AtomicBool::new(false));
|
||||||
|
let is_open = Arc::new(AtomicBool::new(true));
|
||||||
|
|
||||||
|
let handle = WindowHandle {
|
||||||
|
raw_window_handle: None,
|
||||||
|
close_requested: Arc::clone(&close_requested),
|
||||||
|
is_open: Arc::clone(&is_open),
|
||||||
|
_phantom: PhantomData::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(Self { close_requested, is_open }, handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parent_did_drop(&self) -> bool {
|
||||||
|
self.close_requested.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ParentHandle {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.is_open.store(false, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
xcb_connection: XcbConnection,
|
xcb_connection: XcbConnection,
|
||||||
window_id: u32,
|
window_id: u32,
|
||||||
|
@ -21,8 +92,10 @@ pub struct Window {
|
||||||
|
|
||||||
frame_interval: Duration,
|
frame_interval: Duration,
|
||||||
event_loop_running: bool,
|
event_loop_running: bool,
|
||||||
|
close_requested: bool,
|
||||||
|
|
||||||
new_physical_size: Option<PhySize>,
|
new_physical_size: Option<PhySize>,
|
||||||
|
parent_handle: Option<ParentHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hack to allow sending a RawWindowHandle between threads. Do not make public
|
// Hack to allow sending a RawWindowHandle between threads. Do not make public
|
||||||
|
@ -33,7 +106,7 @@ unsafe impl Send for SendableRwh {}
|
||||||
type WindowOpenResult = Result<SendableRwh, ()>;
|
type WindowOpenResult = Result<SendableRwh, ()>;
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
P: HasRawWindowHandle,
|
P: HasRawWindowHandle,
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
|
@ -49,14 +122,19 @@ impl Window {
|
||||||
|
|
||||||
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
||||||
|
|
||||||
|
let (parent_handle, mut window_handle) = ParentHandle::new();
|
||||||
|
|
||||||
let thread = thread::spawn(move || {
|
let thread = thread::spawn(move || {
|
||||||
Self::window_thread(Some(parent_id), options, build, tx.clone());
|
Self::window_thread(Some(parent_id), options, build, tx.clone(), Some(parent_handle));
|
||||||
});
|
});
|
||||||
|
|
||||||
let _ = rx.recv().unwrap().unwrap();
|
let raw_window_handle = rx.recv().unwrap().unwrap();
|
||||||
|
window_handle.raw_window_handle = Some(raw_window_handle.0);
|
||||||
|
|
||||||
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
@ -64,11 +142,16 @@ impl Window {
|
||||||
{
|
{
|
||||||
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
||||||
|
|
||||||
|
let (parent_handle, mut window_handle) = ParentHandle::new();
|
||||||
|
|
||||||
let thread = thread::spawn(move || {
|
let thread = thread::spawn(move || {
|
||||||
Self::window_thread(None, options, build, tx.clone());
|
Self::window_thread(None, options, build, tx.clone(), Some(parent_handle));
|
||||||
});
|
});
|
||||||
|
|
||||||
rx.recv().unwrap().unwrap().0
|
let raw_window_handle = rx.recv().unwrap().unwrap();
|
||||||
|
window_handle.raw_window_handle = Some(raw_window_handle.0);
|
||||||
|
|
||||||
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
@ -80,7 +163,7 @@ impl Window {
|
||||||
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
||||||
|
|
||||||
let thread = thread::spawn(move || {
|
let thread = thread::spawn(move || {
|
||||||
Self::window_thread(None, options, build, tx.clone());
|
Self::window_thread(None, options, build, tx.clone(), None);
|
||||||
});
|
});
|
||||||
|
|
||||||
let _ = rx.recv().unwrap().unwrap();
|
let _ = rx.recv().unwrap().unwrap();
|
||||||
|
@ -90,7 +173,7 @@ impl Window {
|
||||||
|
|
||||||
fn window_thread<H, B>(
|
fn window_thread<H, B>(
|
||||||
parent: Option<u32>, options: WindowOpenOptions, build: B,
|
parent: Option<u32>, options: WindowOpenOptions, build: B,
|
||||||
tx: mpsc::SyncSender<WindowOpenResult>,
|
tx: mpsc::SyncSender<WindowOpenResult>, parent_handle: Option<ParentHandle>,
|
||||||
) where
|
) where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
@ -182,8 +265,10 @@ impl Window {
|
||||||
|
|
||||||
frame_interval: Duration::from_millis(15),
|
frame_interval: Duration::from_millis(15),
|
||||||
event_loop_running: false,
|
event_loop_running: false,
|
||||||
|
close_requested: false,
|
||||||
|
|
||||||
new_physical_size: None,
|
new_physical_size: None,
|
||||||
|
parent_handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut handler = build(&mut crate::Window::new(&mut window));
|
let mut handler = build(&mut crate::Window::new(&mut window));
|
||||||
|
@ -200,10 +285,6 @@ impl Window {
|
||||||
window.run_event_loop(&mut handler);
|
window.run_event_loop(&mut handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_info(&self) -> &WindowInfo {
|
|
||||||
&self.window_info
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) {
|
pub fn set_mouse_cursor(&mut self, mouse_cursor: MouseCursor) {
|
||||||
if self.mouse_cursor == mouse_cursor {
|
if self.mouse_cursor == mouse_cursor {
|
||||||
return;
|
return;
|
||||||
|
@ -224,6 +305,10 @@ impl Window {
|
||||||
self.mouse_cursor = mouse_cursor;
|
self.mouse_cursor = mouse_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn close(&mut self) {
|
||||||
|
self.close_requested = true;
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drain_xcb_events(&mut self, handler: &mut dyn WindowHandler) {
|
fn drain_xcb_events(&mut self, handler: &mut dyn WindowHandler) {
|
||||||
// the X server has a tendency to send spurious/extraneous configure notify events when a
|
// the X server has a tendency to send spurious/extraneous configure notify events when a
|
||||||
|
@ -291,9 +376,41 @@ impl Window {
|
||||||
self.drain_xcb_events(handler);
|
self.drain_xcb_events(handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the parents's handle was dropped (such as when the host
|
||||||
|
// requested the window to close)
|
||||||
|
//
|
||||||
|
// FIXME: This will need to be changed from just setting an atomic to somehow
|
||||||
|
// synchronizing with the window being closed (using a synchronous channel, or
|
||||||
|
// by joining on the event loop thread).
|
||||||
|
if let Some(parent_handle) = &self.parent_handle {
|
||||||
|
if parent_handle.parent_did_drop() {
|
||||||
|
self.handle_must_close(handler);
|
||||||
|
self.close_requested = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user has requested the window to close
|
||||||
|
if self.close_requested {
|
||||||
|
self.handle_must_close(handler);
|
||||||
|
self.close_requested = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_close_requested(&mut self, handler: &mut dyn WindowHandler) {
|
||||||
|
handler.on_event(&mut crate::Window::new(self), Event::Window(WindowEvent::WillClose));
|
||||||
|
|
||||||
|
// FIXME: handler should decide whether window stays open or not
|
||||||
|
self.event_loop_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_must_close(&mut self, handler: &mut dyn WindowHandler) {
|
||||||
|
handler.on_event(&mut crate::Window::new(self), Event::Window(WindowEvent::WillClose));
|
||||||
|
|
||||||
|
self.event_loop_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_xcb_event(&mut self, handler: &mut dyn WindowHandler, event: xcb::GenericEvent) {
|
fn handle_xcb_event(&mut self, handler: &mut dyn WindowHandler, event: xcb::GenericEvent) {
|
||||||
let event_type = event.response_type() & !0x80;
|
let event_type = event.response_type() & !0x80;
|
||||||
|
|
||||||
|
@ -332,13 +449,7 @@ impl Window {
|
||||||
self.xcb_connection.atoms.wm_delete_window.unwrap_or(xcb::NONE);
|
self.xcb_connection.atoms.wm_delete_window.unwrap_or(xcb::NONE);
|
||||||
|
|
||||||
if wm_delete_window == data32[0] {
|
if wm_delete_window == data32[0] {
|
||||||
handler.on_event(
|
self.handle_close_requested(handler);
|
||||||
&mut crate::Window::new(self),
|
|
||||||
Event::Window(WindowEvent::WillClose),
|
|
||||||
);
|
|
||||||
|
|
||||||
// FIXME: handler should decide whether window stays open or not
|
|
||||||
self.event_loop_running = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue