1
0
Fork 0

Add compiler arguments for choosing between OpenGL or wgpu. Add Receiver and Message types.

This commit is contained in:
Billy Messenger 2020-09-02 16:22:49 -05:00
parent efce8c5ec9
commit 9234f050c0
9 changed files with 388 additions and 150 deletions

View file

@ -6,16 +6,29 @@ authors = [
"Charles Saracco <crsaracco@gmail.com>", "Charles Saracco <crsaracco@gmail.com>",
"Mirko Covizzi <mrkcvzz@gmail.com>", "Mirko Covizzi <mrkcvzz@gmail.com>",
"Micah Johnston <micah@glowcoil.com>", "Micah Johnston <micah@glowcoil.com>",
"Billy Messenger <billydm@protonmail.com>",
] ]
edition = "2018" edition = "2018"
[features]
default = ["gl_renderer"]
gl_renderer = ["gl"]
wgpu_renderer = ["wgpu"]
[dependencies] [dependencies]
gl = "0.14.0"
log = "0.4.8" log = "0.4.8"
[dependencies.gl]
gl = "0.14"
optional = true
[dependencies.wgpu]
wgpu = "0.6"
optional = true
[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"] }
x11 = { version = "2.3", features = ["xlib", "glx"]} x11 = { version = "2.18", features = ["xlib", "glx"] }
libc = "0.2" libc = "0.2"
[target.'cfg(target_os="windows")'.dependencies] [target.'cfg(target_os="windows")'.dependencies]

View file

@ -1,3 +1,5 @@
use baseview::Message;
fn main() { fn main() {
let window_open_options = baseview::WindowOpenOptions { let window_open_options = baseview::WindowOpenOptions {
title: "baseview", title: "baseview",
@ -6,5 +8,57 @@ fn main() {
parent: baseview::Parent::None, parent: baseview::Parent::None,
}; };
baseview::Window::open(window_open_options); let my_program = MyProgram {};
baseview::Window::open(window_open_options, my_program);
}
struct MyProgram {
}
impl baseview::Receiver for MyProgram {
fn on_message(&mut self, message: Message) {
match message {
Message::CursorMotion(x, y) => {
println!("Cursor moved, x: {}, y: {}", x, y);
},
Message::MouseDown(button_id) => {
println!("Mouse down, button id: {:?}", button_id);
},
Message::MouseUp(button_id) => {
println!("Mouse up, button id: {:?}", button_id);
},
Message::MouseScroll(mouse_scroll) => {
println!("Mouse scroll, {:?}", mouse_scroll);
},
Message::MouseClick(mouse_click) => {
println!("Mouse click, {:?}", mouse_click);
}
Message::KeyDown(keycode) => {
println!("Key down, keycode: {}", keycode);
},
Message::KeyUp(keycode) => {
println!("Key up, keycode: {}", keycode);
},
Message::CharacterInput(char_code) => {
println!("Character input, char_code: {}", char_code);
},
Message::WindowResized(window_info) => {
println!("Window resized, {:?}", window_info);
},
Message::WindowFocus => {
println!("Window focused");
},
Message::WindowUnfocus => {
println!("Window unfocused");
},
Message::Opened(window_info) => {
println!("Window opened, {:?}", window_info);
},
Message::WillClose => {
println!("Window will close");
},
}
}
} }

View file

@ -15,6 +15,9 @@ mod macos;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub use macos::*; pub use macos::*;
mod message;
pub use message::*;
pub enum Parent { pub enum Parent {
None, None,
AsIfParented, AsIfParented,
@ -29,3 +32,7 @@ pub struct WindowOpenOptions<'a> {
pub parent: Parent, pub parent: Parent,
} }
pub trait Receiver {
fn on_message(&mut self, message: Message);
}

View file

@ -6,12 +6,14 @@ use cocoa::appkit::{
use cocoa::base::{nil, NO}; use cocoa::base::{nil, NO};
use cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString}; use cocoa::foundation::{NSAutoreleasePool, NSPoint, NSRect, NSSize, NSString};
use crate::WindowOpenOptions; use crate::{WindowOpenOptions, Message, Receiver, MouseButtonID, MouseScroll};
pub struct Window; pub struct Window<R: Receiver> {
receiver: R,
}
impl Window { impl<R: Receiver> Window<R> {
pub fn open(options: WindowOpenOptions) -> Self { pub fn open(options: WindowOpenOptions, receiver: R) -> Self {
unsafe { unsafe {
let _pool = NSAutoreleasePool::new(nil); let _pool = NSAutoreleasePool::new(nil);
@ -42,7 +44,17 @@ impl Window {
current_app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps); current_app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps);
app.run(); app.run();
Window receiver.on_message(Message::Opened(
crate::message::WindowInfo {
width: options.width as u32,
height: options.height as u32,
dpi: None,
}
));
Window {
receiver,
}
} }
} }
} }

54
src/message.rs Normal file
View file

@ -0,0 +1,54 @@
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum MouseButtonID {
Left,
Middle,
Right,
Back,
Forward,
Other(u8),
}
#[derive(Debug, Copy, Clone)]
pub struct MouseScroll {
pub x_delta: f64,
pub y_delta: f64,
}
#[derive(Debug, Copy, Clone)]
pub enum MouseClickType {
Single,
Double,
Triple,
}
#[derive(Debug, Copy, Clone)]
pub struct MouseClick {
pub id: MouseButtonID,
pub click_type: MouseClickType,
pub x: i32,
pub y: i32,
}
#[derive(Debug)]
pub struct WindowInfo {
pub width: u32,
pub height: u32,
pub dpi: Option<f64>,
}
#[derive(Debug)]
pub enum Message {
CursorMotion(i32, i32), // new (x, y) relative to window
MouseDown(MouseButtonID),
MouseUp(MouseButtonID),
MouseScroll(MouseScroll),
MouseClick(MouseClick),
KeyDown(u8), // keycode
KeyUp(u8), // keycode
CharacterInput(u32), // character code
WindowResized(WindowInfo), // new (width, height)
WindowFocus,
WindowUnfocus,
Opened(WindowInfo),
WillClose,
}

View file

@ -25,6 +25,7 @@ use self::winapi::um::winuser::{
use self::winapi::ctypes::c_void; use self::winapi::ctypes::c_void;
use crate::Parent::WithParent; use crate::Parent::WithParent;
use crate::{handle_message, WindowOpenOptions}; use crate::{handle_message, WindowOpenOptions};
use crate::{Message, Receiver, MouseButtonID, MouseScroll};
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
unsafe fn message_box(title: &str, msg: &str) { unsafe fn message_box(title: &str, msg: &str) {
@ -111,24 +112,28 @@ unsafe fn unregister_wnd_class(wnd_class: ATOM) {
unsafe fn init_gl_context() {} unsafe fn init_gl_context() {}
pub struct Window { pub struct Window<R: Receiver> {
pub(crate) hwnd: HWND, pub(crate) hwnd: HWND,
hdc: HDC, hdc: HDC,
gl_context: HGLRC, gl_context: HGLRC,
window_class: ATOM, window_class: ATOM,
receiver: R,
scaling: Option<f64>, // DPI scale, 96.0 is "default".
r: f32, r: f32,
g: f32, g: f32,
b: f32, b: f32,
} }
impl Window { impl<R: Receiver> Window<R> {
pub fn open(options: WindowOpenOptions) { pub fn open(options: WindowOpenOptions, receiver: R) {
unsafe { unsafe {
let mut window = Window { let mut window = Window {
hwnd: null_mut(), hwnd: null_mut(),
hdc: null_mut(), hdc: null_mut(),
gl_context: null_mut(), gl_context: null_mut(),
window_class: 0, window_class: 0,
receiver,
scaling: None,
r: 0.3, r: 0.3,
g: 0.8, g: 0.8,
b: 0.3, b: 0.3,
@ -236,6 +241,14 @@ impl Window {
SetTimer(hwnd, 4242, 13, None); SetTimer(hwnd, 4242, 13, None);
window.receiver.on_message(Message::Opened(
crate::message::WindowInfo {
width: options.width as u32,
height: options.height as u32,
dpi: window.scaling,
}
));
// todo: decide what to do with the message pump // todo: decide what to do with the message pump
if parent.is_null() { if parent.is_null() {
let mut msg: MSG = std::mem::zeroed(); let mut msg: MSG = std::mem::zeroed();
@ -252,6 +265,8 @@ impl Window {
} }
pub fn close(&self) { pub fn close(&self) {
self.receiver.on_message(Message::WillClose);
// todo: see https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L402 // todo: see https://github.com/wrl/rutabaga/blob/f30ff67e157375cafdbafe5fb549f1790443a3a8/src/platform/win/window.c#L402
unsafe { unsafe {
wglMakeCurrent(null_mut(), null_mut()); wglMakeCurrent(null_mut(), null_mut());
@ -270,10 +285,14 @@ impl Window {
} }
pub(crate) fn handle_mouse_motion(&mut self, x: i32, y: i32) { pub(crate) fn handle_mouse_motion(&mut self, x: i32, y: i32) {
println!("{}, {}", x, y);
let r = (x as f32) / 1000.0; let r = (x as f32) / 1000.0;
let g = (y as f32) / 1000.0; let g = (y as f32) / 1000.0;
self.r = r; self.r = r;
self.g = g; self.g = g;
self.receiver.on_message(Message::CursorMotion(
x,
y,
));
} }
} }

View file

@ -1,7 +1,8 @@
mod window;
pub use window::*;
mod xcb_connection; mod xcb_connection;
use xcb_connection::XcbConnection; use xcb_connection::XcbConnection;
mod window;
pub use window::*;
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
mod opengl_util; mod opengl_util;

View file

@ -1,10 +1,114 @@
use std::ffi::CString; use std::ffi::{CString, CStr};
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
use std::ptr::null_mut;
use ::x11::{glx, xlib}; use ::x11::{glx, xlib};
use super::XcbConnection; use super::XcbConnection;
pub fn fb_config(xcb_connection: &XcbConnection) -> *mut glx::__GLXFBConfigRec {
// Check GLX version (>= 1.3 needed)
check_glx_version(&xcb_connection);
// Get GLX framebuffer config (requires GLX >= 1.3)
#[rustfmt::skip]
let fb_config = get_glxfbconfig(
&xcb_connection,
&[
glx::GLX_X_RENDERABLE, 1,
glx::GLX_DRAWABLE_TYPE, glx::GLX_WINDOW_BIT,
glx::GLX_RENDER_TYPE, glx::GLX_RGBA_BIT,
glx::GLX_X_VISUAL_TYPE, glx::GLX_TRUE_COLOR,
glx::GLX_RED_SIZE, 8,
glx::GLX_GREEN_SIZE, 8,
glx::GLX_BLUE_SIZE, 8,
glx::GLX_ALPHA_SIZE, 8,
glx::GLX_DEPTH_SIZE, 24,
glx::GLX_STENCIL_SIZE, 8,
glx::GLX_DOUBLEBUFFER, 1,
0
],
);
fb_config
}
pub fn x_visual_info(
xcb_connection: &XcbConnection,
fb_config: *mut glx::__GLXFBConfigRec
) -> *const xlib::XVisualInfo {
// The GLX framebuffer config holds an XVisualInfo, which we'll need for other X operations.
unsafe { glx::glXGetVisualFromFBConfig(
xcb_connection.conn.get_raw_dpy(),
fb_config
)}
}
pub fn glx_context(
xcb_connection: &XcbConnection,
fb_config: *mut glx::__GLXFBConfigRec
) -> *mut glx::__GLXcontextRec {
// Load GLX extensions
// We need at least `GLX_ARB_create_context`
let glx_extensions = unsafe {
CStr::from_ptr(glx::glXQueryExtensionsString(
xcb_connection.conn.get_raw_dpy(),
xcb_connection.xlib_display,
))
.to_str()
.unwrap()
};
glx_extensions
.find("GLX_ARB_create_context")
.expect("could not find GLX extension GLX_ARB_create_context");
// With GLX, we don't need a context pre-created in order to load symbols.
// Otherwise, we would need to create a temporary legacy (dummy) GL context to load them.
// (something that has at least GlXCreateContextAttribsARB)
let glx_create_context_attribs: GlXCreateContextAttribsARBProc =
unsafe { std::mem::transmute(load_gl_func("glXCreateContextAttribsARB")) };
// Load all other symbols
unsafe {
gl::load_with(|n| load_gl_func(&n));
}
// Check GL3 support
if !gl::GenVertexArrays::is_loaded() {
panic!("no GL3 support available!");
}
// Create GLX context attributes. (?)
let context_attribs: [c_int; 5] = [
glx::arb::GLX_CONTEXT_MAJOR_VERSION_ARB as c_int,
3,
glx::arb::GLX_CONTEXT_MINOR_VERSION_ARB as c_int,
0,
0,
];
let ctx = unsafe {
glx_create_context_attribs(
xcb_connection.conn.get_raw_dpy(),
fb_config,
null_mut(),
xlib::True,
&context_attribs[0] as *const c_int,
)
};
if ctx.is_null()
/* || ctx_error_occurred */
{
panic!("Error when creating a GL 3.0 context");
}
if unsafe { glx::glXIsDirect(xcb_connection.conn.get_raw_dpy(), ctx) } == 0 {
panic!("Obtained indirect rendering context");
}
ctx
}
pub type GlXCreateContextAttribsARBProc = unsafe extern "C" fn( pub type GlXCreateContextAttribsARBProc = unsafe extern "C" fn(
dpy: *mut xlib::Display, dpy: *mut xlib::Display,
fbc: glx::GLXFBConfig, fbc: glx::GLXFBConfig,
@ -15,7 +119,7 @@ pub type GlXCreateContextAttribsARBProc = unsafe extern "C" fn(
// Check to make sure this system supports the correct version of GLX (>= 1.3 for now) // Check to make sure this system supports the correct version of GLX (>= 1.3 for now)
// For now it just panics if not, but TODO: do correct error handling // For now it just panics if not, but TODO: do correct error handling
pub fn check_glx_version(xcb_connection: &XcbConnection) { fn check_glx_version(xcb_connection: &XcbConnection) {
let raw_display = xcb_connection.conn.get_raw_dpy(); let raw_display = xcb_connection.conn.get_raw_dpy();
let mut maj: c_int = 0; let mut maj: c_int = 0;
let mut min: c_int = 0; let mut min: c_int = 0;
@ -32,7 +136,7 @@ pub fn check_glx_version(xcb_connection: &XcbConnection) {
// Get GLX framebuffer config // Get GLX framebuffer config
// History: https://stackoverflow.com/questions/51558473/whats-the-difference-between-a-glx-visual-and-a-fbconfig // History: https://stackoverflow.com/questions/51558473/whats-the-difference-between-a-glx-visual-and-a-fbconfig
pub fn get_glxfbconfig(xcb_connection: &XcbConnection, visual_attribs: &[i32]) -> glx::GLXFBConfig { fn get_glxfbconfig(xcb_connection: &XcbConnection, visual_attribs: &[i32]) -> glx::GLXFBConfig {
let raw_display = xcb_connection.conn.get_raw_dpy(); let raw_display = xcb_connection.conn.get_raw_dpy();
let xlib_display = xcb_connection.xlib_display; let xlib_display = xcb_connection.xlib_display;
@ -64,3 +168,18 @@ pub unsafe fn load_gl_func(name: &str) -> *mut c_void {
} }
ptr ptr
} }
pub fn xcb_expose(
window_id: u32,
raw_display: *mut xlib::_XDisplay,
ctx: *mut glx::__GLXcontextRec,
) {
unsafe {
glx::glXMakeCurrent(raw_display, window_id as xlib::XID, ctx);
gl::ClearColor(0.3, 0.8, 0.3, 1.0);
gl::Clear(gl::COLOR_BUFFER_BIT);
gl::Flush();
glx::glXSwapBuffers(raw_display, window_id as xlib::XID);
glx::glXMakeCurrent(raw_display, 0, null_mut());
}
}

View file

@ -9,21 +9,26 @@ use std::ffi::CStr;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
use std::ptr::null_mut; use std::ptr::null_mut;
use ::x11::{glx, xlib}; use ::x11::xlib;
// use xcb::dri2; // needed later // use xcb::dri2; // needed later
#[cfg(all(not(feature = "wgpu_renderer"), feature = "gl_renderer"))]
use super::opengl_util; use super::opengl_util;
use super::XcbConnection;
use crate::Parent;
use crate::WindowOpenOptions;
pub struct Window { use super::XcbConnection;
use crate::{Parent, WindowOpenOptions, Message, Receiver, MouseButtonID, MouseScroll};
pub struct Window<R: Receiver> {
xcb_connection: XcbConnection, xcb_connection: XcbConnection,
scaling: Option<f64>, // DPI scale, 96.0 is "default". scaling: Option<f64>, // DPI scale, 96.0 is "default".
receiver: R,
#[cfg(all(not(feature = "wgpu_renderer"), feature = "gl_renderer"))]
ctx: *mut x11::glx::__GLXcontextRec,
} }
impl Window { impl<R: Receiver> Window<R> {
pub fn open(options: WindowOpenOptions) -> Self { pub fn open(options: WindowOpenOptions, receiver: R) -> Self {
// 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,
@ -34,32 +39,12 @@ impl Window {
// Connect to the X server // Connect to the X server
let xcb_connection = XcbConnection::new(); let xcb_connection = XcbConnection::new();
// Check GLX version (>= 1.3 needed) #[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
opengl_util::check_glx_version(&xcb_connection); let fb_config = opengl_util::fb_config(&xcb_connection);
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
// Get GLX framebuffer config (requires GLX >= 1.3) let x_visual_info: *const xlib::XVisualInfo = {
#[rustfmt::skip] opengl_util::x_visual_info(&xcb_connection, fb_config)
let fb_config = opengl_util::get_glxfbconfig( };
&xcb_connection,
&[
glx::GLX_X_RENDERABLE, 1,
glx::GLX_DRAWABLE_TYPE, glx::GLX_WINDOW_BIT,
glx::GLX_RENDER_TYPE, glx::GLX_RGBA_BIT,
glx::GLX_X_VISUAL_TYPE, glx::GLX_TRUE_COLOR,
glx::GLX_RED_SIZE, 8,
glx::GLX_GREEN_SIZE, 8,
glx::GLX_BLUE_SIZE, 8,
glx::GLX_ALPHA_SIZE, 8,
glx::GLX_DEPTH_SIZE, 24,
glx::GLX_STENCIL_SIZE, 8,
glx::GLX_DOUBLEBUFFER, 1,
0
],
);
// The GLX framebuffer config holds an XVisualInfo, which we'll need for other X operations.
let x_visual_info: *const xlib::XVisualInfo =
unsafe { glx::glXGetVisualFromFBConfig(xcb_connection.conn.get_raw_dpy(), fb_config) };
// Load up DRI2 extensions. // Load up DRI2 extensions.
// See also: https://www.x.org/releases/X11R7.7/doc/dri2proto/dri2proto.txt // See also: https://www.x.org/releases/X11R7.7/doc/dri2proto/dri2proto.txt
@ -157,36 +142,6 @@ impl Window {
title.as_bytes(), title.as_bytes(),
); );
// Load GLX extensions
// We need at least `GLX_ARB_create_context`
let glx_extensions = unsafe {
CStr::from_ptr(glx::glXQueryExtensionsString(
xcb_connection.conn.get_raw_dpy(),
xcb_connection.xlib_display,
))
.to_str()
.unwrap()
};
glx_extensions
.find("GLX_ARB_create_context")
.expect("could not find GLX extension GLX_ARB_create_context");
// With GLX, we don't need a context pre-created in order to load symbols.
// Otherwise, we would need to create a temporary legacy (dummy) GL context to load them.
// (something that has at least GlXCreateContextAttribsARB)
let glx_create_context_attribs: opengl_util::GlXCreateContextAttribsARBProc =
unsafe { std::mem::transmute(opengl_util::load_gl_func("glXCreateContextAttribsARB")) };
// Load all other symbols
unsafe {
gl::load_with(|n| opengl_util::load_gl_func(&n));
}
// Check GL3 support
if !gl::GenVertexArrays::is_loaded() {
panic!("no GL3 support available!");
}
// TODO: This requires a global, which is a no. Figure out if there's a better way to do it. // TODO: This requires a global, which is a no. Figure out if there's a better way to do it.
/* /*
// installing an event handler to check if error is generated // installing an event handler to check if error is generated
@ -198,32 +153,8 @@ impl Window {
}; };
*/ */
// Create GLX context attributes. (?) #[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
let context_attribs: [c_int; 5] = [ let ctx = opengl_util::glx_context(&xcb_connection, fb_config);
glx::arb::GLX_CONTEXT_MAJOR_VERSION_ARB as c_int,
3,
glx::arb::GLX_CONTEXT_MINOR_VERSION_ARB as c_int,
0,
0,
];
let ctx = unsafe {
glx_create_context_attribs(
xcb_connection.conn.get_raw_dpy(),
fb_config,
null_mut(),
xlib::True,
&context_attribs[0] as *const c_int,
)
};
if ctx.is_null()
/* || ctx_error_occurred */
{
panic!("Error when creating a GL 3.0 context");
}
if unsafe { glx::glXIsDirect(xcb_connection.conn.get_raw_dpy(), ctx) } == 0 {
panic!("Obtained indirect rendering context");
}
// Display the window // Display the window
xcb::map_window(&xcb_connection.conn, window_id); xcb::map_window(&xcb_connection.conn, window_id);
@ -232,22 +163,36 @@ impl Window {
xlib::XSync(xcb_connection.conn.get_raw_dpy(), xlib::False); xlib::XSync(xcb_connection.conn.get_raw_dpy(), xlib::False);
} }
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
let mut x11_window = Self { let mut x11_window = Self {
xcb_connection, xcb_connection,
scaling: None, scaling: None,
ctx,
receiver,
}; };
x11_window.scaling = x11_window x11_window.scaling = x11_window
.get_scaling_xft() .get_scaling_xft()
.or(x11_window.get_scaling_screen_dimensions()); .or(x11_window.get_scaling_screen_dimensions());
println!("Scale factor: {:?}", x11_window.scaling); println!("Scale factor: {:?}", x11_window.scaling);
x11_window.handle_events(window_id, ctx);
x11_window.receiver.on_message(Message::Opened(
crate::message::WindowInfo {
width: options.width as u32,
height: options.height as u32,
dpi: x11_window.scaling,
}
));
x11_window.handle_events(window_id);
x11_window.receiver.on_message(Message::WillClose);
return x11_window; return x11_window;
} }
// Event loop // Event loop
fn handle_events(&self, window_id: u32, ctx: *mut x11::glx::__GLXcontextRec) { fn handle_events(&mut self, window_id: u32) {
let raw_display = self.xcb_connection.conn.get_raw_dpy(); let raw_display = self.xcb_connection.conn.get_raw_dpy();
loop { loop {
let ev = self.xcb_connection.conn.wait_for_event(); let ev = self.xcb_connection.conn.wait_for_event();
@ -275,65 +220,68 @@ impl Window {
// http://rtbo.github.io/rust-xcb/src/xcb/ffi/xproto.rs.html#445 // http://rtbo.github.io/rust-xcb/src/xcb/ffi/xproto.rs.html#445
match event_type { match event_type {
xcb::EXPOSE => unsafe { xcb::EXPOSE => {
glx::glXMakeCurrent(raw_display, window_id as xlib::XID, ctx); #[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
gl::ClearColor(0.3, 0.8, 0.3, 1.0); opengl_util::xcb_expose(window_id, raw_display, self.ctx);
gl::Clear(gl::COLOR_BUFFER_BIT);
gl::Flush();
glx::glXSwapBuffers(raw_display, window_id as xlib::XID);
glx::glXMakeCurrent(raw_display, 0, null_mut());
}, },
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 x = event.event_x();
let y = event.event_y();
let detail = event.detail(); let detail = event.detail();
let state = event.state();
println!("Mouse motion: ({}, {}) -- {} / {}", x, y, detail, state); if detail != 4 && detail != 5 {
self.receiver.on_message(Message::CursorMotion(
event.event_x() as i32,
event.event_y() as i32,
));
}
} }
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 x = event.event_x();
let y = event.event_y();
let detail = event.detail(); let detail = event.detail();
let state = event.state();
println!( match detail {
"Mouse button pressed: ({}, {}) -- {} / {}", 4 => {
x, y, detail, state self.receiver.on_message(Message::MouseScroll(
); MouseScroll {
x_delta: 0.0,
y_delta: 1.0,
}
));
},
5 => {
self.receiver.on_message(Message::MouseScroll(
MouseScroll {
x_delta: 0.0,
y_delta: -1.0,
}
));
}
detail => {
let button_id = mouse_id(detail);
self.receiver.on_message(Message::MouseDown(button_id));
}
}
} }
xcb::BUTTON_RELEASE => { xcb::BUTTON_RELEASE => {
let event = unsafe { xcb::cast_event::<xcb::ButtonReleaseEvent>(&event) }; let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
let x = event.event_x();
let y = event.event_y();
let detail = event.detail(); let detail = event.detail();
let state = event.state();
println!( if detail != 4 && detail != 5 {
"Mouse button released: ({}, {}) -- {} / {}", let button_id = mouse_id(detail);
x, y, detail, state self.receiver.on_message(Message::MouseUp(button_id));
); }
} }
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 x = event.event_x();
let y = event.event_y();
let detail = event.detail(); let detail = event.detail();
let state = event.state();
println!( self.receiver.on_message(Message::KeyDown(detail));
"Keyboard key pressed: ({}, {}) -- {} / {}",
x, y, detail, state
);
} }
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 x = event.event_x();
let y = event.event_y();
let detail = event.detail(); let detail = event.detail();
let state = event.state();
println!( self.receiver.on_message(Message::KeyUp(detail));
"Keyboard key released: ({}, {}) -- {} / {}",
x, y, detail, state
);
} }
_ => { _ => {
println!("Unhandled event type: {:?}", event_type); println!("Unhandled event type: {:?}", event_type);
@ -422,3 +370,14 @@ impl Window {
Some(yres) Some(yres)
} }
} }
fn mouse_id(id: u8) -> MouseButtonID {
match id {
1 => MouseButtonID::Left,
2 => MouseButtonID::Middle,
3 => MouseButtonID::Right,
6 => MouseButtonID::Back,
7 => MouseButtonID::Forward,
id => MouseButtonID::Other(id),
}
}