separate Window::open() into three functions (parented, as_if_parented, and blocking)
This commit is contained in:
parent
86bf222601
commit
36e4474c8a
|
@ -34,16 +34,10 @@ fn main() {
|
||||||
title: "baseview".into(),
|
title: "baseview".into(),
|
||||||
size: baseview::Size::new(512.0, 512.0),
|
size: baseview::Size::new(512.0, 512.0),
|
||||||
scale: WindowScalePolicy::SystemScaleFactor,
|
scale: WindowScalePolicy::SystemScaleFactor,
|
||||||
parent: baseview::Parent::None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (mut tx, rx) = RingBuffer::new(128).split();
|
let (mut tx, rx) = RingBuffer::new(128).split();
|
||||||
|
|
||||||
let opt_app_runner = Window::open(
|
|
||||||
window_open_options,
|
|
||||||
|_| OpenWindowExample { rx }
|
|
||||||
);
|
|
||||||
|
|
||||||
::std::thread::spawn(move || {
|
::std::thread::spawn(move || {
|
||||||
loop {
|
loop {
|
||||||
::std::thread::sleep(Duration::from_secs(5));
|
::std::thread::sleep(Duration::from_secs(5));
|
||||||
|
@ -54,5 +48,8 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
opt_app_runner.unwrap().app_run_blocking();
|
Window::open_blocking(
|
||||||
|
window_open_options,
|
||||||
|
|_| OpenWindowExample { rx }
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
16
src/lib.rs
16
src/lib.rs
|
@ -1,5 +1,3 @@
|
||||||
use raw_window_handle::RawWindowHandle;
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
mod win;
|
mod win;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
@ -19,17 +17,3 @@ pub use mouse_cursor::MouseCursor;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
pub use window_info::*;
|
pub use window_info::*;
|
||||||
pub use window_open_options::*;
|
pub use window_open_options::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Parent {
|
|
||||||
None,
|
|
||||||
AsIfParented,
|
|
||||||
WithParent(RawWindowHandle),
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl Send for Parent {}
|
|
||||||
|
|
||||||
pub trait WindowHandler {
|
|
||||||
fn on_frame(&mut self);
|
|
||||||
fn on_event(&mut self, window: &mut Window, event: Event);
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,27 +17,13 @@ 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::{
|
use crate::{
|
||||||
Event, Parent, WindowHandler, WindowOpenOptions,
|
Event, WindowHandler, WindowOpenOptions, WindowScalePolicy, WindowInfo,
|
||||||
WindowScalePolicy, WindowInfo
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::view::{create_view, BASEVIEW_STATE_IVAR};
|
use super::view::{create_view, BASEVIEW_STATE_IVAR};
|
||||||
use super::keyboard::KeyboardState;
|
use super::keyboard::KeyboardState;
|
||||||
|
|
||||||
|
|
||||||
pub struct AppRunner;
|
|
||||||
|
|
||||||
impl AppRunner {
|
|
||||||
pub fn app_run_blocking(self) {
|
|
||||||
unsafe {
|
|
||||||
// Get reference to already created shared NSApplication object
|
|
||||||
// and run the main loop
|
|
||||||
NSApp().run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
/// 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
|
||||||
|
@ -47,54 +33,73 @@ pub struct Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn open<H, B>(
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
||||||
options: WindowOpenOptions,
|
where
|
||||||
build: B
|
P: HasRawWindowHandle,
|
||||||
) -> Option<crate::AppRunner>
|
H: WindowHandler + 'static,
|
||||||
where H: WindowHandler + 'static,
|
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
B: Send + 'static
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
let _pool = unsafe { NSAutoreleasePool::new(nil) };
|
let _pool = unsafe { NSAutoreleasePool::new(nil) };
|
||||||
|
|
||||||
let mut window = unsafe {
|
let handle = if let RawWindowHandle::MacOS(handle) = parent.raw_window_handle() {
|
||||||
Window {
|
handle
|
||||||
ns_window: None,
|
} else {
|
||||||
ns_view: create_view(&options),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let window_handler = Box::new(build(&mut crate::Window::new(&mut window)));
|
|
||||||
|
|
||||||
let retain_count_after_build: usize = unsafe {
|
|
||||||
msg_send![window.ns_view, retainCount]
|
|
||||||
};
|
|
||||||
|
|
||||||
let opt_app_runner = match options.parent {
|
|
||||||
Parent::WithParent(RawWindowHandle::MacOS(handle)) => {
|
|
||||||
unsafe {
|
|
||||||
let () = msg_send![
|
|
||||||
handle.ns_view as *mut Object,
|
|
||||||
addSubview: window.ns_view
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
},
|
|
||||||
Parent::WithParent(_) => {
|
|
||||||
panic!("Not a macOS window");
|
panic!("Not a macOS window");
|
||||||
},
|
};
|
||||||
Parent::AsIfParented => {
|
|
||||||
None
|
let ns_view = unsafe { create_view(&options) };
|
||||||
},
|
|
||||||
Parent::None => {
|
let window = Window {
|
||||||
|
ns_window: None,
|
||||||
|
ns_view,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::init(window, build);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let _: id = msg_send![handle.ns_view as *mut Object, addSubview: ns_view];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
||||||
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
let _pool = unsafe { NSAutoreleasePool::new(nil) };
|
||||||
|
|
||||||
|
let ns_view = unsafe { create_view(&options) };
|
||||||
|
|
||||||
|
let window = Window {
|
||||||
|
ns_window: None,
|
||||||
|
ns_view,
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_window_handle = window.raw_window_handle();
|
||||||
|
|
||||||
|
Self::init(window, build);
|
||||||
|
|
||||||
|
raw_window_handle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
let _pool = unsafe { NSAutoreleasePool::new(nil) };
|
||||||
|
|
||||||
// It seems prudent to run NSApp() here before doing other
|
// It seems prudent to run NSApp() here before doing other
|
||||||
// work. It runs [NSApplication sharedApplication], which is
|
// work. It runs [NSApplication sharedApplication], which is
|
||||||
// what is run at the very start of the Xcode-generated main
|
// what is run at the very start of the Xcode-generated main
|
||||||
// function of a cocoa app according to:
|
// function of a cocoa app according to:
|
||||||
// https://developer.apple.com/documentation/appkit/nsapplication
|
// https://developer.apple.com/documentation/appkit/nsapplication
|
||||||
|
let app = unsafe { NSApp() };
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let app = NSApp();
|
|
||||||
app.setActivationPolicy_(
|
app.setActivationPolicy_(
|
||||||
NSApplicationActivationPolicyRegular
|
NSApplicationActivationPolicyRegular
|
||||||
);
|
);
|
||||||
|
@ -118,7 +123,7 @@ impl Window {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
unsafe {
|
let ns_window = unsafe {
|
||||||
let ns_window = NSWindow::alloc(nil)
|
let ns_window = NSWindow::alloc(nil)
|
||||||
.initWithContentRect_styleMask_backing_defer_(
|
.initWithContentRect_styleMask_backing_defer_(
|
||||||
rect,
|
rect,
|
||||||
|
@ -136,13 +141,39 @@ impl Window {
|
||||||
|
|
||||||
ns_window.makeKeyAndOrderFront_(nil);
|
ns_window.makeKeyAndOrderFront_(nil);
|
||||||
|
|
||||||
ns_window.setContentView_(window.ns_view);
|
ns_window
|
||||||
|
};
|
||||||
|
|
||||||
window.ns_window = Some(ns_window);
|
let ns_view = unsafe { create_view(&options) };
|
||||||
|
|
||||||
Some(crate::AppRunner(AppRunner))
|
let window = Window {
|
||||||
|
ns_window: Some(ns_window),
|
||||||
|
ns_view,
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::init(window, build);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ns_window.setContentView_(ns_view);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
unsafe {
|
||||||
|
app.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init<H, B>(
|
||||||
|
mut window: Window,
|
||||||
|
build: B
|
||||||
|
)
|
||||||
|
where H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
let window_handler = Box::new(build(&mut crate::Window::new(&mut window)));
|
||||||
|
|
||||||
|
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 {
|
||||||
|
@ -161,8 +192,6 @@ impl Window {
|
||||||
|
|
||||||
WindowState::setup_timer(window_state_ptr);
|
WindowState::setup_timer(window_state_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
opt_app_runner
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ use raw_window_handle::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, MouseButton, MouseEvent, Parent::WithParent, WindowEvent,
|
Event, MouseButton, MouseEvent, WindowEvent,
|
||||||
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy, PhyPoint,
|
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy, PhyPoint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -225,17 +225,49 @@ pub struct Window {
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AppRunner {
|
impl Window {
|
||||||
hwnd: HWND,
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
||||||
|
where
|
||||||
|
P: HasRawWindowHandle,
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
let parent = match parent.raw_window_handle() {
|
||||||
|
RawWindowHandle::Windows(h) => h.hwnd as HWND,
|
||||||
|
h => panic!("unsupported parent handle {:?}", h),
|
||||||
|
};
|
||||||
|
|
||||||
|
Self::open(true, parent, options, build);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppRunner {
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
||||||
pub fn app_run_blocking(self) {
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
let hwnd = Self::open(true, null_mut(), options, build);
|
||||||
|
|
||||||
|
RawWindowHandle::Windows(WindowsHandle {
|
||||||
|
hwnd: hwnd as *mut std::ffi::c_void,
|
||||||
|
..WindowsHandle::empty()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let status = GetMessageW(&mut msg, self.hwnd, 0, 0);
|
let status = GetMessageW(&mut msg, hwnd, 0, 0);
|
||||||
|
|
||||||
if status == -1 {
|
if status == -1 {
|
||||||
break;
|
break;
|
||||||
|
@ -246,16 +278,16 @@ impl AppRunner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Window {
|
fn open<H, B>(
|
||||||
pub fn open<H, B>(
|
parented: bool,
|
||||||
|
parent: HWND,
|
||||||
options: WindowOpenOptions,
|
options: WindowOpenOptions,
|
||||||
build: B
|
build: B
|
||||||
) -> Option<crate::AppRunner>
|
) -> HWND
|
||||||
where H: WindowHandler + 'static,
|
where H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
B: Send + 'static
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut title: Vec<u16> = OsStr::new(&options.title[..])
|
let mut title: Vec<u16> = OsStr::new(&options.title[..])
|
||||||
|
@ -266,14 +298,6 @@ impl Window {
|
||||||
let window_class = register_wnd_class();
|
let window_class = register_wnd_class();
|
||||||
// todo: manage error ^
|
// todo: manage error ^
|
||||||
|
|
||||||
let mut flags = WS_POPUPWINDOW
|
|
||||||
| WS_CAPTION
|
|
||||||
| WS_VISIBLE
|
|
||||||
| WS_SIZEBOX
|
|
||||||
| WS_MINIMIZEBOX
|
|
||||||
| WS_MAXIMIZEBOX
|
|
||||||
| WS_CLIPSIBLINGS;
|
|
||||||
|
|
||||||
let scaling = match options.scale {
|
let scaling = match options.scale {
|
||||||
WindowScalePolicy::SystemScaleFactor => get_scaling().unwrap_or(1.0),
|
WindowScalePolicy::SystemScaleFactor => get_scaling().unwrap_or(1.0),
|
||||||
WindowScalePolicy::ScaleFactor(scale) => scale
|
WindowScalePolicy::ScaleFactor(scale) => scale
|
||||||
|
@ -289,21 +313,22 @@ impl Window {
|
||||||
bottom: window_info.physical_size().height as i32,
|
bottom: window_info.physical_size().height as i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
// todo: add check flags https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L351
|
let flags = if parented {
|
||||||
let parent = match options.parent {
|
WS_CHILD | WS_VISIBLE
|
||||||
WithParent(RawWindowHandle::Windows(h)) => {
|
} else {
|
||||||
flags = WS_CHILD | WS_VISIBLE;
|
WS_POPUPWINDOW
|
||||||
h.hwnd
|
| WS_CAPTION
|
||||||
}
|
| WS_VISIBLE
|
||||||
|
| WS_SIZEBOX
|
||||||
WithParent(h) => panic!("unsupported parent handle {:?}", h),
|
| WS_MINIMIZEBOX
|
||||||
|
| WS_MAXIMIZEBOX
|
||||||
_ => {
|
| WS_CLIPSIBLINGS
|
||||||
AdjustWindowRectEx(&mut rect, flags, FALSE, 0);
|
|
||||||
null_mut()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if !parented {
|
||||||
|
AdjustWindowRectEx(&mut rect, flags, FALSE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
let hwnd = CreateWindowExW(
|
let hwnd = CreateWindowExW(
|
||||||
0,
|
0,
|
||||||
window_class as _,
|
window_class as _,
|
||||||
|
@ -333,11 +358,7 @@ impl Window {
|
||||||
SetWindowLongPtrW(hwnd, GWLP_USERDATA, Box::into_raw(window_state) as *const _ as _);
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, Box::into_raw(window_state) as *const _ as _);
|
||||||
SetTimer(hwnd, WIN_FRAME_TIMER, 15, None);
|
SetTimer(hwnd, WIN_FRAME_TIMER, 15, None);
|
||||||
|
|
||||||
if let crate::Parent::None = options.parent {
|
hwnd
|
||||||
Some(crate::AppRunner(AppRunner { hwnd }))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,19 @@ use std::marker::PhantomData;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
use crate::WindowHandler;
|
use crate::event::Event;
|
||||||
use crate::window_open_options::WindowOpenOptions;
|
use crate::window_open_options::WindowOpenOptions;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
use crate::macos as platform;
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
use crate::win as platform;
|
use crate::win as platform;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use crate::x11 as platform;
|
use crate::x11 as platform;
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
use crate::macos as platform;
|
|
||||||
|
|
||||||
pub struct AppRunner(pub(crate) platform::AppRunner);
|
pub trait WindowHandler {
|
||||||
|
fn on_frame(&mut self);
|
||||||
impl AppRunner {
|
fn on_event(&mut self, window: &mut Window, event: Event);
|
||||||
pub fn app_run_blocking(self){
|
|
||||||
self.0.app_run_blocking();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window<'a> {
|
pub struct Window<'a> {
|
||||||
|
@ -34,15 +31,32 @@ impl<'a> Window<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open<H, B>(
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
||||||
options: WindowOpenOptions,
|
where
|
||||||
build: B
|
P: HasRawWindowHandle,
|
||||||
) -> Option<AppRunner>
|
H: WindowHandler + 'static,
|
||||||
where H: WindowHandler + 'static,
|
|
||||||
B: FnOnce(&mut Window) -> H,
|
B: FnOnce(&mut Window) -> H,
|
||||||
B: Send + 'static
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
platform::Window::open::<H, B>(options, build)
|
platform::Window::open_parented::<P, H, B>(parent, options, build)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
||||||
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
platform::Window::open_as_if_parented::<H, B>(options, build)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
platform::Window::open_blocking::<H, B>(options, build)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{Parent, Size};
|
use crate::Size;
|
||||||
|
|
||||||
/// The dpi scaling policy of the window
|
/// The dpi scaling policy of the window
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -10,7 +10,6 @@ pub enum WindowScalePolicy {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The options for opening a new window
|
/// The options for opening a new window
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct WindowOpenOptions {
|
pub struct WindowOpenOptions {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
|
|
||||||
|
@ -22,6 +21,4 @@ pub struct WindowOpenOptions {
|
||||||
|
|
||||||
/// The dpi scaling policy
|
/// The dpi scaling policy
|
||||||
pub scale: WindowScalePolicy,
|
pub scale: WindowScalePolicy,
|
||||||
|
|
||||||
pub parent: Parent,
|
|
||||||
}
|
}
|
|
@ -11,7 +11,7 @@ use raw_window_handle::{
|
||||||
|
|
||||||
use super::XcbConnection;
|
use super::XcbConnection;
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, MouseButton, MouseCursor, MouseEvent, Parent, ScrollDelta,
|
Event, MouseButton, MouseCursor, MouseEvent, ScrollDelta,
|
||||||
WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
|
WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
|
||||||
WindowScalePolicy, PhyPoint, PhySize,
|
WindowScalePolicy, PhyPoint, PhySize,
|
||||||
};
|
};
|
||||||
|
@ -30,57 +30,77 @@ pub struct Window {
|
||||||
new_physical_size: Option<PhySize>,
|
new_physical_size: Option<PhySize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WindowHandle;
|
// Hack to allow sending a RawWindowHandle between threads. Do not make public
|
||||||
|
struct SendableRwh(RawWindowHandle);
|
||||||
|
|
||||||
|
unsafe impl Send for SendableRwh {}
|
||||||
|
|
||||||
pub struct AppRunner {
|
type WindowOpenResult = Result<SendableRwh, ()>;
|
||||||
thread: std::thread::JoinHandle<()>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AppRunner {
|
|
||||||
pub fn app_run_blocking(self) {
|
|
||||||
let _ = self.thread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type WindowOpenResult = Result<(), ()>;
|
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn open<H, B>(
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B)
|
||||||
options: WindowOpenOptions,
|
where
|
||||||
build: B
|
P: HasRawWindowHandle,
|
||||||
) -> Option<crate::AppRunner>
|
H: WindowHandler + 'static,
|
||||||
where H: WindowHandler,
|
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
B: Send + 'static
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
let is_not_parented = matches!(options.parent, Parent::None);
|
// Convert parent into something that X understands
|
||||||
|
let parent_id = match parent.raw_window_handle() {
|
||||||
|
RawWindowHandle::Xlib(h) => h.window as u32,
|
||||||
|
RawWindowHandle::Xcb(h) => h.window,
|
||||||
|
h => panic!("unsupported parent handle type {:?}", h),
|
||||||
|
};
|
||||||
|
|
||||||
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 || {
|
||||||
if let Err(e) = Self::window_thread::<H, B>(options, build, tx.clone()) {
|
Self::window_thread(Some(parent_id), options, build, tx.clone());
|
||||||
let _ = tx.send(Err(e));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// FIXME: placeholder types for returning errors in the future
|
let _ = rx.recv().unwrap().unwrap();
|
||||||
let _ = rx.recv();
|
|
||||||
|
|
||||||
if is_not_parented {
|
|
||||||
Some(crate::AppRunner(AppRunner { thread }))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn open_as_if_parented<H, B>(options: WindowOpenOptions, build: B) -> RawWindowHandle
|
||||||
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
||||||
|
|
||||||
|
let thread = thread::spawn(move || {
|
||||||
|
Self::window_thread(None, options, build, tx.clone());
|
||||||
|
});
|
||||||
|
|
||||||
|
rx.recv().unwrap().unwrap().0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
|
where
|
||||||
|
H: WindowHandler + 'static,
|
||||||
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
|
B: Send + 'static,
|
||||||
|
{
|
||||||
|
let (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
||||||
|
|
||||||
|
let thread = thread::spawn(move || {
|
||||||
|
Self::window_thread(None, options, build, tx.clone());
|
||||||
|
});
|
||||||
|
|
||||||
|
let _ = rx.recv().unwrap().unwrap();
|
||||||
|
|
||||||
|
thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_thread<H, B>(
|
fn window_thread<H, B>(
|
||||||
|
parent: Option<u32>,
|
||||||
options: WindowOpenOptions, build: B,
|
options: WindowOpenOptions, build: B,
|
||||||
tx: mpsc::SyncSender<WindowOpenResult>,
|
tx: mpsc::SyncSender<WindowOpenResult>,
|
||||||
) -> WindowOpenResult
|
)
|
||||||
where H: WindowHandler,
|
where H: WindowHandler + 'static,
|
||||||
B: FnOnce(&mut crate::Window) -> H,
|
B: FnOnce(&mut crate::Window) -> H,
|
||||||
B: Send + 'static
|
B: Send + 'static,
|
||||||
{
|
{
|
||||||
// Connect to the X server
|
// Connect to the X server
|
||||||
// FIXME: baseview error type instead of unwrap()
|
// FIXME: baseview error type instead of unwrap()
|
||||||
|
@ -95,15 +115,7 @@ impl Window {
|
||||||
|
|
||||||
let foreground = xcb_connection.conn.generate_id();
|
let foreground = xcb_connection.conn.generate_id();
|
||||||
|
|
||||||
// Convert parent into something that X understands
|
let parent_id = parent.unwrap_or_else(|| screen.root());
|
||||||
let parent_id = match options.parent {
|
|
||||||
Parent::WithParent(RawWindowHandle::Xlib(h)) => h.window as u32,
|
|
||||||
Parent::WithParent(RawWindowHandle::Xcb(h)) => h.window,
|
|
||||||
Parent::WithParent(h) =>
|
|
||||||
panic!("unsupported parent handle type {:?}", h),
|
|
||||||
|
|
||||||
Parent::None | Parent::AsIfParented => screen.root(),
|
|
||||||
};
|
|
||||||
|
|
||||||
xcb::create_gc(
|
xcb::create_gc(
|
||||||
&xcb_connection.conn,
|
&xcb_connection.conn,
|
||||||
|
@ -188,10 +200,9 @@ impl Window {
|
||||||
|
|
||||||
let mut handler = build(&mut crate::Window::new(&mut window));
|
let mut handler = build(&mut crate::Window::new(&mut window));
|
||||||
|
|
||||||
let _ = tx.send(Ok(()));
|
let _ = tx.send(Ok(SendableRwh(window.raw_window_handle())));
|
||||||
|
|
||||||
window.run_event_loop(&mut handler);
|
window.run_event_loop(&mut handler);
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_info(&self) -> &WindowInfo {
|
pub fn window_info(&self) -> &WindowInfo {
|
||||||
|
|
Loading…
Reference in a new issue