commit
877c913a0c
|
@ -15,7 +15,7 @@ impl WindowHandler for MyProgram {
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(e) => println!("Mouse event: {:?}", e),
|
Event::Mouse(e) => println!("Mouse event: {:?}", e),
|
||||||
Event::Keyboard(e) => println!("Keyboard event: {:?}", e),
|
Event::Keyboard(e) => println!("Keyboard event: {:?}", e),
|
||||||
Event::Window(e) => println!("Window event: {:?}", e)
|
Event::Window(e) => println!("Window event: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,5 +91,5 @@ pub enum WindowEvent {
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
Mouse(MouseEvent),
|
Mouse(MouseEvent),
|
||||||
Keyboard(KeyboardEvent),
|
Keyboard(KeyboardEvent),
|
||||||
Window(WindowEvent)
|
Window(WindowEvent),
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,8 @@ 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::{
|
||||||
Event, KeyboardEvent, MouseButton, MouseEvent, ScrollDelta, WindowEvent,
|
Event, KeyboardEvent, MouseButton, MouseEvent, ScrollDelta, WindowEvent, WindowHandler,
|
||||||
WindowHandler, WindowOpenOptions,
|
WindowOpenOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
|
|
@ -19,8 +19,8 @@ use std::rc::Rc;
|
||||||
use raw_window_handle::{windows::WindowsHandle, HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{windows::WindowsHandle, HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, KeyboardEvent, MouseButton, MouseEvent, Parent::WithParent, ScrollDelta,
|
Event, KeyboardEvent, MouseButton, MouseEvent, Parent::WithParent, ScrollDelta, WindowEvent,
|
||||||
WindowEvent, WindowHandler, WindowInfo, WindowOpenOptions,
|
WindowHandler, WindowInfo, WindowOpenOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe fn message_box(title: &str, msg: &str) {
|
unsafe fn message_box(title: &str, msg: &str) {
|
||||||
|
@ -142,7 +142,7 @@ pub struct Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct WindowHandle {
|
pub struct WindowHandle {
|
||||||
hwnd: HWND
|
hwnd: HWND,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowHandle {
|
impl WindowHandle {
|
||||||
|
@ -193,7 +193,7 @@ impl Window {
|
||||||
WithParent(p) => {
|
WithParent(p) => {
|
||||||
flags = WS_CHILD | WS_VISIBLE;
|
flags = WS_CHILD | WS_VISIBLE;
|
||||||
p
|
p
|
||||||
},
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
AdjustWindowRectEx(&mut rect, flags, FALSE, 0);
|
AdjustWindowRectEx(&mut rect, flags, FALSE, 0);
|
||||||
|
@ -232,9 +232,7 @@ impl Window {
|
||||||
SetWindowLongPtrA(hwnd, GWLP_USERDATA, Rc::into_raw(win) as *const _ as _);
|
SetWindowLongPtrA(hwnd, GWLP_USERDATA, Rc::into_raw(win) as *const _ as _);
|
||||||
SetTimer(hwnd, 4242, 13, None);
|
SetTimer(hwnd, 4242, 13, None);
|
||||||
|
|
||||||
WindowHandle {
|
WindowHandle { hwnd }
|
||||||
hwnd
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,29 @@
|
||||||
use std::os::raw::{c_ulong, c_void};
|
use std::os::raw::{c_ulong, c_void};
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::time::*;
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
use std::time::*;
|
||||||
|
use std::time::*;
|
||||||
|
|
||||||
use raw_window_handle::{unix::XlibHandle, HasRawWindowHandle, RawWindowHandle};
|
use raw_window_handle::{unix::XlibHandle, HasRawWindowHandle, RawWindowHandle};
|
||||||
|
|
||||||
use super::XcbConnection;
|
use super::XcbConnection;
|
||||||
use crate::{
|
use crate::{
|
||||||
Event, KeyboardEvent, MouseButton, MouseEvent, Parent, ScrollDelta, WindowEvent,
|
Event, KeyboardEvent, MouseButton, MouseEvent, Parent, ScrollDelta, WindowEvent, WindowHandler,
|
||||||
WindowHandler, WindowOpenOptions,
|
WindowInfo, WindowOpenOptions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
xcb_connection: XcbConnection,
|
xcb_connection: XcbConnection,
|
||||||
window_id: u32,
|
window_id: u32,
|
||||||
scaling: f64,
|
window_info: WindowInfo,
|
||||||
|
|
||||||
frame_interval: Duration,
|
frame_interval: Duration,
|
||||||
event_loop_running: bool
|
event_loop_running: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: move to outer crate context
|
// FIXME: move to outer crate context
|
||||||
pub struct WindowHandle {
|
pub struct WindowHandle {
|
||||||
thread: std::thread::JoinHandle<()>
|
thread: std::thread::JoinHandle<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowHandle {
|
impl WindowHandle {
|
||||||
|
@ -47,12 +47,13 @@ impl Window {
|
||||||
// FIXME: placeholder types for returning errors in the future
|
// FIXME: placeholder types for returning errors in the future
|
||||||
let _ = rx.recv();
|
let _ = rx.recv();
|
||||||
|
|
||||||
WindowHandle {
|
WindowHandle { thread }
|
||||||
thread
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn window_thread<H: WindowHandler>(options: WindowOpenOptions, tx: mpsc::SyncSender<WindowOpenResult>) -> WindowOpenResult {
|
fn window_thread<H: WindowHandler>(
|
||||||
|
options: WindowOpenOptions,
|
||||||
|
tx: mpsc::SyncSender<WindowOpenResult>,
|
||||||
|
) -> WindowOpenResult {
|
||||||
// Connect to the X server
|
// Connect to the X server
|
||||||
// FIXME: baseview error type instead of unwrap()
|
// FIXME: baseview error type instead of unwrap()
|
||||||
let xcb_connection = XcbConnection::new().unwrap();
|
let xcb_connection = XcbConnection::new().unwrap();
|
||||||
|
@ -102,7 +103,8 @@ impl Window {
|
||||||
| xcb::EVENT_MASK_BUTTON_PRESS
|
| xcb::EVENT_MASK_BUTTON_PRESS
|
||||||
| 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,
|
||||||
)],
|
)],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -120,14 +122,16 @@ impl Window {
|
||||||
title.as_bytes(),
|
title.as_bytes(),
|
||||||
);
|
);
|
||||||
|
|
||||||
xcb_connection.atoms.wm_protocols
|
xcb_connection
|
||||||
|
.atoms
|
||||||
|
.wm_protocols
|
||||||
.zip(xcb_connection.atoms.wm_delete_window)
|
.zip(xcb_connection.atoms.wm_delete_window)
|
||||||
.map(|(wm_protocols, wm_delete_window)| {
|
.map(|(wm_protocols, wm_delete_window)| {
|
||||||
xcb_util::icccm::set_wm_protocols(
|
xcb_util::icccm::set_wm_protocols(
|
||||||
&xcb_connection.conn,
|
&xcb_connection.conn,
|
||||||
window_id,
|
window_id,
|
||||||
wm_protocols,
|
wm_protocols,
|
||||||
&[wm_delete_window]
|
&[wm_delete_window],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -135,13 +139,19 @@ impl Window {
|
||||||
|
|
||||||
let scaling = xcb_connection.get_scaling().unwrap_or(1.0);
|
let scaling = xcb_connection.get_scaling().unwrap_or(1.0);
|
||||||
|
|
||||||
|
let window_info = WindowInfo {
|
||||||
|
width: options.width as u32,
|
||||||
|
height: options.height as u32,
|
||||||
|
scale: scaling,
|
||||||
|
};
|
||||||
|
|
||||||
let mut window = Self {
|
let mut window = Self {
|
||||||
xcb_connection,
|
xcb_connection,
|
||||||
window_id,
|
window_id,
|
||||||
scaling,
|
window_info,
|
||||||
|
|
||||||
frame_interval: Duration::from_millis(15),
|
frame_interval: Duration::from_millis(15),
|
||||||
event_loop_running: false
|
event_loop_running: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut handler = H::build(&mut window);
|
let mut handler = H::build(&mut window);
|
||||||
|
@ -152,6 +162,10 @@ impl Window {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn window_info(&self) -> &WindowInfo {
|
||||||
|
&self.window_info
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn drain_xcb_events<H: WindowHandler>(&mut self, handler: &mut H) {
|
fn drain_xcb_events<H: WindowHandler>(&mut self, handler: &mut H) {
|
||||||
while let Some(event) = self.xcb_connection.conn.poll_for_event() {
|
while let Some(event) = self.xcb_connection.conn.poll_for_event() {
|
||||||
|
@ -176,8 +190,7 @@ impl Window {
|
||||||
|
|
||||||
while self.event_loop_running {
|
while self.event_loop_running {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
let until_next_frame =
|
let until_next_frame = if now > next_frame {
|
||||||
if now > next_frame {
|
|
||||||
handler.on_frame();
|
handler.on_frame();
|
||||||
|
|
||||||
next_frame = now + self.frame_interval;
|
next_frame = now + self.frame_interval;
|
||||||
|
@ -186,13 +199,10 @@ impl Window {
|
||||||
next_frame - now
|
next_frame - now
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut fds = [
|
let mut fds = [PollFd::new(xcb_fd, PollFlags::POLLIN)];
|
||||||
PollFd::new(xcb_fd, PollFlags::POLLIN)
|
|
||||||
];
|
|
||||||
|
|
||||||
// FIXME: handle errors
|
// FIXME: handle errors
|
||||||
poll(&mut fds, until_next_frame.subsec_millis() as i32)
|
poll(&mut fds, until_next_frame.subsec_millis() as i32).unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if let Some(revents) = fds[0].revents() {
|
if let Some(revents) = fds[0].revents() {
|
||||||
if revents.contains(PollFlags::POLLERR) {
|
if revents.contains(PollFlags::POLLERR) {
|
||||||
|
@ -231,9 +241,8 @@ impl Window {
|
||||||
|
|
||||||
match event_type {
|
match event_type {
|
||||||
////
|
////
|
||||||
// keys
|
// window
|
||||||
////
|
////
|
||||||
|
|
||||||
xcb::EXPOSE => {
|
xcb::EXPOSE => {
|
||||||
handler.on_frame();
|
handler.on_frame();
|
||||||
}
|
}
|
||||||
|
@ -245,7 +254,11 @@ impl Window {
|
||||||
let data = event.data().data;
|
let data = event.data().data;
|
||||||
let (_, data32, _) = unsafe { data.align_to::<u32>() };
|
let (_, data32, _) = unsafe { data.align_to::<u32>() };
|
||||||
|
|
||||||
let wm_delete_window = self.xcb_connection.atoms.wm_delete_window.unwrap_or(xcb::NONE);
|
let wm_delete_window = self
|
||||||
|
.xcb_connection
|
||||||
|
.atoms
|
||||||
|
.wm_delete_window
|
||||||
|
.unwrap_or(xcb::NONE);
|
||||||
|
|
||||||
if wm_delete_window == data32[0] {
|
if wm_delete_window == data32[0] {
|
||||||
handler.on_event(self, Event::Window(WindowEvent::WillClose));
|
handler.on_event(self, Event::Window(WindowEvent::WillClose));
|
||||||
|
@ -255,10 +268,22 @@ impl Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xcb::CONFIGURE_NOTIFY => {
|
||||||
|
let event = unsafe { xcb::cast_event::<xcb::ConfigureNotifyEvent>(&event) };
|
||||||
|
|
||||||
|
if self.window_info.width != event.width() as u32
|
||||||
|
|| self.window_info.height != event.height() as u32
|
||||||
|
{
|
||||||
|
self.window_info.width = event.width() as u32;
|
||||||
|
self.window_info.height = event.height() as u32;
|
||||||
|
|
||||||
|
handler.on_event(self, Event::Window(WindowEvent::Resized(self.window_info)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
// mouse
|
// mouse
|
||||||
////
|
////
|
||||||
|
|
||||||
xcb::MOTION_NOTIFY => {
|
xcb::MOTION_NOTIFY => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
@ -266,7 +291,10 @@ impl Window {
|
||||||
if detail != 4 && detail != 5 {
|
if detail != 4 && detail != 5 {
|
||||||
handler.on_event(
|
handler.on_event(
|
||||||
self,
|
self,
|
||||||
Event::Mouse(MouseEvent::CursorMoved { x: event.event_x() as i32, y: event.event_y() as i32 }),
|
Event::Mouse(MouseEvent::CursorMoved {
|
||||||
|
x: event.event_x() as i32,
|
||||||
|
y: event.event_y() as i32,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,19 +342,24 @@ impl Window {
|
||||||
////
|
////
|
||||||
// keys
|
// keys
|
||||||
////
|
////
|
||||||
|
|
||||||
xcb::KEY_PRESS => {
|
xcb::KEY_PRESS => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
|
||||||
handler.on_event(self, Event::Keyboard(KeyboardEvent::KeyPressed(detail as u32)));
|
handler.on_event(
|
||||||
|
self,
|
||||||
|
Event::Keyboard(KeyboardEvent::KeyPressed(detail as u32)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb::KEY_RELEASE => {
|
xcb::KEY_RELEASE => {
|
||||||
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
||||||
let detail = event.detail();
|
let detail = event.detail();
|
||||||
|
|
||||||
handler.on_event(self, Event::Keyboard(KeyboardEvent::KeyReleased(detail as u32)));
|
handler.on_event(
|
||||||
|
self,
|
||||||
|
Event::Keyboard(KeyboardEvent::KeyReleased(detail as u32)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -1,22 +1,18 @@
|
||||||
/// A very light abstraction around the XCB connection.
|
/// A very light abstraction around the XCB connection.
|
||||||
///
|
///
|
||||||
/// Keeps track of the xcb connection itself and the xlib display ID that was used to connect.
|
/// Keeps track of the xcb connection itself and the xlib display ID that was used to connect.
|
||||||
|
use std::ffi::{CStr, CString};
|
||||||
use std::ffi::{
|
|
||||||
CString,
|
|
||||||
CStr
|
|
||||||
};
|
|
||||||
|
|
||||||
pub(crate) struct Atoms {
|
pub(crate) struct Atoms {
|
||||||
pub wm_protocols: Option<u32>,
|
pub wm_protocols: Option<u32>,
|
||||||
pub wm_delete_window: Option<u32>
|
pub wm_delete_window: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct XcbConnection {
|
pub struct XcbConnection {
|
||||||
pub conn: xcb::Connection,
|
pub conn: xcb::Connection,
|
||||||
pub xlib_display: i32,
|
pub xlib_display: i32,
|
||||||
|
|
||||||
pub(crate) atoms: Atoms
|
pub(crate) atoms: Atoms,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! intern_atoms {
|
macro_rules! intern_atoms {
|
||||||
|
@ -36,15 +32,11 @@ macro_rules! intern_atoms {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl XcbConnection {
|
impl XcbConnection {
|
||||||
pub fn new() -> Result<Self, xcb::base::ConnError> {
|
pub fn new() -> Result<Self, xcb::base::ConnError> {
|
||||||
let (conn, xlib_display) = xcb::Connection::connect_with_xlib_display()?;
|
let (conn, xlib_display) = xcb::Connection::connect_with_xlib_display()?;
|
||||||
|
|
||||||
let (wm_protocols, wm_delete_window) =
|
let (wm_protocols, wm_delete_window) = intern_atoms!(&conn, WM_PROTOCOLS, WM_DELETE_WINDOW);
|
||||||
intern_atoms!(&conn,
|
|
||||||
WM_PROTOCOLS,
|
|
||||||
WM_DELETE_WINDOW);
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
conn,
|
conn,
|
||||||
|
@ -52,8 +44,8 @@ impl XcbConnection {
|
||||||
|
|
||||||
atoms: Atoms {
|
atoms: Atoms {
|
||||||
wm_protocols,
|
wm_protocols,
|
||||||
wm_delete_window
|
wm_delete_window,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +54,8 @@ impl XcbConnection {
|
||||||
// If neither work, I guess just assume 96.0 and don't do any scaling.
|
// If neither work, I guess just assume 96.0 and don't do any scaling.
|
||||||
fn get_scaling_xft(&self) -> Option<f64> {
|
fn get_scaling_xft(&self) -> Option<f64> {
|
||||||
use x11::xlib::{
|
use x11::xlib::{
|
||||||
XResourceManagerString, XrmDestroyDatabase, XrmGetResource, XrmGetStringDatabase, XrmValue,
|
XResourceManagerString, XrmDestroyDatabase, XrmGetResource, XrmGetStringDatabase,
|
||||||
|
XrmValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let display = self.conn.get_raw_dpy();
|
let display = self.conn.get_raw_dpy();
|
||||||
|
@ -113,10 +106,7 @@ impl XcbConnection {
|
||||||
fn get_scaling_screen_dimensions(&self) -> Option<f64> {
|
fn get_scaling_screen_dimensions(&self) -> Option<f64> {
|
||||||
// Figure out screen information
|
// Figure out screen information
|
||||||
let setup = self.conn.get_setup();
|
let setup = self.conn.get_setup();
|
||||||
let screen = setup
|
let screen = setup.roots().nth(self.xlib_display as usize).unwrap();
|
||||||
.roots()
|
|
||||||
.nth(self.xlib_display as usize)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
// Get the DPI from the screen struct
|
// Get the DPI from the screen struct
|
||||||
//
|
//
|
||||||
|
|
Loading…
Reference in a new issue