1
0
Fork 0

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:
Billy Messenger 2021-11-16 00:00:22 -06:00 committed by GitHub
parent 2a894c6bc9
commit f6e99e9aa6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 423 additions and 65 deletions

View file

@ -33,4 +33,4 @@ objc = "0.2.7"
uuid = { version = "0.8", features = ["v4"] }
[dev-dependencies]
rtrb = "0.1.1"
rtrb = "0.2"

View file

@ -38,7 +38,7 @@ fn main() {
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::sleep(Duration::from_secs(5));

View file

@ -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;
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);

View file

@ -1,4 +1,7 @@
use std::ffi::c_void;
use std::marker::PhantomData;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use cocoa::appkit::{
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 crate::{Event, EventStatus, WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy};
use crate::{
Event, EventStatus, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
WindowScalePolicy,
};
use super::keyboard::KeyboardState;
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 {
/// 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
/// parentless mode
ns_window: Option<id>,
/// Our subclassed NSView
ns_view: id,
close_requested: bool,
}
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
P: HasRawWindowHandle,
H: WindowHandler + 'static,
@ -46,9 +122,9 @@ impl Window {
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 {
let _: id = msg_send![handle.ns_view as *mut Object, addSubview: ns_view];
@ -56,9 +132,11 @@ impl Window {
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
H: WindowHandler + 'static,
B: FnOnce(&mut crate::Window) -> H,
@ -68,17 +146,15 @@ impl Window {
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();
Self::init(window, build);
let window_handle = Self::init(true, window, build);
unsafe {
let () = msg_send![pool, drain];
}
raw_window_handle
window_handle
}
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
@ -118,7 +194,9 @@ impl Window {
let ns_window = unsafe {
let ns_window = NSWindow::alloc(nil).initWithContentRect_styleMask_backing_defer_(
rect,
NSWindowStyleMask::NSTitledWindowMask,
NSWindowStyleMask::NSTitledWindowMask
| NSWindowStyleMask::NSClosableWindowMask
| NSWindowStyleMask::NSMiniaturizableWindowMask,
NSBackingStoreBuffered,
NO,
);
@ -134,21 +212,26 @@ impl Window {
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 {
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];
app.run();
}
}
fn init<H, B>(mut window: Window, build: B)
fn init<H, B>(parented: bool, mut window: Window, build: B) -> WindowHandle
where
H: WindowHandler + 'static,
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 (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 window_state_ptr = Box::into_raw(Box::new(WindowState {
@ -164,6 +250,7 @@ impl Window {
keyboard_state: KeyboardState::new(),
frame_timer: None,
retain_count_after_build,
_parent_handle: parent_handle,
}));
unsafe {
@ -172,6 +259,12 @@ impl Window {
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>,
keyboard_state: KeyboardState,
frame_timer: Option<CFRunLoopTimer>,
_parent_handle: Option<ParentHandle>,
pub retain_count_after_build: usize,
}
@ -201,6 +295,36 @@ impl WindowState {
pub(super) fn trigger_frame(&mut self) {
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> {
@ -235,10 +359,17 @@ impl WindowState {
}
/// 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() {
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);
}
}
}

View file

@ -4,25 +4,29 @@ use winapi::shared::windef::{HWND, RECT};
use winapi::um::combaseapi::CoCreateGuid;
use winapi::um::winuser::{
AdjustWindowRectEx, CreateWindowExW, DefWindowProcW, DestroyWindow, DispatchMessageW,
GetCapture, GetDpiForWindow, GetMessageW, GetWindowLongPtrW, IsWindow, LoadCursorW,
PostMessageW, RegisterClassW, ReleaseCapture, SetCapture, SetProcessDpiAwarenessContext,
SetTimer, SetWindowLongPtrW, SetWindowPos, TranslateMessage, UnregisterClassW, CS_OWNDC,
GET_XBUTTON_WPARAM, GWLP_USERDATA, IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, WHEEL_DELTA,
WM_CHAR, WM_CLOSE, WM_CREATE, WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP,
WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL,
WM_NCDESTROY, WM_RBUTTONDOWN, WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN,
WM_SYSKEYUP, WM_TIMER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD,
WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
XBUTTON1, XBUTTON2,
GetDpiForWindow, GetMessageW, GetWindowLongPtrW, LoadCursorW, PostMessageW, RegisterClassW,
ReleaseCapture, SetCapture, SetProcessDpiAwarenessContext, SetTimer, SetWindowLongPtrW,
SetWindowPos, TranslateMessage, UnregisterClassW, CS_OWNDC, GET_XBUTTON_WPARAM, GWLP_USERDATA,
IDC_ARROW, MSG, SWP_NOMOVE, SWP_NOZORDER, WHEEL_DELTA, WM_CHAR, WM_CLOSE, WM_CREATE,
WM_DPICHANGED, WM_INPUTLANGCHANGE, WM_KEYDOWN, WM_KEYUP, WM_LBUTTONDOWN, WM_LBUTTONUP,
WM_MBUTTONDOWN, WM_MBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL, WM_NCDESTROY, WM_RBUTTONDOWN,
WM_RBUTTONUP, WM_SHOWWINDOW, WM_SIZE, WM_SYSCHAR, WM_SYSKEYDOWN, WM_SYSKEYUP, WM_TIMER,
WM_USER, WM_XBUTTONDOWN, WM_XBUTTONUP, WNDCLASSW, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS,
WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE, XBUTTON1, XBUTTON2,
};
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::ptr::null_mut;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use raw_window_handle::{windows::WindowsHandle, HasRawWindowHandle, RawWindowHandle};
const BV_WINDOW_MUST_CLOSE: UINT = WM_USER + 1;
use crate::{
Event, MouseButton, MouseEvent, PhyPoint, PhySize, ScrollDelta, WindowEvent, WindowHandler,
WindowInfo, WindowOpenOptions, WindowScalePolicy,
@ -51,6 +55,65 @@ unsafe fn generate_guid() -> String {
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(
hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM,
) -> LRESULT {
@ -247,7 +310,12 @@ unsafe extern "system" fn wnd_proc(
unregister_wnd_class(window_state.borrow().window_class);
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 {
window_class: ATOM,
window_info: WindowInfo,
_parent_handle: Option<ParentHandle>,
keyboard_state: KeyboardState,
mouse_button_counter: usize,
handler: Box<dyn WindowHandler>,
@ -295,7 +364,7 @@ pub struct 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
P: HasRawWindowHandle,
H: WindowHandler + 'static,
@ -307,21 +376,20 @@ impl Window {
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
H: WindowHandler + 'static,
B: FnOnce(&mut crate::Window) -> H,
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 {
hwnd: hwnd as *mut std::ffi::c_void,
..WindowsHandle::empty()
})
window_handle
}
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
@ -330,7 +398,7 @@ impl Window {
B: FnOnce(&mut crate::Window) -> H,
B: Send + 'static,
{
let hwnd = Self::open(false, null_mut(), options, build);
let (_, hwnd) = Self::open(false, null_mut(), options, build);
unsafe {
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
H: WindowHandler + 'static,
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 (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 {
window_class,
window_info,
_parent_handle: parent_handle,
keyboard_state: KeyboardState::new(),
mouse_button_counter: 0,
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);
}
}
}

View file

@ -12,6 +12,35 @@ use crate::win as platform;
#[cfg(target_os = "linux")]
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 {
fn on_frame(&mut self, window: &mut Window);
fn on_event(&mut self, window: &mut Window, event: Event) -> EventStatus;
@ -28,23 +57,25 @@ impl<'a> Window<'a> {
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
P: HasRawWindowHandle,
H: WindowHandler + 'static,
B: FnOnce(&mut Window) -> H,
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
H: WindowHandler + 'static,
B: FnOnce(&mut Window) -> H,
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)
@ -55,6 +86,11 @@ impl<'a> Window<'a> {
{
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> {

View file

@ -1,5 +1,8 @@
use std::marker::PhantomData;
use std::os::raw::{c_ulong, c_void};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc;
use std::sync::Arc;
use std::thread;
use std::time::*;
@ -13,6 +16,74 @@ use crate::{
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 {
xcb_connection: XcbConnection,
window_id: u32,
@ -21,8 +92,10 @@ pub struct Window {
frame_interval: Duration,
event_loop_running: bool,
close_requested: bool,
new_physical_size: Option<PhySize>,
parent_handle: Option<ParentHandle>,
}
// 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, ()>;
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
P: HasRawWindowHandle,
H: WindowHandler + 'static,
@ -49,14 +122,19 @@ impl Window {
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
let (parent_handle, mut window_handle) = ParentHandle::new();
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
H: WindowHandler + 'static,
B: FnOnce(&mut crate::Window) -> H,
@ -64,11 +142,16 @@ impl Window {
{
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
let (parent_handle, mut window_handle) = ParentHandle::new();
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)
@ -80,7 +163,7 @@ impl Window {
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
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();
@ -90,7 +173,7 @@ impl Window {
fn window_thread<H, B>(
parent: Option<u32>, options: WindowOpenOptions, build: B,
tx: mpsc::SyncSender<WindowOpenResult>,
tx: mpsc::SyncSender<WindowOpenResult>, parent_handle: Option<ParentHandle>,
) where
H: WindowHandler + 'static,
B: FnOnce(&mut crate::Window) -> H,
@ -182,8 +265,10 @@ impl Window {
frame_interval: Duration::from_millis(15),
event_loop_running: false,
close_requested: false,
new_physical_size: None,
parent_handle,
};
let mut handler = build(&mut crate::Window::new(&mut window));
@ -200,10 +285,6 @@ impl Window {
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) {
if self.mouse_cursor == mouse_cursor {
return;
@ -224,6 +305,10 @@ impl Window {
self.mouse_cursor = mouse_cursor;
}
pub fn close(&mut self) {
self.close_requested = true;
}
#[inline]
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
@ -291,9 +376,41 @@ impl Window {
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) {
let event_type = event.response_type() & !0x80;
@ -332,13 +449,7 @@ impl Window {
self.xcb_connection.atoms.wm_delete_window.unwrap_or(xcb::NONE);
if wm_delete_window == data32[0] {
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;
self.handle_close_requested(handler);
}
}