Add compiler arguments for choosing between OpenGL or wgpu. Add Receiver and Message types.
This commit is contained in:
parent
efce8c5ec9
commit
9234f050c0
17
Cargo.toml
17
Cargo.toml
|
@ -6,16 +6,29 @@ authors = [
|
|||
"Charles Saracco <crsaracco@gmail.com>",
|
||||
"Mirko Covizzi <mrkcvzz@gmail.com>",
|
||||
"Micah Johnston <micah@glowcoil.com>",
|
||||
"Billy Messenger <billydm@protonmail.com>",
|
||||
]
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = ["gl_renderer"]
|
||||
gl_renderer = ["gl"]
|
||||
wgpu_renderer = ["wgpu"]
|
||||
|
||||
[dependencies]
|
||||
gl = "0.14.0"
|
||||
log = "0.4.8"
|
||||
|
||||
[dependencies.gl]
|
||||
gl = "0.14"
|
||||
optional = true
|
||||
|
||||
[dependencies.wgpu]
|
||||
wgpu = "0.6"
|
||||
optional = true
|
||||
|
||||
[target.'cfg(target_os="linux")'.dependencies]
|
||||
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"
|
||||
|
||||
[target.'cfg(target_os="windows")'.dependencies]
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use baseview::Message;
|
||||
|
||||
fn main() {
|
||||
let window_open_options = baseview::WindowOpenOptions {
|
||||
title: "baseview",
|
||||
|
@ -6,5 +8,57 @@ fn main() {
|
|||
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");
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,6 +15,9 @@ mod macos;
|
|||
#[cfg(target_os = "macos")]
|
||||
pub use macos::*;
|
||||
|
||||
mod message;
|
||||
pub use message::*;
|
||||
|
||||
pub enum Parent {
|
||||
None,
|
||||
AsIfParented,
|
||||
|
@ -29,3 +32,7 @@ pub struct WindowOpenOptions<'a> {
|
|||
|
||||
pub parent: Parent,
|
||||
}
|
||||
|
||||
pub trait Receiver {
|
||||
fn on_message(&mut self, message: Message);
|
||||
}
|
|
@ -6,12 +6,14 @@ use cocoa::appkit::{
|
|||
use cocoa::base::{nil, NO};
|
||||
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 {
|
||||
pub fn open(options: WindowOpenOptions) -> Self {
|
||||
impl<R: Receiver> Window<R> {
|
||||
pub fn open(options: WindowOpenOptions, receiver: R) -> Self {
|
||||
unsafe {
|
||||
let _pool = NSAutoreleasePool::new(nil);
|
||||
|
||||
|
@ -42,7 +44,17 @@ impl Window {
|
|||
current_app.activateWithOptions_(NSApplicationActivateIgnoringOtherApps);
|
||||
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
54
src/message.rs
Normal 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,
|
||||
}
|
|
@ -25,6 +25,7 @@ use self::winapi::um::winuser::{
|
|||
use self::winapi::ctypes::c_void;
|
||||
use crate::Parent::WithParent;
|
||||
use crate::{handle_message, WindowOpenOptions};
|
||||
use crate::{Message, Receiver, MouseButtonID, MouseScroll};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
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() {}
|
||||
|
||||
pub struct Window {
|
||||
pub struct Window<R: Receiver> {
|
||||
pub(crate) hwnd: HWND,
|
||||
hdc: HDC,
|
||||
gl_context: HGLRC,
|
||||
window_class: ATOM,
|
||||
receiver: R,
|
||||
scaling: Option<f64>, // DPI scale, 96.0 is "default".
|
||||
r: f32,
|
||||
g: f32,
|
||||
b: f32,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
pub fn open(options: WindowOpenOptions) {
|
||||
impl<R: Receiver> Window<R> {
|
||||
pub fn open(options: WindowOpenOptions, receiver: R) {
|
||||
unsafe {
|
||||
let mut window = Window {
|
||||
hwnd: null_mut(),
|
||||
hdc: null_mut(),
|
||||
gl_context: null_mut(),
|
||||
window_class: 0,
|
||||
receiver,
|
||||
scaling: None,
|
||||
r: 0.3,
|
||||
g: 0.8,
|
||||
b: 0.3,
|
||||
|
@ -236,6 +241,14 @@ impl Window {
|
|||
|
||||
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
|
||||
if parent.is_null() {
|
||||
let mut msg: MSG = std::mem::zeroed();
|
||||
|
@ -252,6 +265,8 @@ impl Window {
|
|||
}
|
||||
|
||||
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
|
||||
unsafe {
|
||||
wglMakeCurrent(null_mut(), null_mut());
|
||||
|
@ -270,10 +285,14 @@ impl Window {
|
|||
}
|
||||
|
||||
pub(crate) fn handle_mouse_motion(&mut self, x: i32, y: i32) {
|
||||
println!("{}, {}", x, y);
|
||||
let r = (x as f32) / 1000.0;
|
||||
let g = (y as f32) / 1000.0;
|
||||
self.r = r;
|
||||
self.g = g;
|
||||
|
||||
self.receiver.on_message(Message::CursorMotion(
|
||||
x,
|
||||
y,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
mod window;
|
||||
pub use window::*;
|
||||
|
||||
mod xcb_connection;
|
||||
use xcb_connection::XcbConnection;
|
||||
|
||||
mod opengl_util;
|
||||
mod window;
|
||||
pub use window::*;
|
||||
|
||||
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
|
||||
mod opengl_util;
|
|
@ -1,10 +1,114 @@
|
|||
use std::ffi::CString;
|
||||
use std::ffi::{CString, CStr};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use ::x11::{glx, xlib};
|
||||
|
||||
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(
|
||||
dpy: *mut xlib::Display,
|
||||
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)
|
||||
// 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 mut maj: 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
|
||||
// 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 xlib_display = xcb_connection.xlib_display;
|
||||
|
||||
|
@ -64,3 +168,18 @@ pub unsafe fn load_gl_func(name: &str) -> *mut c_void {
|
|||
}
|
||||
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());
|
||||
}
|
||||
}
|
|
@ -9,21 +9,26 @@ use std::ffi::CStr;
|
|||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr::null_mut;
|
||||
|
||||
use ::x11::{glx, xlib};
|
||||
use ::x11::xlib;
|
||||
// use xcb::dri2; // needed later
|
||||
|
||||
#[cfg(all(not(feature = "wgpu_renderer"), feature = "gl_renderer"))]
|
||||
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,
|
||||
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 {
|
||||
pub fn open(options: WindowOpenOptions) -> Self {
|
||||
impl<R: Receiver> Window<R> {
|
||||
pub fn open(options: WindowOpenOptions, receiver: R) -> Self {
|
||||
// Convert the parent to a X11 window ID if we're given one
|
||||
let parent = match options.parent {
|
||||
Parent::None => None,
|
||||
|
@ -34,32 +39,12 @@ impl Window {
|
|||
// Connect to the X server
|
||||
let xcb_connection = XcbConnection::new();
|
||||
|
||||
// Check GLX version (>= 1.3 needed)
|
||||
opengl_util::check_glx_version(&xcb_connection);
|
||||
|
||||
// Get GLX framebuffer config (requires GLX >= 1.3)
|
||||
#[rustfmt::skip]
|
||||
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) };
|
||||
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
|
||||
let fb_config = opengl_util::fb_config(&xcb_connection);
|
||||
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
|
||||
let x_visual_info: *const xlib::XVisualInfo = {
|
||||
opengl_util::x_visual_info(&xcb_connection, fb_config)
|
||||
};
|
||||
|
||||
// Load up DRI2 extensions.
|
||||
// See also: https://www.x.org/releases/X11R7.7/doc/dri2proto/dri2proto.txt
|
||||
|
@ -157,36 +142,6 @@ impl Window {
|
|||
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.
|
||||
/*
|
||||
// installing an event handler to check if error is generated
|
||||
|
@ -198,32 +153,8 @@ impl Window {
|
|||
};
|
||||
*/
|
||||
|
||||
// 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");
|
||||
}
|
||||
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
|
||||
let ctx = opengl_util::glx_context(&xcb_connection, fb_config);
|
||||
|
||||
// Display the window
|
||||
xcb::map_window(&xcb_connection.conn, window_id);
|
||||
|
@ -232,22 +163,36 @@ impl Window {
|
|||
xlib::XSync(xcb_connection.conn.get_raw_dpy(), xlib::False);
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
|
||||
let mut x11_window = Self {
|
||||
xcb_connection,
|
||||
scaling: None,
|
||||
ctx,
|
||||
receiver,
|
||||
};
|
||||
|
||||
x11_window.scaling = x11_window
|
||||
.get_scaling_xft()
|
||||
.or(x11_window.get_scaling_screen_dimensions());
|
||||
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;
|
||||
}
|
||||
|
||||
// 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();
|
||||
loop {
|
||||
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
|
||||
|
||||
match event_type {
|
||||
xcb::EXPOSE => 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());
|
||||
xcb::EXPOSE => {
|
||||
#[cfg(all(feature = "gl_renderer", not(feature = "wgpu_renderer")))]
|
||||
opengl_util::xcb_expose(window_id, raw_display, self.ctx);
|
||||
},
|
||||
xcb::MOTION_NOTIFY => {
|
||||
let event = unsafe { xcb::cast_event::<xcb::MotionNotifyEvent>(&event) };
|
||||
let x = event.event_x();
|
||||
let y = event.event_y();
|
||||
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 => {
|
||||
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
||||
let x = event.event_x();
|
||||
let y = event.event_y();
|
||||
let detail = event.detail();
|
||||
let state = event.state();
|
||||
println!(
|
||||
"Mouse button pressed: ({}, {}) -- {} / {}",
|
||||
x, y, detail, state
|
||||
);
|
||||
|
||||
match detail {
|
||||
4 => {
|
||||
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 => {
|
||||
let event = unsafe { xcb::cast_event::<xcb::ButtonReleaseEvent>(&event) };
|
||||
let x = event.event_x();
|
||||
let y = event.event_y();
|
||||
let event = unsafe { xcb::cast_event::<xcb::ButtonPressEvent>(&event) };
|
||||
let detail = event.detail();
|
||||
let state = event.state();
|
||||
println!(
|
||||
"Mouse button released: ({}, {}) -- {} / {}",
|
||||
x, y, detail, state
|
||||
);
|
||||
|
||||
if detail != 4 && detail != 5 {
|
||||
let button_id = mouse_id(detail);
|
||||
self.receiver.on_message(Message::MouseUp(button_id));
|
||||
}
|
||||
}
|
||||
xcb::KEY_PRESS => {
|
||||
let event = unsafe { xcb::cast_event::<xcb::KeyPressEvent>(&event) };
|
||||
let x = event.event_x();
|
||||
let y = event.event_y();
|
||||
let detail = event.detail();
|
||||
let state = event.state();
|
||||
println!(
|
||||
"Keyboard key pressed: ({}, {}) -- {} / {}",
|
||||
x, y, detail, state
|
||||
);
|
||||
|
||||
self.receiver.on_message(Message::KeyDown(detail));
|
||||
}
|
||||
xcb::KEY_RELEASE => {
|
||||
let event = unsafe { xcb::cast_event::<xcb::KeyReleaseEvent>(&event) };
|
||||
let x = event.event_x();
|
||||
let y = event.event_y();
|
||||
let detail = event.detail();
|
||||
let state = event.state();
|
||||
println!(
|
||||
"Keyboard key released: ({}, {}) -- {} / {}",
|
||||
x, y, detail, state
|
||||
);
|
||||
|
||||
self.receiver.on_message(Message::KeyUp(detail));
|
||||
}
|
||||
_ => {
|
||||
println!("Unhandled event type: {:?}", event_type);
|
||||
|
@ -422,3 +370,14 @@ impl Window {
|
|||
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),
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue