Merge pull request #39 from glowcoil/window
API refactors: pass Window to AppWindow and introduce WindowHandle
This commit is contained in:
commit
23af18020e
|
@ -1,6 +1,4 @@
|
||||||
use std::sync::mpsc;
|
use baseview::{Event, Window, WindowHandler};
|
||||||
|
|
||||||
use baseview::Event;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let window_open_options = baseview::WindowOpenOptions {
|
let window_open_options = baseview::WindowOpenOptions {
|
||||||
|
@ -10,25 +8,21 @@ fn main() {
|
||||||
parent: baseview::Parent::None,
|
parent: baseview::Parent::None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_app_message_tx, app_message_rx) = mpsc::channel::<()>();
|
let _handle = Window::open::<MyProgram>(window_open_options);
|
||||||
|
|
||||||
// Send _app_message_tx to a separate thread, then send messages to the GUI thread.
|
|
||||||
|
|
||||||
let _ = baseview::Window::<MyProgram>::open(window_open_options, app_message_rx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MyProgram {}
|
struct MyProgram {}
|
||||||
|
|
||||||
impl baseview::AppWindow for MyProgram {
|
impl WindowHandler for MyProgram {
|
||||||
type AppMessage = ();
|
type Message = ();
|
||||||
|
|
||||||
fn build(_window_handle: baseview::RawWindow, window_info: &baseview::WindowInfo) -> Self {
|
fn build(window: &mut Window) -> Self {
|
||||||
println!("Window info: {:?}", window_info);
|
|
||||||
Self {}
|
Self {}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(&mut self) {}
|
fn draw(&mut self, window: &mut Window) {}
|
||||||
|
|
||||||
fn on_event(&mut self, event: Event) {
|
fn on_event(&mut self, window: &mut Window, event: Event) {
|
||||||
match event {
|
match event {
|
||||||
Event::CursorMotion(x, y) => {
|
Event::CursorMotion(x, y) => {
|
||||||
println!("Cursor moved, x: {}, y: {}", x, y);
|
println!("Cursor moved, x: {}, y: {}", x, y);
|
||||||
|
@ -69,5 +63,5 @@ impl baseview::AppWindow for MyProgram {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_app_message(&mut self, _message: Self::AppMessage) {}
|
fn on_message(&mut self, window: &mut Window, _message: Self::Message) {}
|
||||||
}
|
}
|
||||||
|
|
24
src/lib.rs
24
src/lib.rs
|
@ -33,24 +33,12 @@ pub struct WindowOpenOptions<'a> {
|
||||||
pub parent: Parent,
|
pub parent: Parent,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AppWindow {
|
pub trait WindowHandler {
|
||||||
type AppMessage;
|
type Message;
|
||||||
|
|
||||||
fn build(window_handle: RawWindow, window_info: &WindowInfo) -> Self;
|
fn build(window: &mut Window) -> Self;
|
||||||
|
|
||||||
fn draw(&mut self);
|
fn draw(&mut self, window: &mut Window);
|
||||||
fn on_event(&mut self, event: Event);
|
fn on_event(&mut self, window: &mut Window, event: Event);
|
||||||
fn on_app_message(&mut self, message: Self::AppMessage);
|
fn on_message(&mut self, window: &mut Window, message: Self::Message);
|
||||||
}
|
|
||||||
|
|
||||||
/// A wrapper for a `RawWindowHandle`. Some context creators expect an `&impl HasRawWindowHandle`.
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub struct RawWindow {
|
|
||||||
pub raw_window_handle: raw_window_handle::RawWindowHandle,
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe impl raw_window_handle::HasRawWindowHandle for RawWindow {
|
|
||||||
fn raw_window_handle(&self) -> raw_window_handle::RawWindowHandle {
|
|
||||||
self.raw_window_handle
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +1,24 @@
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::sync::mpsc;
|
|
||||||
|
|
||||||
use cocoa::appkit::{
|
use cocoa::appkit::{
|
||||||
NSApp, NSApplication, NSApplicationActivateIgnoringOtherApps,
|
NSApp, NSApplication, NSApplicationActivateIgnoringOtherApps,
|
||||||
NSApplicationActivationPolicyRegular, NSBackingStoreBuffered, NSRunningApplication, NSView,
|
NSApplicationActivationPolicyRegular, NSBackingStoreBuffered, NSRunningApplication, NSView,
|
||||||
NSWindow, NSWindowStyleMask,
|
NSWindow, NSWindowStyleMask,
|
||||||
};
|
};
|
||||||
use cocoa::base::{nil, NO};
|
use cocoa::base::{id, nil, NO};
|
||||||
use cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString};
|
use cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString};
|
||||||
|
|
||||||
use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{macos::MacOSHandle, HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
use crate::{
|
use crate::{MouseScroll, WindowHandler, WindowOpenOptions};
|
||||||
AppWindow, Event, MouseButtonID, MouseScroll, RawWindow, WindowInfo, WindowOpenOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct Window<A: AppWindow> {
|
pub struct Window {
|
||||||
app_window: A,
|
ns_window: id,
|
||||||
app_message_rx: mpsc::Receiver<A::AppMessage>,
|
ns_view: id,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AppWindow> Window<A> {
|
impl Window {
|
||||||
pub fn open(options: WindowOpenOptions, app_message_rx: mpsc::Receiver<A::AppMessage>) -> Self {
|
pub fn open<H: WindowHandler>(options: WindowOpenOptions) -> WindowHandle {
|
||||||
unsafe {
|
unsafe {
|
||||||
let _pool = NSAutoreleasePool::new(nil);
|
let _pool = NSAutoreleasePool::new(nil);
|
||||||
|
|
||||||
|
@ -33,7 +30,7 @@ impl<A: AppWindow> Window<A> {
|
||||||
NSSize::new(options.width as f64, options.height as f64),
|
NSSize::new(options.width as f64, options.height as f64),
|
||||||
);
|
);
|
||||||
|
|
||||||
let window = NSWindow::alloc(nil)
|
let ns_window = NSWindow::alloc(nil)
|
||||||
.initWithContentRect_styleMask_backing_defer_(
|
.initWithContentRect_styleMask_backing_defer_(
|
||||||
rect,
|
rect,
|
||||||
NSWindowStyleMask::NSTitledWindowMask,
|
NSWindowStyleMask::NSTitledWindowMask,
|
||||||
|
@ -41,37 +38,34 @@ impl<A: AppWindow> Window<A> {
|
||||||
NO,
|
NO,
|
||||||
)
|
)
|
||||||
.autorelease();
|
.autorelease();
|
||||||
window.center();
|
ns_window.center();
|
||||||
window.setTitle_(NSString::alloc(nil).init_str(options.title));
|
ns_window.setTitle_(NSString::alloc(nil).init_str(options.title));
|
||||||
window.makeKeyAndOrderFront_(nil);
|
ns_window.makeKeyAndOrderFront_(nil);
|
||||||
|
|
||||||
let view = NSView::alloc(nil).init();
|
let ns_view = NSView::alloc(nil).init();
|
||||||
window.setContentView_(view);
|
ns_window.setContentView_(ns_view);
|
||||||
|
|
||||||
let raw_window = RawWindow {
|
let mut window = Window { ns_window, ns_view };
|
||||||
raw_window_handle: RawWindowHandle::MacOS(MacOSHandle {
|
|
||||||
ns_window: window as *mut c_void,
|
|
||||||
ns_view: app as *mut c_void,
|
|
||||||
..raw_window_handle::macos::MacOSHandle::empty()
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
let window_info = WindowInfo {
|
let handler = H::build(&mut window);
|
||||||
width: options.width as u32,
|
|
||||||
height: options.height as u32,
|
|
||||||
scale: 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let app_window = A::build(raw_window, &window_info);
|
|
||||||
|
|
||||||
let current_app = NSRunningApplication::currentApplication(nil);
|
let current_app = NSRunningApplication::currentApplication(nil);
|
||||||
current_app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps);
|
current_app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps);
|
||||||
app.run();
|
app.run();
|
||||||
|
|
||||||
Window {
|
WindowHandle
|
||||||
app_window,
|
|
||||||
app_message_rx,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl HasRawWindowHandle for Window {
|
||||||
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
|
RawWindowHandle::MacOS(MacOSHandle {
|
||||||
|
ns_window: self.ns_window as *mut c_void,
|
||||||
|
ns_view: self.ns_view as *mut c_void,
|
||||||
|
..MacOSHandle::empty()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WindowHandle;
|
||||||
|
|
|
@ -6,18 +6,19 @@ use winapi::um::winuser::{
|
||||||
AdjustWindowRectEx, CreateWindowExA, DefWindowProcA, DestroyWindow, DispatchMessageA,
|
AdjustWindowRectEx, CreateWindowExA, DefWindowProcA, DestroyWindow, DispatchMessageA,
|
||||||
GetMessageA, GetWindowLongPtrA, MessageBoxA, PostMessageA, RegisterClassA, SetTimer,
|
GetMessageA, GetWindowLongPtrA, MessageBoxA, PostMessageA, RegisterClassA, SetTimer,
|
||||||
SetWindowLongPtrA, TranslateMessage, UnregisterClassA, CS_OWNDC, GWLP_USERDATA, MB_ICONERROR,
|
SetWindowLongPtrA, TranslateMessage, UnregisterClassA, CS_OWNDC, GWLP_USERDATA, MB_ICONERROR,
|
||||||
MB_OK, MB_TOPMOST, MSG, WM_CREATE, WM_MOUSEMOVE, WM_PAINT, WM_SHOWWINDOW, WM_TIMER, WNDCLASSA,
|
MB_OK, MB_TOPMOST, MSG, WM_CLOSE, WM_CREATE, WM_MOUSEMOVE, WM_PAINT, WM_SHOWWINDOW, WM_TIMER,
|
||||||
WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX, WS_POPUPWINDOW,
|
WNDCLASSA, WS_CAPTION, WS_CHILD, WS_CLIPSIBLINGS, WS_MAXIMIZEBOX, WS_MINIMIZEBOX,
|
||||||
WS_SIZEBOX, WS_VISIBLE,
|
WS_POPUPWINDOW, WS_SIZEBOX, WS_VISIBLE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::ptr::null_mut;
|
use std::ptr::null_mut;
|
||||||
use std::sync::mpsc;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
use crate::{AppWindow, Event, Parent::WithParent, RawWindow, WindowInfo, WindowOpenOptions};
|
use raw_window_handle::{windows::WindowsHandle, HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
|
use crate::{Event, Parent::WithParent, WindowHandler, WindowInfo, WindowOpenOptions};
|
||||||
|
|
||||||
unsafe fn message_box(title: &str, msg: &str) {
|
unsafe fn message_box(title: &str, msg: &str) {
|
||||||
let title = (title.to_owned() + "\0").as_ptr() as *const i8;
|
let title = (title.to_owned() + "\0").as_ptr() as *const i8;
|
||||||
|
@ -46,14 +47,14 @@ unsafe fn generate_guid() -> String {
|
||||||
|
|
||||||
const WIN_FRAME_TIMER: usize = 4242;
|
const WIN_FRAME_TIMER: usize = 4242;
|
||||||
|
|
||||||
unsafe fn handle_timer<A: AppWindow>(win: &RefCell<Window<A>>, timer_id: usize) {
|
unsafe fn handle_timer<H: WindowHandler>(window_state: &RefCell<WindowState<H>>, timer_id: usize) {
|
||||||
match timer_id {
|
match timer_id {
|
||||||
WIN_FRAME_TIMER => {}
|
WIN_FRAME_TIMER => {}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "system" fn wnd_proc<A: AppWindow>(
|
unsafe extern "system" fn wnd_proc<H: WindowHandler>(
|
||||||
hwnd: HWND,
|
hwnd: HWND,
|
||||||
msg: UINT,
|
msg: UINT,
|
||||||
wparam: WPARAM,
|
wparam: WPARAM,
|
||||||
|
@ -66,22 +67,33 @@ unsafe extern "system" fn wnd_proc<A: AppWindow>(
|
||||||
|
|
||||||
let win_ptr = GetWindowLongPtrA(hwnd, GWLP_USERDATA) as *const c_void;
|
let win_ptr = GetWindowLongPtrA(hwnd, GWLP_USERDATA) as *const c_void;
|
||||||
if !win_ptr.is_null() {
|
if !win_ptr.is_null() {
|
||||||
let win = &*(win_ptr as *const RefCell<Window<A>>);
|
let window_state = &*(win_ptr as *const RefCell<WindowState<H>>);
|
||||||
|
let mut window = Window { hwnd };
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
WM_MOUSEMOVE => {
|
WM_MOUSEMOVE => {
|
||||||
let x = (lparam & 0xFFFF) as i32;
|
let x = (lparam & 0xFFFF) as i32;
|
||||||
let y = ((lparam >> 16) & 0xFFFF) as i32;
|
let y = ((lparam >> 16) & 0xFFFF) as i32;
|
||||||
win.borrow_mut().handle_mouse_motion(x, y);
|
window_state
|
||||||
|
.borrow_mut()
|
||||||
|
.handler
|
||||||
|
.on_event(&mut window, Event::CursorMotion(x, y));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
WM_TIMER => {
|
WM_TIMER => {
|
||||||
handle_timer(&win, wparam);
|
handle_timer(&window_state, wparam);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
WM_PAINT => {
|
WM_PAINT => {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
WM_CLOSE => {
|
||||||
|
window_state
|
||||||
|
.borrow_mut()
|
||||||
|
.handler
|
||||||
|
.on_event(&mut window, Event::WillClose);
|
||||||
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,13 +101,13 @@ unsafe extern "system" fn wnd_proc<A: AppWindow>(
|
||||||
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn register_wnd_class<A: AppWindow>() -> ATOM {
|
unsafe fn register_wnd_class<H: WindowHandler>() -> ATOM {
|
||||||
// We generate a unique name for the new window class to prevent name collisions
|
// We generate a unique name for the new window class to prevent name collisions
|
||||||
let class_name = format!("Baseview-{}", generate_guid()).as_ptr() as *const i8;
|
let class_name = format!("Baseview-{}", generate_guid()).as_ptr() as *const i8;
|
||||||
|
|
||||||
let wnd_class = WNDCLASSA {
|
let wnd_class = WNDCLASSA {
|
||||||
style: CS_OWNDC,
|
style: CS_OWNDC,
|
||||||
lpfnWndProc: Some(wnd_proc::<A>),
|
lpfnWndProc: Some(wnd_proc::<H>),
|
||||||
hInstance: null_mut(),
|
hInstance: null_mut(),
|
||||||
lpszClassName: class_name,
|
lpszClassName: class_name,
|
||||||
cbClsExtra: 0,
|
cbClsExtra: 0,
|
||||||
|
@ -113,20 +125,22 @@ unsafe fn unregister_wnd_class(wnd_class: ATOM) {
|
||||||
UnregisterClassA(wnd_class as _, null_mut());
|
UnregisterClassA(wnd_class as _, null_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Window<A: AppWindow> {
|
struct WindowState<H> {
|
||||||
pub(crate) hwnd: HWND,
|
|
||||||
window_class: ATOM,
|
window_class: ATOM,
|
||||||
app_window: A,
|
|
||||||
app_message_rx: mpsc::Receiver<A::AppMessage>,
|
|
||||||
scaling: Option<f64>, // DPI scale, 96.0 is "default".
|
scaling: Option<f64>, // DPI scale, 96.0 is "default".
|
||||||
|
handler: H,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AppWindow> Window<A> {
|
pub struct Window {
|
||||||
pub fn open(options: WindowOpenOptions, app_message_rx: mpsc::Receiver<A::AppMessage>) {
|
hwnd: HWND,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Window {
|
||||||
|
pub fn open<H: WindowHandler>(options: WindowOpenOptions) -> WindowHandle {
|
||||||
unsafe {
|
unsafe {
|
||||||
let title = (options.title.to_owned() + "\0").as_ptr() as *const i8;
|
let title = (options.title.to_owned() + "\0").as_ptr() as *const i8;
|
||||||
|
|
||||||
let window_class = register_wnd_class::<A>();
|
let window_class = register_wnd_class::<H>();
|
||||||
// todo: manage error ^
|
// todo: manage error ^
|
||||||
|
|
||||||
let mut flags = WS_POPUPWINDOW
|
let mut flags = WS_POPUPWINDOW
|
||||||
|
@ -170,28 +184,15 @@ impl<A: AppWindow> Window<A> {
|
||||||
);
|
);
|
||||||
// todo: manage error ^
|
// todo: manage error ^
|
||||||
|
|
||||||
let mut windows_handle = raw_window_handle::windows::WindowsHandle::empty();
|
let mut window = Window { hwnd };
|
||||||
windows_handle.hwnd = hwnd as *mut std::ffi::c_void;
|
|
||||||
|
|
||||||
let raw_window = RawWindow {
|
let handler = H::build(&mut window);
|
||||||
raw_window_handle: raw_window_handle::RawWindowHandle::Windows(windows_handle),
|
|
||||||
};
|
|
||||||
|
|
||||||
let window_info = WindowInfo {
|
let window_state = Rc::new(RefCell::new(WindowState {
|
||||||
width: options.width as u32,
|
|
||||||
height: options.height as u32,
|
|
||||||
scale: 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
let app_window = A::build(raw_window, &window_info);
|
|
||||||
|
|
||||||
let window = Window {
|
|
||||||
hwnd,
|
|
||||||
window_class,
|
window_class,
|
||||||
app_window,
|
|
||||||
app_message_rx,
|
|
||||||
scaling: None,
|
scaling: None,
|
||||||
};
|
handler,
|
||||||
|
}));
|
||||||
|
|
||||||
let win = Rc::new(RefCell::new(window));
|
let win = Rc::new(RefCell::new(window));
|
||||||
|
|
||||||
|
@ -212,19 +213,18 @@ impl<A: AppWindow> Window<A> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close(&mut self) {
|
WindowHandle
|
||||||
self.app_window.on_event(Event::WillClose);
|
|
||||||
|
|
||||||
// todo: see https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L402
|
|
||||||
unsafe {
|
|
||||||
DestroyWindow(self.hwnd);
|
|
||||||
unregister_wnd_class(self.window_class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn handle_mouse_motion(&mut self, x: i32, y: i32) {
|
|
||||||
self.app_window.on_event(Event::CursorMotion(x, y));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl HasRawWindowHandle for Window {
|
||||||
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
|
RawWindowHandle::Windows(WindowsHandle {
|
||||||
|
hwnd: self.hwnd as *mut std::ffi::c_void,
|
||||||
|
..WindowsHandle::empty()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct WindowHandle;
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::os::raw::{c_ulong, c_void};
|
use std::os::raw::{c_ulong, c_void};
|
||||||
use std::sync::mpsc;
|
|
||||||
|
|
||||||
use super::XcbConnection;
|
use super::XcbConnection;
|
||||||
use crate::{
|
use crate::{Event, MouseButtonID, MouseScroll, Parent, WindowHandler, WindowOpenOptions};
|
||||||
AppWindow, Event, MouseButtonID, MouseScroll, Parent, RawWindow, WindowInfo, WindowOpenOptions,
|
|
||||||
};
|
|
||||||
|
|
||||||
use raw_window_handle::RawWindowHandle;
|
use raw_window_handle::{unix::XlibHandle, HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
pub struct Window<A: AppWindow> {
|
pub struct Window {
|
||||||
scaling: f64,
|
|
||||||
xcb_connection: XcbConnection,
|
xcb_connection: XcbConnection,
|
||||||
app_window: A,
|
window_id: u32,
|
||||||
app_message_rx: mpsc::Receiver<A::AppMessage>,
|
scaling: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: AppWindow> Window<A> {
|
impl Window {
|
||||||
pub fn open(options: WindowOpenOptions, app_message_rx: mpsc::Receiver<A::AppMessage>) -> Self {
|
pub fn open<H: WindowHandler>(options: WindowOpenOptions) -> WindowHandle {
|
||||||
// Convert the parent to a X11 window ID if we're given one
|
// Convert the parent to a X11 window ID if we're given one
|
||||||
let parent = match options.parent {
|
let parent = match options.parent {
|
||||||
Parent::None => None,
|
Parent::None => None,
|
||||||
|
@ -93,131 +89,130 @@ impl<A: AppWindow> Window<A> {
|
||||||
|
|
||||||
xcb_connection.conn.flush();
|
xcb_connection.conn.flush();
|
||||||
|
|
||||||
let raw_handle = RawWindowHandle::Xlib(raw_window_handle::unix::XlibHandle {
|
|
||||||
window: window_id as c_ulong,
|
|
||||||
display: xcb_connection.conn.get_raw_dpy() as *mut c_void,
|
|
||||||
..raw_window_handle::unix::XlibHandle::empty()
|
|
||||||
});
|
|
||||||
|
|
||||||
let raw_window = RawWindow {
|
|
||||||
raw_window_handle: raw_handle,
|
|
||||||
};
|
|
||||||
|
|
||||||
let scaling = get_scaling_xft(&xcb_connection)
|
let scaling = get_scaling_xft(&xcb_connection)
|
||||||
.or(get_scaling_screen_dimensions(&xcb_connection))
|
.or(get_scaling_screen_dimensions(&xcb_connection))
|
||||||
.unwrap_or(1.0);
|
.unwrap_or(1.0);
|
||||||
|
|
||||||
let window_info = WindowInfo {
|
let mut window = Self {
|
||||||
width: options.width as u32,
|
|
||||||
height: options.height as u32,
|
|
||||||
scale: scaling,
|
|
||||||
};
|
|
||||||
|
|
||||||
let app_window = A::build(raw_window, &window_info);
|
|
||||||
|
|
||||||
let mut x11_window = Self {
|
|
||||||
scaling,
|
|
||||||
xcb_connection,
|
xcb_connection,
|
||||||
app_window,
|
window_id,
|
||||||
app_message_rx,
|
scaling,
|
||||||
};
|
};
|
||||||
|
|
||||||
x11_window.run_event_loop();
|
let mut handler = H::build(&mut window);
|
||||||
|
|
||||||
x11_window
|
run_event_loop(&mut window, &mut handler);
|
||||||
|
|
||||||
|
WindowHandle
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Event loop
|
unsafe impl HasRawWindowHandle for Window {
|
||||||
fn run_event_loop(&mut self) {
|
fn raw_window_handle(&self) -> RawWindowHandle {
|
||||||
loop {
|
RawWindowHandle::Xlib(XlibHandle {
|
||||||
// somehow poll self.app_message_rx for messages at the same time
|
window: self.window_id as c_ulong,
|
||||||
|
display: self.xcb_connection.conn.get_raw_dpy() as *mut c_void,
|
||||||
|
..raw_window_handle::unix::XlibHandle::empty()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let ev = self.xcb_connection.conn.wait_for_event();
|
pub struct WindowHandle;
|
||||||
if let Some(event) = ev {
|
|
||||||
let event_type = event.response_type() & !0x80;
|
|
||||||
|
|
||||||
// For all of the keyboard and mouse events, you can fetch
|
// Event loop
|
||||||
// `x`, `y`, `detail`, and `state`.
|
fn run_event_loop<H: WindowHandler>(window: &mut Window, handler: &mut H) {
|
||||||
// - `x` and `y` are the position inside the window where the cursor currently is
|
loop {
|
||||||
// when the event happened.
|
let ev = window.xcb_connection.conn.wait_for_event();
|
||||||
// - `detail` will tell you which keycode was pressed/released (for keyboard events)
|
if let Some(event) = ev {
|
||||||
// or which mouse button was pressed/released (for mouse events).
|
let event_type = event.response_type() & !0x80;
|
||||||
// For mouse events, here's what the value means (at least on my current mouse):
|
|
||||||
// 1 = left mouse button
|
|
||||||
// 2 = middle mouse button (scroll wheel)
|
|
||||||
// 3 = right mouse button
|
|
||||||
// 4 = scroll wheel up
|
|
||||||
// 5 = scroll wheel down
|
|
||||||
// 8 = lower side button ("back" button)
|
|
||||||
// 9 = upper side button ("forward" button)
|
|
||||||
// Note that you *will* get a "button released" event for even the scroll wheel
|
|
||||||
// events, which you can probably ignore.
|
|
||||||
// - `state` will tell you the state of the main three mouse buttons and some of
|
|
||||||
// the keyboard modifier keys at the time of the event.
|
|
||||||
// http://rtbo.github.io/rust-xcb/src/xcb/ffi/xproto.rs.html#445
|
|
||||||
|
|
||||||
match event_type {
|
// For all of the keyboard and mouse events, you can fetch
|
||||||
xcb::EXPOSE => {
|
// `x`, `y`, `detail`, and `state`.
|
||||||
self.app_window.draw();
|
// - `x` and `y` are the position inside the window where the cursor currently is
|
||||||
|
// when the event happened.
|
||||||
|
// - `detail` will tell you which keycode was pressed/released (for keyboard events)
|
||||||
|
// or which mouse button was pressed/released (for mouse events).
|
||||||
|
// For mouse events, here's what the value means (at least on my current mouse):
|
||||||
|
// 1 = left mouse button
|
||||||
|
// 2 = middle mouse button (scroll wheel)
|
||||||
|
// 3 = right mouse button
|
||||||
|
// 4 = scroll wheel up
|
||||||
|
// 5 = scroll wheel down
|
||||||
|
// 8 = lower side button ("back" button)
|
||||||
|
// 9 = upper side button ("forward" button)
|
||||||
|
// Note that you *will* get a "button released" event for even the scroll wheel
|
||||||
|
// events, which you can probably ignore.
|
||||||
|
// - `state` will tell you the state of the main three mouse buttons and some of
|
||||||
|
// the keyboard modifier keys at the time of the event.
|
||||||
|
// http://rtbo.github.io/rust-xcb/src/xcb/ffi/xproto.rs.html#445
|
||||||
|
|
||||||
|
match event_type {
|
||||||
|
xcb::EXPOSE => {
|
||||||
|
handler.draw(window);
|
||||||
|
}
|
||||||
|
xcb::MOTION_NOTIFY => {
|
||||||
|
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
|
||||||
|
let detail = event.detail();
|
||||||
|
|
||||||
|
if detail != 4 && detail != 5 {
|
||||||
|
handler.on_event(
|
||||||
|
window,
|
||||||
|
Event::CursorMotion(event.event_x() as i32, event.event_y() as i32),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
xcb::MOTION_NOTIFY => {
|
}
|
||||||
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
|
xcb::BUTTON_PRESS => {
|
||||||
let detail = event.detail();
|
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
||||||
|
let detail = event.detail();
|
||||||
|
|
||||||
if detail != 4 && detail != 5 {
|
match detail {
|
||||||
self.app_window.on_event(Event::CursorMotion(
|
4 => {
|
||||||
event.event_x() as i32,
|
handler.on_event(
|
||||||
event.event_y() as i32,
|
window,
|
||||||
));
|
Event::MouseScroll(MouseScroll {
|
||||||
}
|
|
||||||
}
|
|
||||||
xcb::BUTTON_PRESS => {
|
|
||||||
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
|
||||||
let detail = event.detail();
|
|
||||||
|
|
||||||
match detail {
|
|
||||||
4 => {
|
|
||||||
self.app_window.on_event(Event::MouseScroll(MouseScroll {
|
|
||||||
x_delta: 0.0,
|
x_delta: 0.0,
|
||||||
y_delta: 1.0,
|
y_delta: 1.0,
|
||||||
}));
|
}),
|
||||||
}
|
);
|
||||||
5 => {
|
}
|
||||||
self.app_window.on_event(Event::MouseScroll(MouseScroll {
|
5 => {
|
||||||
|
handler.on_event(
|
||||||
|
window,
|
||||||
|
Event::MouseScroll(MouseScroll {
|
||||||
x_delta: 0.0,
|
x_delta: 0.0,
|
||||||
y_delta: -1.0,
|
y_delta: -1.0,
|
||||||
}));
|
}),
|
||||||
}
|
);
|
||||||
detail => {
|
|
||||||
let button_id = mouse_id(detail);
|
|
||||||
self.app_window.on_event(Event::MouseDown(button_id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
detail => {
|
||||||
xcb::BUTTON_RELEASE => {
|
|
||||||
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
|
||||||
let detail = event.detail();
|
|
||||||
|
|
||||||
if detail != 4 && detail != 5 {
|
|
||||||
let button_id = mouse_id(detail);
|
let button_id = mouse_id(detail);
|
||||||
self.app_window.on_event(Event::MouseUp(button_id));
|
handler.on_event(window, Event::MouseDown(button_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xcb::KEY_PRESS => {
|
}
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
xcb::BUTTON_RELEASE => {
|
||||||
let detail = event.detail();
|
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
||||||
|
let detail = event.detail();
|
||||||
|
|
||||||
self.app_window.on_event(Event::KeyDown(detail));
|
if detail != 4 && detail != 5 {
|
||||||
|
let button_id = mouse_id(detail);
|
||||||
|
handler.on_event(window, Event::MouseUp(button_id));
|
||||||
}
|
}
|
||||||
xcb::KEY_RELEASE => {
|
}
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
xcb::KEY_PRESS => {
|
||||||
let detail = event.detail();
|
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
||||||
|
let detail = event.detail();
|
||||||
|
|
||||||
self.app_window.on_event(Event::KeyUp(detail));
|
handler.on_event(window, Event::KeyDown(detail));
|
||||||
}
|
}
|
||||||
_ => {
|
xcb::KEY_RELEASE => {
|
||||||
println!("Unhandled event type: {:?}", event_type);
|
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
||||||
}
|
let detail = event.detail();
|
||||||
|
|
||||||
|
handler.on_event(window, Event::KeyUp(detail));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
println!("Unhandled event type: {:?}", event_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue