Merge branch 'master' into feature/windows-cursor-enter-leave
This commit is contained in:
commit
d8cedc8a77
|
@ -1,3 +1,3 @@
|
||||||
fn_args_layout = "Compressed"
|
fn_params_layout = "Compressed"
|
||||||
use_small_heuristics = "Max"
|
use_small_heuristics = "Max"
|
||||||
use_field_init_shorthand = true
|
use_field_init_shorthand = true
|
||||||
|
|
|
@ -20,7 +20,7 @@ opengl = ["uuid", "x11/glx"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
keyboard-types = { version = "0.6.1", default-features = false }
|
keyboard-types = { version = "0.6.1", default-features = false }
|
||||||
raw-window-handle = "0.4.2"
|
raw-window-handle = "0.5"
|
||||||
|
|
||||||
[target.'cfg(target_os="linux")'.dependencies]
|
[target.'cfg(target_os="linux")'.dependencies]
|
||||||
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
|
xcb = { version = "0.9", features = ["thread", "xlib_xcb", "dri2"] }
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl WindowHandler for OpenWindowExample {
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
match e {
|
match e {
|
||||||
MouseEvent::ButtonPressed { button, modifiers } => {
|
MouseEvent::ButtonPressed { .. } => {
|
||||||
copy_to_clipboard(&"This is a test!")
|
copy_to_clipboard(&"This is a test!")
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::RawWindowHandle;
|
||||||
|
|
||||||
use cocoa::appkit::{
|
use cocoa::appkit::{
|
||||||
NSOpenGLContext, NSOpenGLContextParameter, NSOpenGLPFAAccelerated, NSOpenGLPFAAlphaSize,
|
NSOpenGLContext, NSOpenGLContextParameter, NSOpenGLPFAAccelerated, NSOpenGLPFAAlphaSize,
|
||||||
|
@ -28,10 +28,8 @@ pub struct GlContext {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlContext {
|
impl GlContext {
|
||||||
pub unsafe fn create(
|
pub unsafe fn create(parent: &RawWindowHandle, config: GlConfig) -> Result<GlContext, GlError> {
|
||||||
parent: &impl HasRawWindowHandle, config: GlConfig,
|
let handle = if let RawWindowHandle::AppKit(handle) = parent {
|
||||||
) -> Result<GlContext, GlError> {
|
|
||||||
let handle = if let RawWindowHandle::AppKit(handle) = parent.raw_window_handle() {
|
|
||||||
handle
|
handle
|
||||||
} else {
|
} else {
|
||||||
return Err(GlError::InvalidWindowHandle);
|
return Err(GlError::InvalidWindowHandle);
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::marker::PhantomData;
|
||||||
|
|
||||||
// On X11 creating the context is a two step process
|
// On X11 creating the context is a two step process
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
use raw_window_handle::HasRawWindowHandle;
|
use raw_window_handle::RawWindowHandle;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
mod win;
|
mod win;
|
||||||
|
@ -77,7 +77,7 @@ pub struct GlContext {
|
||||||
impl GlContext {
|
impl GlContext {
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
pub(crate) unsafe fn create(
|
pub(crate) unsafe fn create(
|
||||||
parent: &impl HasRawWindowHandle, config: GlConfig,
|
parent: &RawWindowHandle, config: GlConfig,
|
||||||
) -> Result<GlContext, GlError> {
|
) -> Result<GlContext, GlError> {
|
||||||
platform::GlContext::create(parent, config)
|
platform::GlContext::create(parent, config)
|
||||||
.map(|context| GlContext { context, phantom: PhantomData })
|
.map(|context| GlContext { context, phantom: PhantomData })
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::ffi::{c_void, CString, OsStr};
|
use std::ffi::{c_void, CString, OsStr};
|
||||||
use std::os::windows::ffi::OsStrExt;
|
use std::os::windows::ffi::OsStrExt;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::RawWindowHandle;
|
||||||
|
|
||||||
use winapi::shared::minwindef::{HINSTANCE, HMODULE};
|
use winapi::shared::minwindef::{HINSTANCE, HMODULE};
|
||||||
use winapi::shared::ntdef::WCHAR;
|
use winapi::shared::ntdef::WCHAR;
|
||||||
|
@ -77,10 +77,8 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GlContext {
|
impl GlContext {
|
||||||
pub unsafe fn create(
|
pub unsafe fn create(parent: &RawWindowHandle, config: GlConfig) -> Result<GlContext, GlError> {
|
||||||
parent: &impl HasRawWindowHandle, config: GlConfig,
|
let handle = if let RawWindowHandle::Win32(handle) = parent {
|
||||||
) -> Result<GlContext, GlError> {
|
|
||||||
let handle = if let RawWindowHandle::Win32(handle) = parent.raw_window_handle() {
|
|
||||||
handle
|
handle
|
||||||
} else {
|
} else {
|
||||||
return Err(GlError::InvalidWindowHandle);
|
return Err(GlError::InvalidWindowHandle);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
use std::ffi::{c_void, CString};
|
use std::ffi::{c_void, CString};
|
||||||
use std::os::raw::{c_int, c_ulong};
|
use std::os::raw::{c_int, c_ulong};
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
|
||||||
|
|
||||||
use x11::glx;
|
use x11::glx;
|
||||||
use x11::xlib;
|
use x11::xlib;
|
||||||
|
|
||||||
|
@ -80,20 +78,12 @@ impl GlContext {
|
||||||
///
|
///
|
||||||
/// Use [Self::get_fb_config_and_visual] to create both of these things.
|
/// Use [Self::get_fb_config_and_visual] to create both of these things.
|
||||||
pub unsafe fn create(
|
pub unsafe fn create(
|
||||||
parent: &impl HasRawWindowHandle, config: FbConfig,
|
window: c_ulong, display: *mut xlib::_XDisplay, config: FbConfig,
|
||||||
) -> Result<GlContext, GlError> {
|
) -> Result<GlContext, GlError> {
|
||||||
let handle = if let RawWindowHandle::Xlib(handle) = parent.raw_window_handle() {
|
if display.is_null() {
|
||||||
handle
|
|
||||||
} else {
|
|
||||||
return Err(GlError::InvalidWindowHandle);
|
|
||||||
};
|
|
||||||
|
|
||||||
if handle.display.is_null() {
|
|
||||||
return Err(GlError::InvalidWindowHandle);
|
return Err(GlError::InvalidWindowHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
let display = handle.display as *mut xlib::_XDisplay;
|
|
||||||
|
|
||||||
errors::XErrorHandler::handle(display, |error_handler| {
|
errors::XErrorHandler::handle(display, |error_handler| {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
let glXCreateContextAttribsARB: GlXCreateContextAttribsARB = {
|
let glXCreateContextAttribsARB: GlXCreateContextAttribsARB = {
|
||||||
|
@ -144,13 +134,13 @@ impl GlContext {
|
||||||
return Err(GlError::CreationFailed(CreationFailedError::ContextCreationFailed));
|
return Err(GlError::CreationFailed(CreationFailedError::ContextCreationFailed));
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = glx::glXMakeCurrent(display, handle.window, context);
|
let res = glx::glXMakeCurrent(display, window, context);
|
||||||
error_handler.check()?;
|
error_handler.check()?;
|
||||||
if res == 0 {
|
if res == 0 {
|
||||||
return Err(GlError::CreationFailed(CreationFailedError::MakeCurrentFailed));
|
return Err(GlError::CreationFailed(CreationFailedError::MakeCurrentFailed));
|
||||||
}
|
}
|
||||||
|
|
||||||
glXSwapIntervalEXT(display, handle.window, config.gl_config.vsync as i32);
|
glXSwapIntervalEXT(display, window, config.gl_config.vsync as i32);
|
||||||
error_handler.check()?;
|
error_handler.check()?;
|
||||||
|
|
||||||
if glx::glXMakeCurrent(display, 0, std::ptr::null_mut()) == 0 {
|
if glx::glXMakeCurrent(display, 0, std::ptr::null_mut()) == 0 {
|
||||||
|
@ -158,7 +148,7 @@ impl GlContext {
|
||||||
return Err(GlError::CreationFailed(CreationFailedError::MakeCurrentFailed));
|
return Err(GlError::CreationFailed(CreationFailedError::MakeCurrentFailed));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(GlContext { window: handle.window, display, context })
|
Ok(GlContext { window, display, context })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
|
|
||||||
//! Conversion of platform keyboard event into cross-platform event.
|
//! Conversion of platform keyboard event into cross-platform event.
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
|
||||||
use cocoa::appkit::{NSEvent, NSEventModifierFlags, NSEventType};
|
use cocoa::appkit::{NSEvent, NSEventModifierFlags, NSEventType};
|
||||||
use cocoa::base::id;
|
use cocoa::base::id;
|
||||||
use cocoa::foundation::NSString;
|
use cocoa::foundation::NSString;
|
||||||
|
@ -44,7 +46,7 @@ pub(crate) fn from_nsstring(s: id) -> String {
|
||||||
/// Most of the logic in this module is adapted from Mozilla, and in particular
|
/// Most of the logic in this module is adapted from Mozilla, and in particular
|
||||||
/// TextInputHandler.mm.
|
/// TextInputHandler.mm.
|
||||||
pub(crate) struct KeyboardState {
|
pub(crate) struct KeyboardState {
|
||||||
last_mods: NSEventModifierFlags,
|
last_mods: Cell<NSEventModifierFlags>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a macOS platform key code (keyCode field of NSEvent).
|
/// Convert a macOS platform key code (keyCode field of NSEvent).
|
||||||
|
@ -269,11 +271,15 @@ fn is_modifier_code(code: Code) -> bool {
|
||||||
|
|
||||||
impl KeyboardState {
|
impl KeyboardState {
|
||||||
pub(crate) fn new() -> KeyboardState {
|
pub(crate) fn new() -> KeyboardState {
|
||||||
let last_mods = NSEventModifierFlags::empty();
|
let last_mods = Cell::new(NSEventModifierFlags::empty());
|
||||||
KeyboardState { last_mods }
|
KeyboardState { last_mods }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process_native_event(&mut self, event: id) -> Option<KeyboardEvent> {
|
pub(crate) fn last_mods(&self) -> NSEventModifierFlags {
|
||||||
|
self.last_mods.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn process_native_event(&self, event: id) -> Option<KeyboardEvent> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let event_type = event.eventType();
|
let event_type = event.eventType();
|
||||||
let key_code = event.keyCode();
|
let key_code = event.keyCode();
|
||||||
|
@ -288,8 +294,8 @@ impl KeyboardState {
|
||||||
// We use `bits` here because we want to distinguish the
|
// We use `bits` here because we want to distinguish the
|
||||||
// device dependent bits (when both left and right keys
|
// device dependent bits (when both left and right keys
|
||||||
// may be pressed, for example).
|
// may be pressed, for example).
|
||||||
let any_down = raw_mods.bits() & !self.last_mods.bits();
|
let any_down = raw_mods.bits() & !self.last_mods.get().bits();
|
||||||
self.last_mods = raw_mods;
|
self.last_mods.set(raw_mods);
|
||||||
if is_modifier_code(code) {
|
if is_modifier_code(code) {
|
||||||
if any_down == 0 {
|
if any_down == 0 {
|
||||||
KeyState::Up
|
KeyState::Up
|
||||||
|
|
|
@ -3,3 +3,15 @@ mod view;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
mod consts {
|
||||||
|
use cocoa::foundation::NSUInteger;
|
||||||
|
|
||||||
|
pub const NSDragOperationNone: NSUInteger = 0;
|
||||||
|
pub const NSDragOperationCopy: NSUInteger = 1;
|
||||||
|
pub const NSDragOperationLink: NSUInteger = 2;
|
||||||
|
pub const NSDragOperationGeneric: NSUInteger = 4;
|
||||||
|
pub const NSDragOperationMove: NSUInteger = 16;
|
||||||
|
}
|
||||||
|
use consts::*;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
|
|
||||||
use cocoa::appkit::{NSEvent, NSView, NSWindow};
|
use cocoa::appkit::{NSEvent, NSFilenamesPboardType, NSView, NSWindow};
|
||||||
use cocoa::base::{id, nil, BOOL, NO, YES};
|
use cocoa::base::{id, nil, BOOL, NO, YES};
|
||||||
use cocoa::foundation::{NSArray, NSPoint, NSRect, NSSize};
|
use cocoa::foundation::{NSArray, NSPoint, NSRect, NSSize, NSUInteger};
|
||||||
|
|
||||||
use objc::{
|
use objc::{
|
||||||
class,
|
class,
|
||||||
|
@ -15,12 +15,16 @@ use uuid::Uuid;
|
||||||
|
|
||||||
use crate::MouseEvent::{ButtonPressed, ButtonReleased};
|
use crate::MouseEvent::{ButtonPressed, ButtonReleased};
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, EventStatus, MouseButton, MouseEvent, Point, ScrollDelta, Size, WindowEvent, WindowInfo,
|
DropData, DropEffect, Event, EventStatus, MouseButton, MouseEvent, Point, ScrollDelta, Size,
|
||||||
WindowOpenOptions,
|
WindowEvent, WindowInfo, WindowOpenOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::keyboard::make_modifiers;
|
use super::keyboard::{from_nsstring, make_modifiers};
|
||||||
use super::window::WindowState;
|
use super::window::WindowState;
|
||||||
|
use super::{
|
||||||
|
NSDragOperationCopy, NSDragOperationGeneric, NSDragOperationLink, NSDragOperationMove,
|
||||||
|
NSDragOperationNone,
|
||||||
|
};
|
||||||
|
|
||||||
/// Name of the field used to store the `WindowState` pointer.
|
/// Name of the field used to store the `WindowState` pointer.
|
||||||
pub(super) const BASEVIEW_STATE_IVAR: &str = "baseview_state";
|
pub(super) const BASEVIEW_STATE_IVAR: &str = "baseview_state";
|
||||||
|
@ -29,9 +33,7 @@ macro_rules! add_simple_mouse_class_method {
|
||||||
($class:ident, $sel:ident, $event:expr) => {
|
($class:ident, $sel:ident, $event:expr) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
extern "C" fn $sel(this: &Object, _: Sel, _: id){
|
extern "C" fn $sel(this: &Object, _: Sel, _: id){
|
||||||
let state: &mut WindowState = unsafe {
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
WindowState::from_field(this)
|
|
||||||
};
|
|
||||||
|
|
||||||
state.trigger_event(Event::Mouse($event));
|
state.trigger_event(Event::Mouse($event));
|
||||||
}
|
}
|
||||||
|
@ -49,9 +51,7 @@ macro_rules! add_mouse_button_class_method {
|
||||||
($class:ident, $sel:ident, $event_ty:ident, $button:expr) => {
|
($class:ident, $sel:ident, $event_ty:ident, $button:expr) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
extern "C" fn $sel(this: &Object, _: Sel, event: id){
|
extern "C" fn $sel(this: &Object, _: Sel, event: id){
|
||||||
let state: &mut WindowState = unsafe {
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
WindowState::from_field(this)
|
|
||||||
};
|
|
||||||
|
|
||||||
let modifiers = unsafe { NSEvent::modifierFlags(event) };
|
let modifiers = unsafe { NSEvent::modifierFlags(event) };
|
||||||
|
|
||||||
|
@ -72,9 +72,7 @@ macro_rules! add_simple_keyboard_class_method {
|
||||||
($class:ident, $sel:ident) => {
|
($class:ident, $sel:ident) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
extern "C" fn $sel(this: &Object, _: Sel, event: id){
|
extern "C" fn $sel(this: &Object, _: Sel, event: id){
|
||||||
let state: &mut WindowState = unsafe {
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
WindowState::from_field(this)
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(key_event) = state.process_native_key_event(event){
|
if let Some(key_event) = state.process_native_key_event(event){
|
||||||
let status = state.trigger_event(Event::Keyboard(key_event));
|
let status = state.trigger_event(Event::Keyboard(key_event));
|
||||||
|
@ -105,6 +103,11 @@ pub(super) unsafe fn create_view(window_options: &WindowOpenOptions) -> id {
|
||||||
|
|
||||||
view.initWithFrame_(NSRect::new(NSPoint::new(0., 0.), NSSize::new(size.width, size.height)));
|
view.initWithFrame_(NSRect::new(NSPoint::new(0., 0.), NSSize::new(size.width, size.height)));
|
||||||
|
|
||||||
|
let _: id = msg_send![
|
||||||
|
view,
|
||||||
|
registerForDraggedTypes: NSArray::arrayWithObjects(nil, &[NSFilenamesPboardType])
|
||||||
|
];
|
||||||
|
|
||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +134,10 @@ unsafe fn create_view_class() -> &'static Class {
|
||||||
accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL,
|
accepts_first_mouse as extern "C" fn(&Object, Sel, id) -> BOOL,
|
||||||
);
|
);
|
||||||
|
|
||||||
class.add_method(sel!(release), release as extern "C" fn(&mut Object, Sel));
|
class.add_method(
|
||||||
|
sel!(windowShouldClose:),
|
||||||
|
window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL,
|
||||||
|
);
|
||||||
class.add_method(sel!(dealloc), dealloc as extern "C" fn(&mut Object, Sel));
|
class.add_method(sel!(dealloc), dealloc as extern "C" fn(&mut Object, Sel));
|
||||||
class.add_method(
|
class.add_method(
|
||||||
sel!(viewWillMoveToWindow:),
|
sel!(viewWillMoveToWindow:),
|
||||||
|
@ -154,6 +160,24 @@ unsafe fn create_view_class() -> &'static Class {
|
||||||
view_did_change_backing_properties as extern "C" fn(&Object, Sel, id),
|
view_did_change_backing_properties as extern "C" fn(&Object, Sel, id),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
class.add_method(
|
||||||
|
sel!(draggingEntered:),
|
||||||
|
dragging_entered as extern "C" fn(&Object, Sel, id) -> NSUInteger,
|
||||||
|
);
|
||||||
|
class.add_method(
|
||||||
|
sel!(prepareForDragOperation:),
|
||||||
|
prepare_for_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL,
|
||||||
|
);
|
||||||
|
class.add_method(
|
||||||
|
sel!(performDragOperation:),
|
||||||
|
perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL,
|
||||||
|
);
|
||||||
|
class.add_method(
|
||||||
|
sel!(draggingUpdated:),
|
||||||
|
dragging_updated as extern "C" fn(&Object, Sel, id) -> NSUInteger,
|
||||||
|
);
|
||||||
|
class.add_method(sel!(draggingExited:), dragging_exited as extern "C" fn(&Object, Sel, id));
|
||||||
|
|
||||||
add_mouse_button_class_method!(class, mouseDown, ButtonPressed, MouseButton::Left);
|
add_mouse_button_class_method!(class, mouseDown, ButtonPressed, MouseButton::Left);
|
||||||
add_mouse_button_class_method!(class, mouseUp, ButtonReleased, MouseButton::Left);
|
add_mouse_button_class_method!(class, mouseUp, ButtonReleased, MouseButton::Left);
|
||||||
add_mouse_button_class_method!(class, rightMouseDown, ButtonPressed, MouseButton::Right);
|
add_mouse_button_class_method!(class, rightMouseDown, ButtonPressed, MouseButton::Right);
|
||||||
|
@ -184,37 +208,14 @@ extern "C" fn accepts_first_mouse(_this: &Object, _sel: Sel, _event: id) -> BOOL
|
||||||
YES
|
YES
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn release(this: &mut Object, _sel: Sel) {
|
extern "C" fn window_should_close(this: &Object, _: Sel, _sender: id) -> BOOL {
|
||||||
// Hack for breaking circular references. We store the value of retainCount
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
// after build(), and then when retainCount drops back to that value, we
|
|
||||||
// drop the WindowState, hoping that any circular references it holds back
|
|
||||||
// to the NSView (e.g. wgpu surfaces) get released.
|
|
||||||
//
|
|
||||||
// This is definitely broken, since it can be thwarted by e.g. creating a
|
|
||||||
// wgpu surface at some point after build() (which will mean the NSView
|
|
||||||
// never gets dealloced) or dropping a wgpu surface at some point before
|
|
||||||
// drop() (which will mean the WindowState gets dropped early).
|
|
||||||
//
|
|
||||||
// TODO: Find a better solution for circular references.
|
|
||||||
|
|
||||||
unsafe {
|
state.trigger_event(Event::Window(WindowEvent::WillClose));
|
||||||
let retain_count: usize = msg_send![this, retainCount];
|
|
||||||
|
|
||||||
let state_ptr: *mut c_void = *this.get_ivar(BASEVIEW_STATE_IVAR);
|
state.window_inner.close();
|
||||||
|
|
||||||
if !state_ptr.is_null() {
|
NO
|
||||||
let retain_count_after_build = WindowState::from_field(this).retain_count_after_build;
|
|
||||||
|
|
||||||
if retain_count <= retain_count_after_build {
|
|
||||||
WindowState::stop_and_free(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let superclass = msg_send![this, superclass];
|
|
||||||
let () = msg_send![super(this, superclass), release];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn dealloc(this: &mut Object, _sel: Sel) {
|
extern "C" fn dealloc(this: &mut Object, _sel: Sel) {
|
||||||
|
@ -236,7 +237,7 @@ extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel, _: id) {
|
||||||
let scale_factor: f64 =
|
let scale_factor: f64 =
|
||||||
if ns_window.is_null() { 1.0 } else { NSWindow::backingScaleFactor(ns_window) };
|
if ns_window.is_null() { 1.0 } else { NSWindow::backingScaleFactor(ns_window) };
|
||||||
|
|
||||||
let state: &mut WindowState = WindowState::from_field(this);
|
let state = WindowState::from_view(this);
|
||||||
|
|
||||||
let bounds: NSRect = msg_send![this, bounds];
|
let bounds: NSRect = msg_send![this, bounds];
|
||||||
|
|
||||||
|
@ -245,10 +246,12 @@ extern "C" fn view_did_change_backing_properties(this: &Object, _: Sel, _: id) {
|
||||||
scale_factor,
|
scale_factor,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let window_info = state.window_info.get();
|
||||||
|
|
||||||
// Only send the event when the window's size has actually changed to be in line with the
|
// Only send the event when the window's size has actually changed to be in line with the
|
||||||
// other platform implementations
|
// other platform implementations
|
||||||
if new_window_info.physical_size() != state.window_info.physical_size() {
|
if new_window_info.physical_size() != window_info.physical_size() {
|
||||||
state.window_info = new_window_info;
|
state.window_info.set(new_window_info);
|
||||||
state.trigger_event(Event::Window(WindowEvent::Resized(new_window_info)));
|
state.trigger_event(Event::Window(WindowEvent::Resized(new_window_info)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,7 +337,7 @@ extern "C" fn update_tracking_areas(this: &Object, _self: Sel, _: id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn mouse_moved(this: &Object, _sel: Sel, event: id) {
|
extern "C" fn mouse_moved(this: &Object, _sel: Sel, event: id) {
|
||||||
let state: &mut WindowState = unsafe { WindowState::from_field(this) };
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
|
|
||||||
let point: NSPoint = unsafe {
|
let point: NSPoint = unsafe {
|
||||||
let point = NSEvent::locationInWindow(event);
|
let point = NSEvent::locationInWindow(event);
|
||||||
|
@ -352,7 +355,7 @@ extern "C" fn mouse_moved(this: &Object, _sel: Sel, event: id) {
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn scroll_wheel(this: &Object, _: Sel, event: id) {
|
extern "C" fn scroll_wheel(this: &Object, _: Sel, event: id) {
|
||||||
let state: &mut WindowState = unsafe { WindowState::from_field(this) };
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
|
|
||||||
let delta = unsafe {
|
let delta = unsafe {
|
||||||
let x = NSEvent::scrollingDeltaX(event) as f32;
|
let x = NSEvent::scrollingDeltaX(event) as f32;
|
||||||
|
@ -372,3 +375,101 @@ extern "C" fn scroll_wheel(this: &Object, _: Sel, event: id) {
|
||||||
modifiers: make_modifiers(modifiers),
|
modifiers: make_modifiers(modifiers),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_drag_position(sender: id) -> Point {
|
||||||
|
let point: NSPoint = unsafe { msg_send![sender, draggingLocation] };
|
||||||
|
Point::new(point.x, point.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_drop_data(sender: id) -> DropData {
|
||||||
|
if sender == nil {
|
||||||
|
return DropData::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let pasteboard: id = msg_send![sender, draggingPasteboard];
|
||||||
|
let file_list: id = msg_send![pasteboard, propertyListForType: NSFilenamesPboardType];
|
||||||
|
|
||||||
|
if file_list == nil {
|
||||||
|
return DropData::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut files = vec![];
|
||||||
|
for i in 0..NSArray::count(file_list) {
|
||||||
|
let data = NSArray::objectAtIndex(file_list, i);
|
||||||
|
files.push(from_nsstring(data).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
DropData::Files(files)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_event(window_state: &WindowState, event: MouseEvent) -> NSUInteger {
|
||||||
|
let event_status = window_state.trigger_event(Event::Mouse(event));
|
||||||
|
match event_status {
|
||||||
|
EventStatus::AcceptDrop(DropEffect::Copy) => NSDragOperationCopy,
|
||||||
|
EventStatus::AcceptDrop(DropEffect::Move) => NSDragOperationMove,
|
||||||
|
EventStatus::AcceptDrop(DropEffect::Link) => NSDragOperationLink,
|
||||||
|
EventStatus::AcceptDrop(DropEffect::Scroll) => NSDragOperationGeneric,
|
||||||
|
_ => NSDragOperationNone,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn dragging_entered(this: &Object, _sel: Sel, sender: id) -> NSUInteger {
|
||||||
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
|
let modifiers = state.keyboard_state().last_mods();
|
||||||
|
let drop_data = get_drop_data(sender);
|
||||||
|
|
||||||
|
let event = MouseEvent::DragEntered {
|
||||||
|
position: get_drag_position(sender),
|
||||||
|
modifiers: make_modifiers(modifiers),
|
||||||
|
data: drop_data,
|
||||||
|
};
|
||||||
|
|
||||||
|
on_event(&state, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn dragging_updated(this: &Object, _sel: Sel, sender: id) -> NSUInteger {
|
||||||
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
|
let modifiers = state.keyboard_state().last_mods();
|
||||||
|
let drop_data = get_drop_data(sender);
|
||||||
|
|
||||||
|
let event = MouseEvent::DragMoved {
|
||||||
|
position: get_drag_position(sender),
|
||||||
|
modifiers: make_modifiers(modifiers),
|
||||||
|
data: drop_data,
|
||||||
|
};
|
||||||
|
|
||||||
|
on_event(&state, event)
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn prepare_for_drag_operation(_this: &Object, _sel: Sel, _sender: id) -> BOOL {
|
||||||
|
// Always accept drag operation if we get this far
|
||||||
|
// This function won't be called unless dragging_entered/updated
|
||||||
|
// has returned an acceptable operation
|
||||||
|
YES
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn perform_drag_operation(this: &Object, _sel: Sel, sender: id) -> BOOL {
|
||||||
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
|
let modifiers = state.keyboard_state().last_mods();
|
||||||
|
let drop_data = get_drop_data(sender);
|
||||||
|
|
||||||
|
let event = MouseEvent::DragDropped {
|
||||||
|
position: get_drag_position(sender),
|
||||||
|
modifiers: make_modifiers(modifiers),
|
||||||
|
data: drop_data,
|
||||||
|
};
|
||||||
|
|
||||||
|
let event_status = state.trigger_event(Event::Mouse(event));
|
||||||
|
match event_status {
|
||||||
|
EventStatus::AcceptDrop(_) => YES,
|
||||||
|
_ => NO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" fn dragging_exited(this: &Object, _sel: Sel, _sender: id) {
|
||||||
|
let state = unsafe { WindowState::from_view(this) };
|
||||||
|
|
||||||
|
on_event(&state, MouseEvent::DragLeft);
|
||||||
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
use std::cell::{Cell, RefCell};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use cocoa::appkit::{
|
use cocoa::appkit::{
|
||||||
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSBackingStoreBuffered,
|
NSApp, NSApplication, NSApplicationActivationPolicyRegular, NSBackingStoreBuffered,
|
||||||
|
@ -17,10 +16,13 @@ use keyboard_types::KeyboardEvent;
|
||||||
|
|
||||||
use objc::{msg_send, runtime::Object, sel, sel_impl};
|
use objc::{msg_send, runtime::Object, sel, sel_impl};
|
||||||
|
|
||||||
use raw_window_handle::{AppKitHandle, HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{
|
||||||
|
AppKitDisplayHandle, AppKitWindowHandle, HasRawDisplayHandle, HasRawWindowHandle,
|
||||||
|
RawDisplayHandle, RawWindowHandle,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, EventStatus, Size, WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
|
Event, EventStatus, MouseCursor, Size, WindowHandler, WindowInfo, WindowOpenOptions,
|
||||||
WindowScalePolicy,
|
WindowScalePolicy,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,93 +30,99 @@ use super::keyboard::KeyboardState;
|
||||||
use super::view::{create_view, BASEVIEW_STATE_IVAR};
|
use super::view::{create_view, BASEVIEW_STATE_IVAR};
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
use crate::{
|
use crate::gl::{GlConfig, GlContext};
|
||||||
gl::{GlConfig, GlContext},
|
|
||||||
window::RawWindowHandleWrapper,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct WindowHandle {
|
pub struct WindowHandle {
|
||||||
raw_window_handle: Option<RawWindowHandle>,
|
state: Rc<WindowState>,
|
||||||
close_requested: Arc<AtomicBool>,
|
|
||||||
is_open: Arc<AtomicBool>,
|
|
||||||
|
|
||||||
// Ensure handle is !Send
|
|
||||||
_phantom: PhantomData<*mut ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowHandle {
|
impl WindowHandle {
|
||||||
pub fn close(&mut self) {
|
pub fn close(&mut self) {
|
||||||
if self.raw_window_handle.take().is_some() {
|
self.state.window_inner.close();
|
||||||
self.close_requested.store(true, Ordering::Relaxed);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_open(&self) -> bool {
|
pub fn is_open(&self) -> bool {
|
||||||
self.is_open.load(Ordering::Relaxed)
|
self.state.window_inner.open.get()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl HasRawWindowHandle for WindowHandle {
|
unsafe impl HasRawWindowHandle for WindowHandle {
|
||||||
fn raw_window_handle(&self) -> RawWindowHandle {
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
if let Some(raw_window_handle) = self.raw_window_handle {
|
self.state.window_inner.raw_window_handle()
|
||||||
if self.is_open.load(Ordering::Relaxed) {
|
|
||||||
return raw_window_handle;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RawWindowHandle::AppKit(AppKitHandle::empty())
|
pub(super) struct WindowInner {
|
||||||
}
|
open: Cell<bool>,
|
||||||
}
|
|
||||||
|
|
||||||
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
|
/// Only set if we created the parent window, i.e. we are running in
|
||||||
/// parentless mode
|
/// parentless mode
|
||||||
ns_app: Option<id>,
|
ns_app: Cell<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: Cell<Option<id>>,
|
||||||
/// Our subclassed NSView
|
/// Our subclassed NSView
|
||||||
ns_view: id,
|
ns_view: id,
|
||||||
close_requested: bool,
|
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
gl_context: Option<GlContext>,
|
gl_context: Option<GlContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl WindowInner {
|
||||||
|
pub(super) fn close(&self) {
|
||||||
|
if self.open.get() {
|
||||||
|
self.open.set(false);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
// Take back ownership of the NSView's Rc<WindowState>
|
||||||
|
let state_ptr: *const c_void = *(*self.ns_view).get_ivar(BASEVIEW_STATE_IVAR);
|
||||||
|
let window_state = Rc::from_raw(state_ptr as *mut WindowState);
|
||||||
|
|
||||||
|
// Cancel the frame timer
|
||||||
|
if let Some(frame_timer) = window_state.frame_timer.take() {
|
||||||
|
CFRunLoop::get_current().remove_timer(&frame_timer, kCFRunLoopDefaultMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(window_state);
|
||||||
|
|
||||||
|
// Close the window if in non-parented mode
|
||||||
|
if let Some(ns_window) = self.ns_window.take() {
|
||||||
|
ns_window.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the NSView is detached from the parent window
|
||||||
|
self.ns_view.removeFromSuperview();
|
||||||
|
let () = msg_send![self.ns_view as id, release];
|
||||||
|
|
||||||
|
// If in non-parented mode, we want to also quit the app altogether
|
||||||
|
let app = self.ns_app.take();
|
||||||
|
if let Some(app) = app {
|
||||||
|
app.stop_(app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
|
if self.open.get() {
|
||||||
|
let ns_window = self.ns_window.get().unwrap_or(ptr::null_mut()) as *mut c_void;
|
||||||
|
|
||||||
|
let mut handle = AppKitWindowHandle::empty();
|
||||||
|
handle.ns_window = ns_window;
|
||||||
|
handle.ns_view = self.ns_view as *mut c_void;
|
||||||
|
|
||||||
|
return RawWindowHandle::AppKit(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
RawWindowHandle::AppKit(AppKitWindowHandle::empty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Window<'a> {
|
||||||
|
inner: &'a WindowInner,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Window<'a> {
|
||||||
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
P: HasRawWindowHandle,
|
P: HasRawWindowHandle,
|
||||||
|
@ -139,11 +147,11 @@ impl Window {
|
||||||
|
|
||||||
let ns_view = unsafe { create_view(&options) };
|
let ns_view = unsafe { create_view(&options) };
|
||||||
|
|
||||||
let window = Window {
|
let window_inner = WindowInner {
|
||||||
ns_app: None,
|
open: Cell::new(true),
|
||||||
ns_window: None,
|
ns_app: Cell::new(None),
|
||||||
|
ns_window: Cell::new(None),
|
||||||
ns_view,
|
ns_view,
|
||||||
close_requested: false,
|
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
gl_context: options
|
gl_context: options
|
||||||
|
@ -151,11 +159,10 @@ impl Window {
|
||||||
.map(|gl_config| Self::create_gl_context(None, ns_view, gl_config)),
|
.map(|gl_config| Self::create_gl_context(None, ns_view, gl_config)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let window_handle = Self::init(true, window, window_info, build);
|
let window_handle = Self::init(window_inner, window_info, 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];
|
||||||
let () = msg_send![ns_view as id, release];
|
|
||||||
|
|
||||||
let () = msg_send![pool, drain];
|
let () = msg_send![pool, drain];
|
||||||
}
|
}
|
||||||
|
@ -163,44 +170,6 @@ impl Window {
|
||||||
window_handle
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
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 pool = unsafe { NSAutoreleasePool::new(nil) };
|
|
||||||
|
|
||||||
let scaling = match options.scale {
|
|
||||||
WindowScalePolicy::ScaleFactor(scale) => scale,
|
|
||||||
WindowScalePolicy::SystemScaleFactor => 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let window_info = WindowInfo::from_logical_size(options.size, scaling);
|
|
||||||
|
|
||||||
let ns_view = unsafe { create_view(&options) };
|
|
||||||
|
|
||||||
let window = Window {
|
|
||||||
ns_app: None,
|
|
||||||
ns_window: None,
|
|
||||||
ns_view,
|
|
||||||
close_requested: false,
|
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
|
||||||
gl_context: options
|
|
||||||
.gl_config
|
|
||||||
.map(|gl_config| Self::create_gl_context(None, ns_view, gl_config)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let window_handle = Self::init(true, window, window_info, build);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let () = msg_send![pool, drain];
|
|
||||||
}
|
|
||||||
|
|
||||||
window_handle
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
|
@ -253,11 +222,11 @@ impl Window {
|
||||||
|
|
||||||
let ns_view = unsafe { create_view(&options) };
|
let ns_view = unsafe { create_view(&options) };
|
||||||
|
|
||||||
let window = Window {
|
let window_inner = WindowInner {
|
||||||
ns_app: Some(app),
|
open: Cell::new(true),
|
||||||
ns_window: Some(ns_window),
|
ns_app: Cell::new(Some(app)),
|
||||||
|
ns_window: Cell::new(Some(ns_window)),
|
||||||
ns_view,
|
ns_view,
|
||||||
close_requested: false,
|
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
gl_context: options
|
gl_context: options
|
||||||
|
@ -265,165 +234,144 @@ impl Window {
|
||||||
.map(|gl_config| Self::create_gl_context(Some(ns_window), ns_view, gl_config)),
|
.map(|gl_config| Self::create_gl_context(Some(ns_window), ns_view, gl_config)),
|
||||||
};
|
};
|
||||||
|
|
||||||
let _ = Self::init(false, window, window_info, build);
|
let _ = Self::init(window_inner, window_info, build);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
ns_window.setContentView_(ns_view);
|
ns_window.setContentView_(ns_view);
|
||||||
|
ns_window.setDelegate_(ns_view);
|
||||||
|
|
||||||
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>(
|
fn init<H, B>(window_inner: WindowInner, window_info: WindowInfo, build: B) -> WindowHandle
|
||||||
parented: bool, mut window: Window, window_info: WindowInfo, 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 window_handler = Box::new(build(&mut crate::Window::new(&mut window)));
|
let mut window = crate::Window::new(Window { inner: &window_inner });
|
||||||
|
let window_handler = Box::new(build(&mut window));
|
||||||
|
|
||||||
let (parent_handle, window_handle) = ParentHandle::new(window.raw_window_handle());
|
let ns_view = window_inner.ns_view;
|
||||||
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 = Rc::new(WindowState {
|
||||||
|
window_inner,
|
||||||
let window_state_ptr = Box::into_raw(Box::new(WindowState {
|
window_handler: RefCell::new(window_handler),
|
||||||
window,
|
|
||||||
window_handler,
|
|
||||||
keyboard_state: KeyboardState::new(),
|
keyboard_state: KeyboardState::new(),
|
||||||
frame_timer: None,
|
frame_timer: Cell::new(None),
|
||||||
retain_count_after_build,
|
window_info: Cell::new(window_info),
|
||||||
window_info,
|
});
|
||||||
_parent_handle: parent_handle,
|
|
||||||
}));
|
let window_state_ptr = Rc::into_raw(Rc::clone(&window_state));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(*(*window_state_ptr).window.ns_view)
|
(*ns_view).set_ivar(BASEVIEW_STATE_IVAR, window_state_ptr as *const c_void);
|
||||||
.set_ivar(BASEVIEW_STATE_IVAR, window_state_ptr as *mut c_void);
|
|
||||||
|
|
||||||
WindowState::setup_timer(window_state_ptr);
|
WindowState::setup_timer(window_state_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
window_handle
|
WindowHandle { state: window_state }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&mut self) {
|
pub fn close(&mut self) {
|
||||||
self.close_requested = true;
|
self.inner.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, size: Size) {
|
pub fn resize(&mut self, size: Size) {
|
||||||
// NOTE: macOS gives you a personal rave if you pass in fractional pixels here. Even though
|
if self.inner.open.get() {
|
||||||
// the size is in fractional pixels.
|
// NOTE: macOS gives you a personal rave if you pass in fractional pixels here. Even
|
||||||
|
// though the size is in fractional pixels.
|
||||||
let size = NSSize::new(size.width.round(), size.height.round());
|
let size = NSSize::new(size.width.round(), size.height.round());
|
||||||
|
|
||||||
unsafe { NSView::setFrameSize(self.ns_view, size) };
|
unsafe { NSView::setFrameSize(self.inner.ns_view, size) };
|
||||||
unsafe {
|
unsafe {
|
||||||
let _: () = msg_send![self.ns_view, setNeedsDisplay: YES];
|
let _: () = msg_send![self.inner.ns_view, setNeedsDisplay: YES];
|
||||||
}
|
}
|
||||||
|
|
||||||
// When using OpenGL the `NSOpenGLView` needs to be resized separately? Why? Because macOS.
|
// When using OpenGL the `NSOpenGLView` needs to be resized separately? Why? Because
|
||||||
|
// macOS.
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
if let Some(gl_context) = &self.gl_context {
|
if let Some(gl_context) = &self.inner.gl_context {
|
||||||
gl_context.resize(size);
|
gl_context.resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a standalone window then we'll also need to resize the window itself
|
// If this is a standalone window then we'll also need to resize the window itself
|
||||||
if let Some(ns_window) = self.ns_window {
|
if let Some(ns_window) = self.inner.ns_window.get() {
|
||||||
unsafe { NSWindow::setContentSize_(ns_window, size) };
|
unsafe { NSWindow::setContentSize_(ns_window, size) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_mouse_cursor(&mut self, _mouse_cursor: MouseCursor) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
pub fn gl_context(&self) -> Option<&GlContext> {
|
pub fn gl_context(&self) -> Option<&GlContext> {
|
||||||
self.gl_context.as_ref()
|
self.inner.gl_context.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
fn create_gl_context(ns_window: Option<id>, ns_view: id, config: GlConfig) -> GlContext {
|
fn create_gl_context(ns_window: Option<id>, ns_view: id, config: GlConfig) -> GlContext {
|
||||||
let mut handle = AppKitHandle::empty();
|
let mut handle = AppKitWindowHandle::empty();
|
||||||
handle.ns_window = ns_window.unwrap_or(ptr::null_mut()) as *mut c_void;
|
handle.ns_window = ns_window.unwrap_or(ptr::null_mut()) as *mut c_void;
|
||||||
handle.ns_view = ns_view as *mut c_void;
|
handle.ns_view = ns_view as *mut c_void;
|
||||||
let handle = RawWindowHandleWrapper { handle: RawWindowHandle::AppKit(handle) };
|
let handle = RawWindowHandle::AppKit(handle);
|
||||||
|
|
||||||
unsafe { GlContext::create(&handle, config).expect("Could not create OpenGL context") }
|
unsafe { GlContext::create(&handle, config).expect("Could not create OpenGL context") }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct WindowState {
|
pub(super) struct WindowState {
|
||||||
window: Window,
|
pub(super) window_inner: WindowInner,
|
||||||
window_handler: Box<dyn WindowHandler>,
|
window_handler: RefCell<Box<dyn WindowHandler>>,
|
||||||
keyboard_state: KeyboardState,
|
keyboard_state: KeyboardState,
|
||||||
frame_timer: Option<CFRunLoopTimer>,
|
frame_timer: Cell<Option<CFRunLoopTimer>>,
|
||||||
_parent_handle: Option<ParentHandle>,
|
|
||||||
pub retain_count_after_build: usize,
|
|
||||||
/// The last known window info for this window.
|
/// The last known window info for this window.
|
||||||
pub window_info: WindowInfo,
|
pub window_info: Cell<WindowInfo>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowState {
|
impl WindowState {
|
||||||
/// Returns a mutable reference to a WindowState from an Objective-C field
|
/// Gets the `WindowState` held by a given `NSView`.
|
||||||
///
|
///
|
||||||
/// Don't use this to create two simulataneous references to a single
|
/// This method returns a cloned `Rc<WindowState>` rather than just a `&WindowState`, since the
|
||||||
/// WindowState. Apparently, macOS blocks for the duration of an event,
|
/// original `Rc<WindowState>` owned by the `NSView` can be dropped at any time
|
||||||
/// callback, meaning that this shouldn't be a problem in practice.
|
/// (including during an event handler).
|
||||||
pub(super) unsafe fn from_field(obj: &Object) -> &mut Self {
|
pub(super) unsafe fn from_view(view: &Object) -> Rc<WindowState> {
|
||||||
let state_ptr: *mut c_void = *obj.get_ivar(BASEVIEW_STATE_IVAR);
|
let state_ptr: *const c_void = *view.get_ivar(BASEVIEW_STATE_IVAR);
|
||||||
|
|
||||||
&mut *(state_ptr as *mut Self)
|
let state_rc = Rc::from_raw(state_ptr as *const WindowState);
|
||||||
|
let state = Rc::clone(&state_rc);
|
||||||
|
let _ = Rc::into_raw(state_rc);
|
||||||
|
|
||||||
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn trigger_event(&mut self, event: Event) -> EventStatus {
|
pub(super) fn trigger_event(&self, event: Event) -> EventStatus {
|
||||||
self.window_handler.on_event(&mut crate::Window::new(&mut self.window), event)
|
let mut window = crate::Window::new(Window { inner: &self.window_inner });
|
||||||
|
self.window_handler.borrow_mut().on_event(&mut window, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn trigger_frame(&mut self) {
|
pub(super) fn trigger_frame(&self) {
|
||||||
self.window_handler.on_frame(&mut crate::Window::new(&mut self.window));
|
let mut window = crate::Window::new(Window { inner: &self.window_inner });
|
||||||
|
self.window_handler.borrow_mut().on_frame(&mut 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 {
|
pub(super) fn keyboard_state(&self) -> &KeyboardState {
|
||||||
unsafe {
|
&self.keyboard_state
|
||||||
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(&self, event: *mut Object) -> Option<KeyboardEvent> {
|
||||||
self.keyboard_state.process_native_event(event)
|
self.keyboard_state.process_native_event(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Don't call until WindowState pointer is stored in view
|
unsafe fn setup_timer(window_state_ptr: *const WindowState) {
|
||||||
unsafe fn setup_timer(window_state_ptr: *mut WindowState) {
|
|
||||||
extern "C" fn timer_callback(_: *mut __CFRunLoopTimer, window_state_ptr: *mut c_void) {
|
extern "C" fn timer_callback(_: *mut __CFRunLoopTimer, window_state_ptr: *mut c_void) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let window_state = &mut *(window_state_ptr as *mut WindowState);
|
let window_state = &*(window_state_ptr as *const WindowState);
|
||||||
|
|
||||||
window_state.trigger_frame();
|
window_state.trigger_frame();
|
||||||
}
|
}
|
||||||
|
@ -441,46 +389,19 @@ impl WindowState {
|
||||||
|
|
||||||
CFRunLoop::get_current().add_timer(&timer, kCFRunLoopDefaultMode);
|
CFRunLoop::get_current().add_timer(&timer, kCFRunLoopDefaultMode);
|
||||||
|
|
||||||
let window_state = &mut *(window_state_ptr);
|
(*window_state_ptr).frame_timer.set(Some(timer));
|
||||||
|
|
||||||
window_state.frame_timer = Some(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call when freeing view
|
|
||||||
pub(super) unsafe fn stop_and_free(ns_view_obj: &mut Object) {
|
|
||||||
let state_ptr: *mut c_void = *ns_view_obj.get_ivar(BASEVIEW_STATE_IVAR);
|
|
||||||
|
|
||||||
// Take back ownership of Box<WindowState> so that it gets dropped
|
|
||||||
// when it goes out of scope
|
|
||||||
let mut window_state = Box::from_raw(state_ptr as *mut WindowState);
|
|
||||||
|
|
||||||
if let Some(frame_timer) = window_state.frame_timer.take() {
|
|
||||||
CFRunLoop::get_current().remove_timer(&frame_timer, kCFRunLoopDefaultMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear ivar before triggering WindowEvent::WillClose. Otherwise, if the
|
|
||||||
// handler of the event causes another call to release, this function could be
|
|
||||||
// called again, leading to a double free.
|
|
||||||
ns_view_obj.set_ivar(BASEVIEW_STATE_IVAR, ptr::null() as *const c_void);
|
|
||||||
|
|
||||||
window_state.trigger_event(Event::Window(WindowEvent::WillClose));
|
|
||||||
|
|
||||||
// If in non-parented mode, we want to also quit the app altogether
|
|
||||||
if let Some(app) = window_state.window.ns_app.take() {
|
|
||||||
app.stop_(app);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl HasRawWindowHandle for Window {
|
unsafe impl<'a> HasRawWindowHandle for Window<'a> {
|
||||||
fn raw_window_handle(&self) -> RawWindowHandle {
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
let ns_window = self.ns_window.unwrap_or(ptr::null_mut()) as *mut c_void;
|
self.inner.raw_window_handle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut handle = AppKitHandle::empty();
|
unsafe impl<'a> HasRawDisplayHandle for Window<'a> {
|
||||||
handle.ns_window = ns_window;
|
fn raw_display_handle(&self) -> RawDisplayHandle {
|
||||||
handle.ns_view = self.ns_view as *mut c_void;
|
RawDisplayHandle::AppKit(AppKitDisplayHandle::empty())
|
||||||
|
|
||||||
RawWindowHandle::AppKit(handle)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,31 +2,51 @@ use std::ffi::OsString;
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use std::os::windows::prelude::OsStringExt;
|
use std::os::windows::prelude::OsStringExt;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::rc::{Weak, Rc};
|
use std::rc::{Rc, Weak};
|
||||||
|
|
||||||
use winapi::Interface;
|
use winapi::shared::guiddef::{IsEqualIID, REFIID};
|
||||||
use winapi::shared::guiddef::{REFIID, IsEqualIID};
|
|
||||||
use winapi::shared::minwindef::{DWORD, WPARAM};
|
use winapi::shared::minwindef::{DWORD, WPARAM};
|
||||||
use winapi::shared::ntdef::{HRESULT, ULONG};
|
use winapi::shared::ntdef::{HRESULT, ULONG};
|
||||||
use winapi::shared::windef::POINTL;
|
use winapi::shared::windef::POINTL;
|
||||||
use winapi::shared::winerror::{S_OK, E_NOINTERFACE, E_UNEXPECTED};
|
use winapi::shared::winerror::{E_NOINTERFACE, E_UNEXPECTED, S_OK};
|
||||||
use winapi::shared::wtypes::DVASPECT_CONTENT;
|
use winapi::shared::wtypes::DVASPECT_CONTENT;
|
||||||
use winapi::um::objidl::{IDataObject, FORMATETC, TYMED_HGLOBAL, STGMEDIUM};
|
use winapi::um::objidl::{IDataObject, FORMATETC, STGMEDIUM, TYMED_HGLOBAL};
|
||||||
use winapi::um::oleidl::{IDropTarget, IDropTargetVtbl, DROPEFFECT_COPY, DROPEFFECT_MOVE, DROPEFFECT_LINK, DROPEFFECT_SCROLL, DROPEFFECT_NONE};
|
use winapi::um::oleidl::{
|
||||||
|
IDropTarget, IDropTargetVtbl, DROPEFFECT_COPY, DROPEFFECT_LINK, DROPEFFECT_MOVE,
|
||||||
|
DROPEFFECT_NONE, DROPEFFECT_SCROLL,
|
||||||
|
};
|
||||||
use winapi::um::shellapi::DragQueryFileW;
|
use winapi::um::shellapi::DragQueryFileW;
|
||||||
use winapi::um::unknwnbase::{IUnknownVtbl, IUnknown};
|
use winapi::um::unknwnbase::{IUnknown, IUnknownVtbl};
|
||||||
use winapi::um::winuser::CF_HDROP;
|
use winapi::um::winuser::CF_HDROP;
|
||||||
|
use winapi::Interface;
|
||||||
|
|
||||||
use crate::{Point, DropData, MouseEvent, Event, EventStatus, DropEffect, PhyPoint};
|
use crate::{DropData, DropEffect, Event, EventStatus, MouseEvent, PhyPoint, Point};
|
||||||
|
|
||||||
use super::WindowState;
|
use super::WindowState;
|
||||||
|
|
||||||
// These function pointers have to be stored in a (const) variable before they can be transmuted
|
// These function pointers have to be stored in a (const) variable before they can be transmuted
|
||||||
// Transmuting is needed because winapi has a bug where the pt parameter has an incorrect
|
// Transmuting is needed because winapi has a bug where the pt parameter has an incorrect
|
||||||
// type `*const POINTL`
|
// type `*const POINTL`
|
||||||
const DRAG_ENTER_PTR: unsafe extern "system" fn(this: *mut IDropTarget, pDataObj: *const IDataObject, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD) -> HRESULT = DropTarget::drag_enter;
|
const DRAG_ENTER_PTR: unsafe extern "system" fn(
|
||||||
const DRAG_OVER_PTR: unsafe extern "system" fn(this: *mut IDropTarget, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD) -> HRESULT = DropTarget::drag_over;
|
this: *mut IDropTarget,
|
||||||
const DROP_PTR: unsafe extern "system" fn(this: *mut IDropTarget, pDataObj: *const IDataObject, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD) -> HRESULT = DropTarget::drop;
|
pDataObj: *const IDataObject,
|
||||||
|
grfKeyState: DWORD,
|
||||||
|
pt: POINTL,
|
||||||
|
pdwEffect: *mut DWORD,
|
||||||
|
) -> HRESULT = DropTarget::drag_enter;
|
||||||
|
const DRAG_OVER_PTR: unsafe extern "system" fn(
|
||||||
|
this: *mut IDropTarget,
|
||||||
|
grfKeyState: DWORD,
|
||||||
|
pt: POINTL,
|
||||||
|
pdwEffect: *mut DWORD,
|
||||||
|
) -> HRESULT = DropTarget::drag_over;
|
||||||
|
const DROP_PTR: unsafe extern "system" fn(
|
||||||
|
this: *mut IDropTarget,
|
||||||
|
pDataObj: *const IDataObject,
|
||||||
|
grfKeyState: DWORD,
|
||||||
|
pt: POINTL,
|
||||||
|
pdwEffect: *mut DWORD,
|
||||||
|
) -> HRESULT = DropTarget::drop;
|
||||||
const DROP_TARGET_VTBL: IDropTargetVtbl = IDropTargetVtbl {
|
const DROP_TARGET_VTBL: IDropTargetVtbl = IDropTargetVtbl {
|
||||||
parent: IUnknownVtbl {
|
parent: IUnknownVtbl {
|
||||||
QueryInterface: DropTarget::query_interface,
|
QueryInterface: DropTarget::query_interface,
|
||||||
|
@ -63,17 +83,18 @@ impl DropTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn on_event(&self, pdwEffect: Option<*mut DWORD>, event: MouseEvent) {
|
fn on_event(&self, pdwEffect: Option<*mut DWORD>, event: MouseEvent) {
|
||||||
let Some(window_state) = self.window_state.upgrade() else {
|
let Some(window_state) = self.window_state.upgrade() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
let event = Event::Mouse(event);
|
let event = Event::Mouse(event);
|
||||||
let event_status = window_state.handler_mut().as_mut().unwrap().on_event(&mut window, event);
|
let event_status =
|
||||||
|
window_state.handler_mut().as_mut().unwrap().on_event(&mut window, event);
|
||||||
|
|
||||||
if let Some(pdwEffect) = pdwEffect {
|
if let Some(pdwEffect) = pdwEffect {
|
||||||
match event_status {
|
match event_status {
|
||||||
|
@ -105,11 +126,7 @@ impl DropTarget {
|
||||||
tymed: TYMED_HGLOBAL,
|
tymed: TYMED_HGLOBAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut medium = STGMEDIUM {
|
let mut medium = STGMEDIUM { tymed: 0, u: null_mut(), pUnkForRelease: null_mut() };
|
||||||
tymed: 0,
|
|
||||||
u: null_mut(),
|
|
||||||
pUnkForRelease: null_mut(),
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let hresult = data_object.GetData(&format, &mut medium);
|
let hresult = data_object.GetData(&format, &mut medium);
|
||||||
|
@ -133,7 +150,12 @@ impl DropTarget {
|
||||||
let buffer_size = characters as usize + 1;
|
let buffer_size = characters as usize + 1;
|
||||||
let mut buffer = Vec::<u16>::with_capacity(buffer_size);
|
let mut buffer = Vec::<u16>::with_capacity(buffer_size);
|
||||||
|
|
||||||
DragQueryFileW(hdrop, i, transmute(buffer.spare_capacity_mut().as_mut_ptr()), buffer_size as u32);
|
DragQueryFileW(
|
||||||
|
hdrop,
|
||||||
|
i,
|
||||||
|
transmute(buffer.spare_capacity_mut().as_mut_ptr()),
|
||||||
|
buffer_size as u32,
|
||||||
|
);
|
||||||
buffer.set_len(buffer_size);
|
buffer.set_len(buffer_size);
|
||||||
|
|
||||||
paths.push(OsString::from_wide(&buffer[..characters as usize]).into())
|
paths.push(OsString::from_wide(&buffer[..characters as usize]).into())
|
||||||
|
@ -143,12 +165,10 @@ impl DropTarget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
unsafe extern "system" fn query_interface(
|
unsafe extern "system" fn query_interface(
|
||||||
this: *mut IUnknown,
|
this: *mut IUnknown, riid: REFIID, ppvObject: *mut *mut winapi::ctypes::c_void,
|
||||||
riid: REFIID,
|
) -> HRESULT {
|
||||||
ppvObject: *mut *mut winapi::ctypes::c_void,
|
|
||||||
) -> HRESULT
|
|
||||||
{
|
|
||||||
if IsEqualIID(&*riid, &IUnknown::uuidof()) || IsEqualIID(&*riid, &IDropTarget::uuidof()) {
|
if IsEqualIID(&*riid, &IUnknown::uuidof()) || IsEqualIID(&*riid, &IDropTarget::uuidof()) {
|
||||||
Self::add_ref(this);
|
Self::add_ref(this);
|
||||||
*ppvObject = this as *mut winapi::ctypes::c_void;
|
*ppvObject = this as *mut winapi::ctypes::c_void;
|
||||||
|
@ -178,20 +198,18 @@ impl DropTarget {
|
||||||
result as ULONG
|
result as ULONG
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
unsafe extern "system" fn drag_enter(
|
unsafe extern "system" fn drag_enter(
|
||||||
this: *mut IDropTarget,
|
this: *mut IDropTarget, pDataObj: *const IDataObject, grfKeyState: DWORD, pt: POINTL,
|
||||||
pDataObj: *const IDataObject,
|
|
||||||
grfKeyState: DWORD,
|
|
||||||
pt: POINTL,
|
|
||||||
pdwEffect: *mut DWORD,
|
pdwEffect: *mut DWORD,
|
||||||
) -> HRESULT
|
) -> HRESULT {
|
||||||
{
|
|
||||||
let drop_target = &mut *(this as *mut DropTarget);
|
let drop_target = &mut *(this as *mut DropTarget);
|
||||||
let Some(window_state) = drop_target.window_state.upgrade() else {
|
let Some(window_state) = drop_target.window_state.upgrade() else {
|
||||||
return E_UNEXPECTED;
|
return E_UNEXPECTED;
|
||||||
};
|
};
|
||||||
|
|
||||||
let modifiers = window_state.keyboard_state().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
|
let modifiers =
|
||||||
|
window_state.keyboard_state().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
|
||||||
|
|
||||||
drop_target.parse_coordinates(pt);
|
drop_target.parse_coordinates(pt);
|
||||||
drop_target.parse_drop_data(&*pDataObj);
|
drop_target.parse_drop_data(&*pDataObj);
|
||||||
|
@ -206,19 +224,17 @@ impl DropTarget {
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
unsafe extern "system" fn drag_over(
|
unsafe extern "system" fn drag_over(
|
||||||
this: *mut IDropTarget,
|
this: *mut IDropTarget, grfKeyState: DWORD, pt: POINTL, pdwEffect: *mut DWORD,
|
||||||
grfKeyState: DWORD,
|
) -> HRESULT {
|
||||||
pt: POINTL,
|
|
||||||
pdwEffect: *mut DWORD,
|
|
||||||
) -> HRESULT
|
|
||||||
{
|
|
||||||
let drop_target = &mut *(this as *mut DropTarget);
|
let drop_target = &mut *(this as *mut DropTarget);
|
||||||
let Some(window_state) = drop_target.window_state.upgrade() else {
|
let Some(window_state) = drop_target.window_state.upgrade() else {
|
||||||
return E_UNEXPECTED;
|
return E_UNEXPECTED;
|
||||||
};
|
};
|
||||||
|
|
||||||
let modifiers = window_state.keyboard_state().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
|
let modifiers =
|
||||||
|
window_state.keyboard_state().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
|
||||||
|
|
||||||
drop_target.parse_coordinates(pt);
|
drop_target.parse_coordinates(pt);
|
||||||
|
|
||||||
|
@ -238,20 +254,18 @@ impl DropTarget {
|
||||||
S_OK
|
S_OK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
unsafe extern "system" fn drop(
|
unsafe extern "system" fn drop(
|
||||||
this: *mut IDropTarget,
|
this: *mut IDropTarget, pDataObj: *const IDataObject, grfKeyState: DWORD, pt: POINTL,
|
||||||
pDataObj: *const IDataObject,
|
|
||||||
grfKeyState: DWORD,
|
|
||||||
pt: POINTL,
|
|
||||||
pdwEffect: *mut DWORD,
|
pdwEffect: *mut DWORD,
|
||||||
) -> HRESULT
|
) -> HRESULT {
|
||||||
{
|
|
||||||
let drop_target = &mut *(this as *mut DropTarget);
|
let drop_target = &mut *(this as *mut DropTarget);
|
||||||
let Some(window_state) = drop_target.window_state.upgrade() else {
|
let Some(window_state) = drop_target.window_state.upgrade() else {
|
||||||
return E_UNEXPECTED;
|
return E_UNEXPECTED;
|
||||||
};
|
};
|
||||||
|
|
||||||
let modifiers = window_state.keyboard_state().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
|
let modifiers =
|
||||||
|
window_state.keyboard_state().get_modifiers_from_mouse_wparam(grfKeyState as WPARAM);
|
||||||
|
|
||||||
drop_target.parse_coordinates(pt);
|
drop_target.parse_coordinates(pt);
|
||||||
drop_target.parse_drop_data(&*pDataObj);
|
drop_target.parse_drop_data(&*pDataObj);
|
||||||
|
|
|
@ -21,17 +21,19 @@ use winapi::um::winuser::{
|
||||||
use std::cell::{Cell, Ref, RefCell, RefMut};
|
use std::cell::{Cell, Ref, RefCell, RefMut};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::ffi::{c_void, OsStr};
|
use std::ffi::{c_void, 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::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, Win32Handle};
|
use raw_window_handle::{
|
||||||
|
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, Win32WindowHandle,
|
||||||
|
WindowsDisplayHandle,
|
||||||
|
};
|
||||||
|
|
||||||
const BV_WINDOW_MUST_CLOSE: UINT = WM_USER + 1;
|
const BV_WINDOW_MUST_CLOSE: UINT = WM_USER + 1;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, MouseButton, MouseEvent, PhyPoint, PhySize, ScrollDelta, Size, WindowEvent,
|
Event, MouseButton, MouseCursor, MouseEvent, PhyPoint, PhySize, ScrollDelta, Size, WindowEvent,
|
||||||
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy,
|
WindowHandler, WindowInfo, WindowOpenOptions, WindowScalePolicy,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,7 +41,7 @@ use super::drop_target::DropTarget;
|
||||||
use super::keyboard::KeyboardState;
|
use super::keyboard::KeyboardState;
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
use crate::{gl::GlContext, window::RawWindowHandleWrapper};
|
use crate::gl::GlContext;
|
||||||
|
|
||||||
unsafe fn generate_guid() -> String {
|
unsafe fn generate_guid() -> String {
|
||||||
let mut guid: GUID = std::mem::zeroed();
|
let mut guid: GUID = std::mem::zeroed();
|
||||||
|
@ -65,9 +67,6 @@ const WIN_FRAME_TIMER: usize = 4242;
|
||||||
pub struct WindowHandle {
|
pub struct WindowHandle {
|
||||||
hwnd: Option<HWND>,
|
hwnd: Option<HWND>,
|
||||||
is_open: Rc<Cell<bool>>,
|
is_open: Rc<Cell<bool>>,
|
||||||
|
|
||||||
// Ensure handle is !Send
|
|
||||||
_phantom: PhantomData<*mut ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowHandle {
|
impl WindowHandle {
|
||||||
|
@ -87,12 +86,12 @@ impl WindowHandle {
|
||||||
unsafe impl HasRawWindowHandle for WindowHandle {
|
unsafe impl HasRawWindowHandle for WindowHandle {
|
||||||
fn raw_window_handle(&self) -> RawWindowHandle {
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
if let Some(hwnd) = self.hwnd {
|
if let Some(hwnd) = self.hwnd {
|
||||||
let mut handle = Win32Handle::empty();
|
let mut handle = Win32WindowHandle::empty();
|
||||||
handle.hwnd = hwnd as *mut c_void;
|
handle.hwnd = hwnd as *mut c_void;
|
||||||
|
|
||||||
RawWindowHandle::Win32(handle)
|
RawWindowHandle::Win32(handle)
|
||||||
} else {
|
} else {
|
||||||
RawWindowHandle::Win32(Win32Handle::empty())
|
RawWindowHandle::Win32(Win32WindowHandle::empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,11 +104,7 @@ impl ParentHandle {
|
||||||
pub fn new(hwnd: HWND) -> (Self, WindowHandle) {
|
pub fn new(hwnd: HWND) -> (Self, WindowHandle) {
|
||||||
let is_open = Rc::new(Cell::new(true));
|
let is_open = Rc::new(Cell::new(true));
|
||||||
|
|
||||||
let handle = WindowHandle {
|
let handle = WindowHandle { hwnd: Some(hwnd), is_open: Rc::clone(&is_open) };
|
||||||
hwnd: Some(hwnd),
|
|
||||||
is_open: Rc::clone(&is_open),
|
|
||||||
_phantom: PhantomData::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
(Self { is_open }, handle)
|
(Self { is_open }, handle)
|
||||||
}
|
}
|
||||||
|
@ -173,10 +168,7 @@ unsafe fn wnd_proc_inner(
|
||||||
) -> Option<LRESULT> {
|
) -> Option<LRESULT> {
|
||||||
match msg {
|
match msg {
|
||||||
WM_MOUSEMOVE => {
|
WM_MOUSEMOVE => {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
let mut handler = window_state.handler.borrow_mut();
|
|
||||||
let handler = handler.as_mut().unwrap();
|
|
||||||
|
|
||||||
let mut mouse_was_outside_window = window_state.mouse_was_outside_window.borrow_mut();
|
let mut mouse_was_outside_window = window_state.mouse_was_outside_window.borrow_mut();
|
||||||
if *mouse_was_outside_window {
|
if *mouse_was_outside_window {
|
||||||
|
@ -194,7 +186,7 @@ unsafe fn wnd_proc_inner(
|
||||||
*mouse_was_outside_window = false;
|
*mouse_was_outside_window = false;
|
||||||
|
|
||||||
let enter_event = Event::Mouse(MouseEvent::CursorEntered);
|
let enter_event = Event::Mouse(MouseEvent::CursorEntered);
|
||||||
handler.on_event(&mut window, enter_event);
|
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, enter_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
let x = (lparam & 0xFFFF) as i16 as i32;
|
let x = (lparam & 0xFFFF) as i16 as i32;
|
||||||
|
@ -209,13 +201,12 @@ unsafe fn wnd_proc_inner(
|
||||||
.borrow()
|
.borrow()
|
||||||
.get_modifiers_from_mouse_wparam(wparam),
|
.get_modifiers_from_mouse_wparam(wparam),
|
||||||
});
|
});
|
||||||
handler.on_event(&mut window, move_event);
|
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, move_event);
|
||||||
Some(0)
|
Some(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
WM_MOUSELEAVE => {
|
WM_MOUSELEAVE => {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
let event = Event::Mouse(MouseEvent::CursorLeft);
|
let event = Event::Mouse(MouseEvent::CursorLeft);
|
||||||
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
|
window_state.handler.borrow_mut().as_mut().unwrap().on_event(&mut window, event);
|
||||||
|
|
||||||
|
@ -223,8 +214,7 @@ unsafe fn wnd_proc_inner(
|
||||||
Some(0)
|
Some(0)
|
||||||
}
|
}
|
||||||
WM_MOUSEWHEEL | WM_MOUSEHWHEEL => {
|
WM_MOUSEWHEEL | WM_MOUSEHWHEEL => {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
let value = (wparam >> 16) as i16;
|
let value = (wparam >> 16) as i16;
|
||||||
let value = value as i32;
|
let value = value as i32;
|
||||||
|
@ -248,8 +238,7 @@ unsafe fn wnd_proc_inner(
|
||||||
}
|
}
|
||||||
WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDOWN
|
WM_LBUTTONDOWN | WM_LBUTTONUP | WM_MBUTTONDOWN | WM_MBUTTONUP | WM_RBUTTONDOWN
|
||||||
| WM_RBUTTONUP | WM_XBUTTONDOWN | WM_XBUTTONUP => {
|
| WM_RBUTTONUP | WM_XBUTTONDOWN | WM_XBUTTONUP => {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
let mut mouse_button_counter = window_state.mouse_button_counter.get();
|
let mut mouse_button_counter = window_state.mouse_button_counter.get();
|
||||||
|
|
||||||
|
@ -312,8 +301,7 @@ unsafe fn wnd_proc_inner(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
WM_TIMER => {
|
WM_TIMER => {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
if wparam == WIN_FRAME_TIMER {
|
if wparam == WIN_FRAME_TIMER {
|
||||||
window_state.handler.borrow_mut().as_mut().unwrap().on_frame(&mut window);
|
window_state.handler.borrow_mut().as_mut().unwrap().on_frame(&mut window);
|
||||||
|
@ -324,8 +312,7 @@ unsafe fn wnd_proc_inner(
|
||||||
WM_CLOSE => {
|
WM_CLOSE => {
|
||||||
// Make sure to release the borrow before the DefWindowProc call
|
// Make sure to release the borrow before the DefWindowProc call
|
||||||
{
|
{
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
window_state
|
window_state
|
||||||
.handler
|
.handler
|
||||||
|
@ -341,8 +328,7 @@ unsafe fn wnd_proc_inner(
|
||||||
}
|
}
|
||||||
WM_CHAR | WM_SYSCHAR | WM_KEYDOWN | WM_SYSKEYDOWN | WM_KEYUP | WM_SYSKEYUP
|
WM_CHAR | WM_SYSCHAR | WM_KEYDOWN | WM_SYSKEYDOWN | WM_KEYUP | WM_SYSKEYUP
|
||||||
| WM_INPUTLANGCHANGE => {
|
| WM_INPUTLANGCHANGE => {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
let opt_event =
|
let opt_event =
|
||||||
window_state.keyboard_state.borrow_mut().process_message(hwnd, msg, wparam, lparam);
|
window_state.keyboard_state.borrow_mut().process_message(hwnd, msg, wparam, lparam);
|
||||||
|
@ -363,8 +349,7 @@ unsafe fn wnd_proc_inner(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WM_SIZE => {
|
WM_SIZE => {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
let width = (lparam & 0xFFFF) as u16 as u32;
|
let width = (lparam & 0xFFFF) as u16 as u32;
|
||||||
let height = ((lparam >> 16) & 0xFFFF) as u16 as u32;
|
let height = ((lparam >> 16) & 0xFFFF) as u16 as u32;
|
||||||
|
@ -592,17 +577,6 @@ impl Window<'_> {
|
||||||
window_handle
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (window_handle, _) = Self::open(true, null_mut(), options, build);
|
|
||||||
|
|
||||||
window_handle
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
pub fn open_blocking<H, B>(options: WindowOpenOptions, build: B)
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
|
@ -691,9 +665,9 @@ impl Window<'_> {
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
let gl_context: Option<GlContext> = options.gl_config.map(|gl_config| {
|
let gl_context: Option<GlContext> = options.gl_config.map(|gl_config| {
|
||||||
let mut handle = Win32Handle::empty();
|
let mut handle = Win32WindowHandle::empty();
|
||||||
handle.hwnd = hwnd as *mut c_void;
|
handle.hwnd = hwnd as *mut c_void;
|
||||||
let handle = RawWindowHandleWrapper { handle: RawWindowHandle::Win32(handle) };
|
let handle = RawWindowHandle::Win32(handle);
|
||||||
|
|
||||||
GlContext::create(&handle, gl_config).expect("Could not create OpenGL context")
|
GlContext::create(&handle, gl_config).expect("Could not create OpenGL context")
|
||||||
});
|
});
|
||||||
|
@ -723,8 +697,7 @@ impl Window<'_> {
|
||||||
});
|
});
|
||||||
|
|
||||||
let handler = {
|
let handler = {
|
||||||
let mut window = window_state.create_window();
|
let mut window = crate::Window::new(window_state.create_window());
|
||||||
let mut window = crate::Window::new(&mut window);
|
|
||||||
|
|
||||||
build(&mut window)
|
build(&mut window)
|
||||||
};
|
};
|
||||||
|
@ -804,6 +777,10 @@ impl Window<'_> {
|
||||||
self.state.deferred_tasks.borrow_mut().push_back(task);
|
self.state.deferred_tasks.borrow_mut().push_back(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_mouse_cursor(&mut self, _mouse_cursor: MouseCursor) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
pub fn gl_context(&self) -> Option<&GlContext> {
|
pub fn gl_context(&self) -> Option<&GlContext> {
|
||||||
self.state.gl_context.as_ref()
|
self.state.gl_context.as_ref()
|
||||||
|
@ -812,13 +789,19 @@ impl Window<'_> {
|
||||||
|
|
||||||
unsafe impl HasRawWindowHandle for Window<'_> {
|
unsafe impl HasRawWindowHandle for Window<'_> {
|
||||||
fn raw_window_handle(&self) -> RawWindowHandle {
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
let mut handle = Win32Handle::empty();
|
let mut handle = Win32WindowHandle::empty();
|
||||||
handle.hwnd = self.state.hwnd as *mut c_void;
|
handle.hwnd = self.state.hwnd as *mut c_void;
|
||||||
|
|
||||||
RawWindowHandle::Win32(handle)
|
RawWindowHandle::Win32(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_to_clipboard(data: &str) {
|
unsafe impl HasRawDisplayHandle for Window<'_> {
|
||||||
|
fn raw_display_handle(&self) -> RawDisplayHandle {
|
||||||
|
RawDisplayHandle::Windows(WindowsDisplayHandle::empty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy_to_clipboard(_data: &str) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{
|
||||||
|
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::event::{Event, EventStatus};
|
use crate::event::{Event, EventStatus};
|
||||||
use crate::window_open_options::WindowOpenOptions;
|
use crate::window_open_options::WindowOpenOptions;
|
||||||
use crate::Size;
|
use crate::{MouseCursor, Size};
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use crate::macos as platform;
|
use crate::macos as platform;
|
||||||
|
@ -19,12 +21,6 @@ pub struct WindowHandle {
|
||||||
phantom: PhantomData<*mut ()>,
|
phantom: PhantomData<*mut ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quick wrapper to satisfy [HasRawWindowHandle], because of course a raw window handle wouldn't
|
|
||||||
/// have a raw window handle, that would be silly.
|
|
||||||
pub(crate) struct RawWindowHandleWrapper {
|
|
||||||
pub handle: RawWindowHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WindowHandle {
|
impl WindowHandle {
|
||||||
fn new(window_handle: platform::WindowHandle) -> Self {
|
fn new(window_handle: platform::WindowHandle) -> Self {
|
||||||
Self { window_handle, phantom: PhantomData::default() }
|
Self { window_handle, phantom: PhantomData::default() }
|
||||||
|
@ -54,10 +50,7 @@ pub trait WindowHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window<'a> {
|
pub struct Window<'a> {
|
||||||
#[cfg(target_os = "windows")]
|
window: platform::Window<'a>,
|
||||||
window: &'a mut platform::Window<'a>,
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
window: &'a mut platform::Window,
|
|
||||||
|
|
||||||
// so that Window is !Send on all platforms
|
// so that Window is !Send on all platforms
|
||||||
phantom: PhantomData<*mut ()>,
|
phantom: PhantomData<*mut ()>,
|
||||||
|
@ -65,12 +58,12 @@ pub struct Window<'a> {
|
||||||
|
|
||||||
impl<'a> Window<'a> {
|
impl<'a> Window<'a> {
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
pub(crate) fn new(window: &'a mut platform::Window<'a>) -> Window<'a> {
|
pub(crate) fn new(window: platform::Window<'a>) -> Window<'a> {
|
||||||
Window { window, phantom: PhantomData }
|
Window { window, phantom: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
pub(crate) fn new(window: &mut platform::Window) -> Window {
|
pub(crate) fn new(window: platform::Window) -> Window {
|
||||||
Window { window, phantom: PhantomData }
|
Window { window, phantom: PhantomData }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,16 +78,6 @@ impl<'a> Window<'a> {
|
||||||
WindowHandle::new(window_handle)
|
WindowHandle::new(window_handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
{
|
|
||||||
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)
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
|
@ -115,6 +98,10 @@ impl<'a> Window<'a> {
|
||||||
self.window.resize(size);
|
self.window.resize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
|
||||||
|
self.window.set_mouse_cursor(cursor);
|
||||||
|
}
|
||||||
|
|
||||||
/// If provided, then an OpenGL context will be created for this window. You'll be able to
|
/// If provided, then an OpenGL context will be created for this window. You'll be able to
|
||||||
/// access this context through [crate::Window::gl_context].
|
/// access this context through [crate::Window::gl_context].
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
|
@ -129,8 +116,8 @@ unsafe impl<'a> HasRawWindowHandle for Window<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl HasRawWindowHandle for RawWindowHandleWrapper {
|
unsafe impl<'a> HasRawDisplayHandle for Window<'a> {
|
||||||
fn raw_window_handle(&self) -> RawWindowHandle {
|
fn raw_display_handle(&self) -> RawDisplayHandle {
|
||||||
self.handle
|
self.window.raw_display_handle()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use std::marker::PhantomData;
|
use std::ffi::c_void;
|
||||||
use std::os::raw::{c_ulong, c_void};
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::*;
|
use std::time::*;
|
||||||
|
|
||||||
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle, XlibHandle};
|
use raw_window_handle::{
|
||||||
|
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle, XlibDisplayHandle,
|
||||||
|
XlibWindowHandle,
|
||||||
|
};
|
||||||
use xcb::ffi::xcb_screen_t;
|
use xcb::ffi::xcb_screen_t;
|
||||||
use xcb::StructPtr;
|
use xcb::StructPtr;
|
||||||
|
|
||||||
|
@ -19,18 +21,12 @@ use crate::{
|
||||||
use super::keyboard::{convert_key_press_event, convert_key_release_event, key_mods};
|
use super::keyboard::{convert_key_press_event, convert_key_release_event, key_mods};
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
use crate::{
|
use crate::gl::{platform, GlContext};
|
||||||
gl::{platform, GlContext},
|
|
||||||
window::RawWindowHandleWrapper,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct WindowHandle {
|
pub struct WindowHandle {
|
||||||
raw_window_handle: Option<RawWindowHandle>,
|
raw_window_handle: Option<RawWindowHandle>,
|
||||||
close_requested: Arc<AtomicBool>,
|
close_requested: Arc<AtomicBool>,
|
||||||
is_open: Arc<AtomicBool>,
|
is_open: Arc<AtomicBool>,
|
||||||
|
|
||||||
// Ensure handle is !Send
|
|
||||||
_phantom: PhantomData<*mut ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowHandle {
|
impl WindowHandle {
|
||||||
|
@ -57,7 +53,7 @@ unsafe impl HasRawWindowHandle for WindowHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RawWindowHandle::Xlib(XlibHandle::empty())
|
RawWindowHandle::Xlib(XlibWindowHandle::empty())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +71,6 @@ impl ParentHandle {
|
||||||
raw_window_handle: None,
|
raw_window_handle: None,
|
||||||
close_requested: Arc::clone(&close_requested),
|
close_requested: Arc::clone(&close_requested),
|
||||||
is_open: Arc::clone(&is_open),
|
is_open: Arc::clone(&is_open),
|
||||||
_phantom: PhantomData::default(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
(Self { close_requested, is_open }, handle)
|
(Self { close_requested, is_open }, handle)
|
||||||
|
@ -92,11 +87,11 @@ impl Drop for ParentHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window {
|
struct WindowInner {
|
||||||
xcb_connection: XcbConnection,
|
xcb_connection: XcbConnection,
|
||||||
window_id: u32,
|
window_id: u32,
|
||||||
window_info: WindowInfo,
|
window_info: WindowInfo,
|
||||||
// FIXME: There's all this mouse cursor logic but it's never actually used, is this correct?
|
visual_id: u32,
|
||||||
mouse_cursor: MouseCursor,
|
mouse_cursor: MouseCursor,
|
||||||
|
|
||||||
frame_interval: Duration,
|
frame_interval: Duration,
|
||||||
|
@ -110,6 +105,10 @@ pub struct Window {
|
||||||
gl_context: Option<GlContext>,
|
gl_context: Option<GlContext>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Window<'a> {
|
||||||
|
inner: &'a mut WindowInner,
|
||||||
|
}
|
||||||
|
|
||||||
// Hack to allow sending a RawWindowHandle between threads. Do not make public
|
// Hack to allow sending a RawWindowHandle between threads. Do not make public
|
||||||
struct SendableRwh(RawWindowHandle);
|
struct SendableRwh(RawWindowHandle);
|
||||||
|
|
||||||
|
@ -117,7 +116,7 @@ unsafe impl Send for SendableRwh {}
|
||||||
|
|
||||||
type WindowOpenResult = Result<SendableRwh, ()>;
|
type WindowOpenResult = Result<SendableRwh, ()>;
|
||||||
|
|
||||||
impl Window {
|
impl<'a> Window<'a> {
|
||||||
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
pub fn open_parented<P, H, B>(parent: &P, options: WindowOpenOptions, build: B) -> WindowHandle
|
||||||
where
|
where
|
||||||
P: HasRawWindowHandle,
|
P: HasRawWindowHandle,
|
||||||
|
@ -146,26 +145,6 @@ impl Window {
|
||||||
window_handle
|
window_handle
|
||||||
}
|
}
|
||||||
|
|
||||||
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 (tx, rx) = mpsc::sync_channel::<WindowOpenResult>(1);
|
|
||||||
|
|
||||||
let (parent_handle, mut window_handle) = ParentHandle::new();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
Self::window_thread(None, options, build, tx.clone(), Some(parent_handle));
|
|
||||||
});
|
|
||||||
|
|
||||||
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)
|
||||||
where
|
where
|
||||||
H: WindowHandler + 'static,
|
H: WindowHandler + 'static,
|
||||||
|
@ -280,10 +259,12 @@ impl Window {
|
||||||
| xcb::EVENT_MASK_BUTTON_RELEASE
|
| xcb::EVENT_MASK_BUTTON_RELEASE
|
||||||
| xcb::EVENT_MASK_KEY_PRESS
|
| xcb::EVENT_MASK_KEY_PRESS
|
||||||
| xcb::EVENT_MASK_KEY_RELEASE
|
| xcb::EVENT_MASK_KEY_RELEASE
|
||||||
| xcb::EVENT_MASK_STRUCTURE_NOTIFY,
|
| xcb::EVENT_MASK_STRUCTURE_NOTIFY
|
||||||
|
| xcb::EVENT_MASK_ENTER_WINDOW
|
||||||
|
| xcb::EVENT_MASK_LEAVE_WINDOW,
|
||||||
),
|
),
|
||||||
// As mentioend above, these two values are needed to be able to create a window
|
// As mentioned above, these two values are needed to be able to create a window
|
||||||
// with a dpeth of 32-bits when the parent window has a different depth
|
// with a depth of 32-bits when the parent window has a different depth
|
||||||
(xcb::CW_COLORMAP, colormap),
|
(xcb::CW_COLORMAP, colormap),
|
||||||
(xcb::CW_BORDER_PIXEL, 0),
|
(xcb::CW_BORDER_PIXEL, 0),
|
||||||
],
|
],
|
||||||
|
@ -323,21 +304,22 @@ impl Window {
|
||||||
// compared to when raw-gl-context was a separate crate.
|
// compared to when raw-gl-context was a separate crate.
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
let gl_context = fb_config.map(|fb_config| {
|
let gl_context = fb_config.map(|fb_config| {
|
||||||
let mut handle = XlibHandle::empty();
|
use std::ffi::c_ulong;
|
||||||
handle.window = window_id as c_ulong;
|
|
||||||
handle.display = xcb_connection.conn.get_raw_dpy() as *mut c_void;
|
let window = window_id as c_ulong;
|
||||||
let handle = RawWindowHandleWrapper { handle: RawWindowHandle::Xlib(handle) };
|
let display = xcb_connection.conn.get_raw_dpy();
|
||||||
|
|
||||||
// Because of the visual negotation we had to take some extra steps to create this context
|
// Because of the visual negotation we had to take some extra steps to create this context
|
||||||
let context = unsafe { platform::GlContext::create(&handle, fb_config) }
|
let context = unsafe { platform::GlContext::create(window, display, fb_config) }
|
||||||
.expect("Could not create OpenGL context");
|
.expect("Could not create OpenGL context");
|
||||||
GlContext::new(context)
|
GlContext::new(context)
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut window = Self {
|
let mut inner = WindowInner {
|
||||||
xcb_connection,
|
xcb_connection,
|
||||||
window_id,
|
window_id,
|
||||||
window_info,
|
window_info,
|
||||||
|
visual_id: visual,
|
||||||
mouse_cursor: MouseCursor::default(),
|
mouse_cursor: MouseCursor::default(),
|
||||||
|
|
||||||
frame_interval: Duration::from_millis(15),
|
frame_interval: Duration::from_millis(15),
|
||||||
|
@ -351,57 +333,56 @@ impl Window {
|
||||||
gl_context,
|
gl_context,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut handler = build(&mut crate::Window::new(&mut window));
|
let mut window = crate::Window::new(Window { inner: &mut inner });
|
||||||
|
|
||||||
|
let mut handler = build(&mut window);
|
||||||
|
|
||||||
// Send an initial window resized event so the user is alerted of
|
// Send an initial window resized event so the user is alerted of
|
||||||
// the correct dpi scaling.
|
// the correct dpi scaling.
|
||||||
handler.on_event(
|
handler.on_event(&mut window, Event::Window(WindowEvent::Resized(window_info)));
|
||||||
&mut crate::Window::new(&mut window),
|
|
||||||
Event::Window(WindowEvent::Resized(window_info)),
|
|
||||||
);
|
|
||||||
|
|
||||||
let _ = tx.send(Ok(SendableRwh(window.raw_window_handle())));
|
let _ = tx.send(Ok(SendableRwh(window.raw_window_handle())));
|
||||||
|
|
||||||
window.run_event_loop(&mut handler);
|
inner.run_event_loop(&mut handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
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.inner.mouse_cursor == mouse_cursor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let xid = self.xcb_connection.get_cursor_xid(mouse_cursor);
|
let xid = self.inner.xcb_connection.get_cursor_xid(mouse_cursor);
|
||||||
|
|
||||||
if xid != 0 {
|
if xid != 0 {
|
||||||
xcb::change_window_attributes(
|
xcb::change_window_attributes(
|
||||||
&self.xcb_connection.conn,
|
&self.inner.xcb_connection.conn,
|
||||||
self.window_id,
|
self.inner.window_id,
|
||||||
&[(xcb::CW_CURSOR, xid)],
|
&[(xcb::CW_CURSOR, xid)],
|
||||||
);
|
);
|
||||||
|
|
||||||
self.xcb_connection.conn.flush();
|
self.inner.xcb_connection.conn.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mouse_cursor = mouse_cursor;
|
self.inner.mouse_cursor = mouse_cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&mut self) {
|
pub fn close(&mut self) {
|
||||||
self.close_requested = true;
|
self.inner.close_requested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resize(&mut self, size: Size) {
|
pub fn resize(&mut self, size: Size) {
|
||||||
let scaling = self.window_info.scale();
|
let scaling = self.inner.window_info.scale();
|
||||||
let new_window_info = WindowInfo::from_logical_size(size, scaling);
|
let new_window_info = WindowInfo::from_logical_size(size, scaling);
|
||||||
|
|
||||||
xcb::configure_window(
|
xcb::configure_window(
|
||||||
&self.xcb_connection.conn,
|
&self.inner.xcb_connection.conn,
|
||||||
self.window_id,
|
self.inner.window_id,
|
||||||
&[
|
&[
|
||||||
(xcb::CONFIG_WINDOW_WIDTH as u16, new_window_info.physical_size().width),
|
(xcb::CONFIG_WINDOW_WIDTH as u16, new_window_info.physical_size().width),
|
||||||
(xcb::CONFIG_WINDOW_HEIGHT as u16, new_window_info.physical_size().height),
|
(xcb::CONFIG_WINDOW_HEIGHT as u16, new_window_info.physical_size().height),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
self.xcb_connection.conn.flush();
|
self.inner.xcb_connection.conn.flush();
|
||||||
|
|
||||||
// This will trigger a `ConfigureNotify` event which will in turn change `self.window_info`
|
// This will trigger a `ConfigureNotify` event which will in turn change `self.window_info`
|
||||||
// and notify the window handler about it
|
// and notify the window handler about it
|
||||||
|
@ -409,7 +390,7 @@ impl Window {
|
||||||
|
|
||||||
#[cfg(feature = "opengl")]
|
#[cfg(feature = "opengl")]
|
||||||
pub fn gl_context(&self) -> Option<&crate::gl::GlContext> {
|
pub fn gl_context(&self) -> Option<&crate::gl::GlContext> {
|
||||||
self.gl_context.as_ref()
|
self.inner.gl_context.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_visual_for_depth(screen: &StructPtr<xcb_screen_t>, depth: u8) -> Option<u32> {
|
fn find_visual_for_depth(screen: &StructPtr<xcb_screen_t>, depth: u8) -> Option<u32> {
|
||||||
|
@ -427,7 +408,9 @@ impl Window {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowInner {
|
||||||
#[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
|
||||||
|
@ -445,7 +428,7 @@ impl Window {
|
||||||
let window_info = self.window_info;
|
let window_info = self.window_info;
|
||||||
|
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
&mut crate::Window::new(self),
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
Event::Window(WindowEvent::Resized(window_info)),
|
Event::Window(WindowEvent::Resized(window_info)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -475,7 +458,7 @@ impl Window {
|
||||||
// if it's already time to draw a new frame.
|
// if it's already time to draw a new frame.
|
||||||
let next_frame = last_frame + self.frame_interval;
|
let next_frame = last_frame + self.frame_interval;
|
||||||
if Instant::now() >= next_frame {
|
if Instant::now() >= next_frame {
|
||||||
handler.on_frame(&mut crate::Window::new(self));
|
handler.on_frame(&mut crate::Window::new(Window { inner: self }));
|
||||||
last_frame = Instant::max(next_frame, Instant::now() - self.frame_interval);
|
last_frame = Instant::max(next_frame, Instant::now() - self.frame_interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,14 +504,20 @@ impl Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_close_requested(&mut self, handler: &mut dyn WindowHandler) {
|
fn handle_close_requested(&mut self, handler: &mut dyn WindowHandler) {
|
||||||
handler.on_event(&mut crate::Window::new(self), Event::Window(WindowEvent::WillClose));
|
handler.on_event(
|
||||||
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
|
Event::Window(WindowEvent::WillClose),
|
||||||
|
);
|
||||||
|
|
||||||
// FIXME: handler should decide whether window stays open or not
|
// FIXME: handler should decide whether window stays open or not
|
||||||
self.event_loop_running = false;
|
self.event_loop_running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_must_close(&mut self, handler: &mut dyn WindowHandler) {
|
fn handle_must_close(&mut self, handler: &mut dyn WindowHandler) {
|
||||||
handler.on_event(&mut crate::Window::new(self), Event::Window(WindowEvent::WillClose));
|
handler.on_event(
|
||||||
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
|
Event::Window(WindowEvent::WillClose),
|
||||||
|
);
|
||||||
|
|
||||||
self.event_loop_running = false;
|
self.event_loop_running = false;
|
||||||
}
|
}
|
||||||
|
@ -600,7 +589,7 @@ impl Window {
|
||||||
let logical_pos = physical_pos.to_logical(&self.window_info);
|
let logical_pos = physical_pos.to_logical(&self.window_info);
|
||||||
|
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
&mut crate::Window::new(self),
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
Event::Mouse(MouseEvent::CursorMoved {
|
Event::Mouse(MouseEvent::CursorMoved {
|
||||||
position: logical_pos,
|
position: logical_pos,
|
||||||
modifiers: key_mods(event.state()),
|
modifiers: key_mods(event.state()),
|
||||||
|
@ -609,6 +598,32 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xcb::ENTER_NOTIFY => {
|
||||||
|
handler.on_event(
|
||||||
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
|
Event::Mouse(MouseEvent::CursorEntered),
|
||||||
|
);
|
||||||
|
// since no `MOTION_NOTIFY` event is generated when `ENTER_NOTIFY` is generated,
|
||||||
|
// we generate a CursorMoved as well, so the mouse position from here isn't lost
|
||||||
|
let event = unsafe { xcb::cast_event::<xcb::EnterNotifyEvent>(&event) };
|
||||||
|
let physical_pos = PhyPoint::new(event.event_x() as i32, event.event_y() as i32);
|
||||||
|
let logical_pos = physical_pos.to_logical(&self.window_info);
|
||||||
|
handler.on_event(
|
||||||
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
|
Event::Mouse(MouseEvent::CursorMoved {
|
||||||
|
position: logical_pos,
|
||||||
|
modifiers: key_mods(event.state()),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb::LEAVE_NOTIFY => {
|
||||||
|
handler.on_event(
|
||||||
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
|
Event::Mouse(MouseEvent::CursorLeft),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
xcb::BUTTON_PRESS => {
|
xcb::BUTTON_PRESS => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
@ -616,7 +631,7 @@ impl Window {
|
||||||
match detail {
|
match detail {
|
||||||
4..=7 => {
|
4..=7 => {
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
&mut crate::Window::new(self),
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
Event::Mouse(MouseEvent::WheelScrolled {
|
Event::Mouse(MouseEvent::WheelScrolled {
|
||||||
delta: match detail {
|
delta: match detail {
|
||||||
4 => ScrollDelta::Lines { x: 0.0, y: 1.0 },
|
4 => ScrollDelta::Lines { x: 0.0, y: 1.0 },
|
||||||
|
@ -632,7 +647,7 @@ impl Window {
|
||||||
detail => {
|
detail => {
|
||||||
let button_id = mouse_id(detail);
|
let button_id = mouse_id(detail);
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
&mut crate::Window::new(self),
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
Event::Mouse(MouseEvent::ButtonPressed {
|
Event::Mouse(MouseEvent::ButtonPressed {
|
||||||
button: button_id,
|
button: button_id,
|
||||||
modifiers: key_mods(event.state()),
|
modifiers: key_mods(event.state()),
|
||||||
|
@ -649,7 +664,7 @@ impl Window {
|
||||||
if !(4..=7).contains(&detail) {
|
if !(4..=7).contains(&detail) {
|
||||||
let button_id = mouse_id(detail);
|
let button_id = mouse_id(detail);
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
&mut crate::Window::new(self),
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
Event::Mouse(MouseEvent::ButtonReleased {
|
Event::Mouse(MouseEvent::ButtonReleased {
|
||||||
button: button_id,
|
button: button_id,
|
||||||
modifiers: key_mods(event.state()),
|
modifiers: key_mods(event.state()),
|
||||||
|
@ -665,7 +680,7 @@ impl Window {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
||||||
|
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
&mut crate::Window::new(self),
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
Event::Keyboard(convert_key_press_event(event)),
|
Event::Keyboard(convert_key_press_event(event)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -674,7 +689,7 @@ impl Window {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
||||||
|
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
&mut crate::Window::new(self),
|
&mut crate::Window::new(Window { inner: self }),
|
||||||
Event::Keyboard(convert_key_release_event(event)),
|
Event::Keyboard(convert_key_release_event(event)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -684,16 +699,29 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl HasRawWindowHandle for Window {
|
unsafe impl<'a> HasRawWindowHandle for Window<'a> {
|
||||||
fn raw_window_handle(&self) -> RawWindowHandle {
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
let mut handle = XlibHandle::empty();
|
let mut handle = XlibWindowHandle::empty();
|
||||||
handle.window = self.window_id as c_ulong;
|
|
||||||
handle.display = self.xcb_connection.conn.get_raw_dpy() as *mut c_void;
|
handle.window = self.inner.window_id.into();
|
||||||
|
handle.visual_id = self.inner.visual_id.into();
|
||||||
|
|
||||||
RawWindowHandle::Xlib(handle)
|
RawWindowHandle::Xlib(handle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<'a> HasRawDisplayHandle for Window<'a> {
|
||||||
|
fn raw_display_handle(&self) -> RawDisplayHandle {
|
||||||
|
let display = self.inner.xcb_connection.conn.get_raw_dpy();
|
||||||
|
let mut handle = XlibDisplayHandle::empty();
|
||||||
|
|
||||||
|
handle.display = display as *mut c_void;
|
||||||
|
handle.screen = unsafe { x11::xlib::XDefaultScreen(display) };
|
||||||
|
|
||||||
|
RawDisplayHandle::Xlib(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn mouse_id(id: u8) -> MouseButton {
|
fn mouse_id(id: u8) -> MouseButton {
|
||||||
match id {
|
match id {
|
||||||
1 => MouseButton::Left,
|
1 => MouseButton::Left,
|
||||||
|
@ -705,6 +733,6 @@ fn mouse_id(id: u8) -> MouseButton {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy_to_clipboard(data: &str) {
|
pub fn copy_to_clipboard(_data: &str) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ pub struct XcbConnection {
|
||||||
|
|
||||||
pub(crate) atoms: Atoms,
|
pub(crate) atoms: Atoms,
|
||||||
|
|
||||||
// FIXME: Same here, there's a ton of unused cursor machinery in here
|
|
||||||
pub(super) cursor_cache: HashMap<MouseCursor, u32>,
|
pub(super) cursor_cache: HashMap<MouseCursor, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue