use std::ffi;
use std::mem;
use std::os::raw;
use std::ptr;
use crate::{Desc, EventType, GlFbConfig, Keycode, MouseButton, WFApp};
use x11_dl::{self as x11, glx, xlib};
const WITHDRAWN_STATE: raw::c_int = 0;
const NORMAL_STATE: raw::c_int = 1;
const ICONIC_STATE: raw::c_int = 3;
pub struct Window {
display: *mut xlib::Display,
screen: i32,
root: xlib::Window,
colormap: xlib::Colormap,
window: xlib::Window,
_dpi: f32,
window_state: u32,
error_code: u8,
xlib: xlib::Xlib,
keycodes: [bool; 256],
x11_utf8_string: xlib::Atom,
x11_wm_protocols: xlib::Atom,
x11_wm_delete_window: xlib::Atom,
x11_wm_state: xlib::Atom,
x11_net_wm_name: xlib::Atom,
x11_net_wm_icon_name: xlib::Atom,
glx_ctx: glx::GLXContext,
glx_window: glx::GLXWindow,
glx: glx::Glx,
glx_create_context_attribs_arb: Option<
unsafe extern "C" fn(
*mut xlib::Display,
glx::GLXFBConfig,
glx::GLXContext,
bool,
*const raw::c_int,
) -> glx::GLXContext,
>,
glx_swap_interval_ext: Option<fn(*mut xlib::Display, glx::GLXDrawable, raw::c_int)>,
glx_swap_interval_mesa: Option<fn(raw::c_int) -> raw::c_int>,
}
unsafe extern "C" fn error_handler(
display: *mut xlib::Display,
error: *mut xlib::XErrorEvent,
) -> i32 {
eprintln!("Yikes: {:?}, {:?}", display, *error);
return 0;
}
fn gl_choose_fb_config(_desired: &GlFbConfig, alternatives: &[GlFbConfig]) -> Option<GlFbConfig> {
alternatives.last().cloned()
}
impl Window {
pub fn grab_error_handler(&mut self) {
self.error_code = xlib::Success;
unsafe {
(self.xlib.XSetErrorHandler)(Some(error_handler));
}
}
pub fn release_error_handler(&mut self) {
unsafe {
(self.xlib.XSync)(self.display, 0);
(self.xlib.XSetErrorHandler)(None);
}
}
pub fn init_extensions(&mut self) {
unsafe {
self.x11_utf8_string = (self.xlib.XInternAtom)(
self.display,
ffi::CString::new("UTF8_STRING").unwrap().as_ptr(),
0,
);
self.x11_wm_protocols = (self.xlib.XInternAtom)(
self.display,
ffi::CString::new("WM_PROTOCOLS").unwrap().as_ptr(),
0,
);
self.x11_wm_delete_window = (self.xlib.XInternAtom)(
self.display,
ffi::CString::new("WM_DELETE_WINDOW").unwrap().as_ptr(),
0,
);
self.x11_wm_state = (self.xlib.XInternAtom)(
self.display,
ffi::CString::new("WM_STATE").unwrap().as_ptr(),
0,
);
self.x11_net_wm_name = (self.xlib.XInternAtom)(
self.display,
ffi::CString::new("_NET_WM_NAME").unwrap().as_ptr(),
0,
);
self.x11_net_wm_icon_name = (self.xlib.XInternAtom)(
self.display,
ffi::CString::new("_NET_WM_ICON_NAME").unwrap().as_ptr(),
0,
);
}
}
pub fn query_system_dpi() -> f32 {
96.0
}
fn glx_has_ext(ext: &str, available_extensions: &str) -> bool {
available_extensions.contains(ext)
}
pub fn glx_extsupported(ext: &str, available_extensions: *const raw::c_char) -> bool {
if available_extensions.is_null() {
return false;
} else {
let cs = unsafe { ffi::CStr::from_ptr(available_extensions) };
let s = cs.to_string_lossy();
Self::glx_has_ext(ext, &s)
}
}
pub unsafe fn getprocaddr(glx: &glx::Glx, procname: &str) -> *const ffi::c_void {
let procname_cstr =
ffi::CString::new(procname).expect("Invalid C string given to getprocaddr");
let procname_p = procname_cstr.as_ptr() as *const raw::c_uchar;
let f = (glx.glXGetProcAddress)(procname_p);
f.expect("getprocaddr: Could not find given function?") as *const ffi::c_void
}
pub unsafe fn glx_attrib(&mut self, fbconfig: glx::GLXFBConfig, attrib: i32) -> i32 {
let mut res: i32 = 0;
(self.glx.glXGetFBConfigAttrib)(self.display, fbconfig, attrib, &mut res);
res
}
pub unsafe fn choose_fb_config(&mut self) -> glx::GLXFBConfig {
let mut trust_window_bit: bool = true;
let vendor = (self.glx.glXGetClientString)(self.display, glx::GLX_VENDOR);
if vendor != ptr::null() {
let vendor_string = ffi::CStr::from_ptr(vendor).to_str().unwrap();
trust_window_bit = vendor_string != "Chromium";
}
let mut native_config_count = 0;
let native_configs =
(self.glx.glXGetFBConfigs)(self.display, self.screen, &mut native_config_count);
println!("GLX configs gotten?");
if native_configs.is_null() || native_config_count == 0 {
panic!("GLX: No GLXFBConfigs returned");
}
let mut usable_configs: Vec<GlFbConfig> = vec![];
for i in 0..(native_config_count as isize) {
let n = native_configs.offset(i);
let mut u = GlFbConfig::default();
if self.glx_attrib(*n, glx::GLX_RENDER_TYPE) & glx::GLX_RGBA_BIT == 0 {
continue;
}
if self.glx_attrib(*n, glx::GLX_DRAWABLE_TYPE) & glx::GLX_WINDOW_BIT == 0 {
if trust_window_bit {
continue;
}
}
u.red_bits = self.glx_attrib(*n, glx::GLX_RED_SIZE);
u.green_bits = self.glx_attrib(*n, glx::GLX_GREEN_SIZE);
u.blue_bits = self.glx_attrib(*n, glx::GLX_BLUE_SIZE);
u.alpha_bits = self.glx_attrib(*n, glx::GLX_ALPHA_SIZE);
u.depth_bits = self.glx_attrib(*n, glx::GLX_DEPTH_SIZE);
u.stencil_bits = self.glx_attrib(*n, glx::GLX_STENCIL_SIZE);
u.doublebuffer = self.glx_attrib(*n, glx::GLX_DOUBLEBUFFER) == 1;
u.samples = self.glx_attrib(*n, glx::GLX_SAMPLES);
u.handle = *n as usize;
usable_configs.push(u);
}
let desired = GlFbConfig {
red_bits: 8,
green_bits: 8,
blue_bits: 8,
alpha_bits: 8,
depth_bits: 24,
stencil_bits: 8,
doublebuffer: true,
samples: 1,
..Default::default()
};
let closest =
gl_choose_fb_config(&desired, &usable_configs).expect("No usable GLXFBConfig found!");
println!("Closest config: {:?}", closest);
closest.handle as *mut _
}
pub fn choose_visual(&mut self) -> (*mut xlib::Visual, i32) {
unsafe {
let native = self.choose_fb_config();
if native.is_null() {
panic!("GLX: Failed to find suitable GLXFBConfig");
}
let result = (self.glx.glXGetVisualFromFBConfig)(self.display, native);
if result.is_null() {
panic!("GLX: Failed to retrieve Visual for GLXFBConfig");
}
let visual = (*result).visual;
let depth = (*result).depth;
(self.xlib.XFree)(result as *mut _);
(visual, depth)
}
}
pub fn glx_create_context(&mut self) {
unsafe {
let native = self.choose_fb_config();
if native.is_null() {
panic!("GLX: Failed to find suitable GLXFBConfig (2)");
}
self.grab_error_handler();
let attribs: [i32; 10] = [
glx::arb::GLX_CONTEXT_MAJOR_VERSION_ARB,
4,
glx::arb::GLX_CONTEXT_MINOR_VERSION_ARB,
3,
glx::arb::GLX_CONTEXT_PROFILE_MASK_ARB,
glx::arb::GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
glx::arb::GLX_CONTEXT_FLAGS_ARB,
glx::arb::GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0,
0,
];
if let Some(f) = self.glx_create_context_attribs_arb {
let glx_ctx = f(
self.display,
native,
ptr::null_mut(),
true,
attribs.as_ptr(),
);
if glx_ctx.is_null() {
panic!("GLX: Failed to create GLX context");
}
} else {
panic!("GLX: glxCreateContextAttribsARB is not found, does your GPU support OpenGL >= 3.3?")
}
let window =
(self.glx.glXCreateWindow)(self.display, native, self.window, ptr::null_mut());
if window == 0 {
panic!("GLX: Failed to create window");
}
self.glx_window = window;
}
}
pub unsafe fn glx_destroy_context(&mut self) {
(self.glx.glXDestroyWindow)(self.display, self.glx_window);
(self.glx.glXDestroyContext)(self.display, self.glx_ctx);
}
unsafe fn glx_make_current(&mut self) {
(self.glx.glXMakeCurrent)(self.display, self.window, self.glx_ctx);
}
unsafe fn glx_swap_buffers(&mut self) {
(self.glx.glXSwapBuffers)(self.display, self.window);
}
unsafe fn glx_swap_interval(&mut self, interval: u32) {
self.glx_make_current();
if let Some(f) = self.glx_swap_interval_ext {
f(self.display, self.glx_window, interval as i32);
} else if let Some(f) = self.glx_swap_interval_mesa {
f(interval as i32);
}
}
pub fn update_window_title(&mut self, title: &str) {
let window_title: *const raw::c_char = ffi::CString::new(title).unwrap().as_ptr();
unsafe {
println!("1");
(self.xlib.XFlush)(self.display);
println!("5");
}
}
pub fn query_window_size(&mut self) -> (u32, u32, u32, u32) {
unsafe {
let mut attribs: xlib::XWindowAttributes = mem::zeroed();
(self.xlib.XGetWindowAttributes)(self.display, self.window, &mut attribs);
let width = attribs.width as u32;
let height = attribs.height as u32;
(width, height, width, height)
}
}
pub fn create_window(&mut self, app: &WFApp, visual: &mut xlib::Visual, depth: i32) {
unsafe {
self.colormap =
(self.xlib.XCreateColormap)(self.display, self.root, visual, xlib::AllocNone);
let mut wa: xlib::XSetWindowAttributes = mem::zeroed();
let wamask = xlib::CWBorderPixel | xlib::CWColormap | xlib::CWEventMask;
wa.colormap = self.colormap;
wa.border_pixel = 0;
wa.event_mask = xlib::StructureNotifyMask
| xlib::KeyPressMask
| xlib::KeyReleaseMask
| xlib::PointerMotionMask
| xlib::ButtonPressMask
| xlib::ButtonReleaseMask
| xlib::ExposureMask
| xlib::FocusChangeMask
| xlib::VisibilityChangeMask
| xlib::EnterWindowMask
| xlib::LeaveWindowMask
| xlib::PropertyChangeMask;
self.grab_error_handler();
self.window = (self.xlib.XCreateWindow)(
self.display,
self.root,
0,
0,
app.window_width,
app.window_height,
0, depth, xlib::InputOutput as u32,
visual,
wamask,
&mut wa,
);
self.release_error_handler();
if self.window == 0 {
panic!("X11: Failed to create window");
}
let protocols = &mut [self.x11_wm_delete_window];
(self.xlib.XSetWMProtocols)(self.display, self.window, protocols.as_mut_ptr(), 1);
{
let hints = (self.xlib.XAllocSizeHints)();
(*hints).flags |= xlib::PWinGravity;
(*hints).win_gravity = xlib::StaticGravity;
(self.xlib.XSetWMNormalHints)(self.display, self.window, hints);
(self.xlib.XFree)(hints as *mut _);
}
self.update_window_title("TODO: Placeholder title");
let _ = self.query_window_size();
}
}
pub fn destroy_window(&mut self) {
unsafe {
if self.window != 0 {
(self.xlib.XUnmapWindow)(self.display, self.window);
(self.xlib.XDestroyWindow)(self.display, self.window);
self.window = 0;
}
if self.colormap != 0 {
(self.xlib.XFreeColormap)(self.display, self.colormap);
self.colormap = 0;
}
(self.xlib.XFlush)(self.display);
}
}
pub fn window_visible(&mut self) -> bool {
unsafe {
let mut wa: xlib::XWindowAttributes = mem::zeroed();
(self.xlib.XGetWindowAttributes)(self.display, self.window, &mut wa);
wa.map_state == xlib::IsViewable
}
}
pub fn show_window(&mut self) {
if !self.window_visible() {
unsafe {
(self.xlib.XMapWindow)(self.display, self.window);
(self.xlib.XRaiseWindow)(self.display, self.window);
(self.xlib.XFlush)(self.display);
}
}
}
pub fn hide_window(&mut self) {
unsafe {
(self.xlib.XUnmapWindow)(self.display, self.window);
(self.xlib.XFlush)(self.display);
}
}
pub unsafe fn get_window_property(
&mut self,
property: xlib::Atom,
typ: xlib::Atom,
value: *mut *mut raw::c_char,
) -> u64 {
let actual_type: &mut xlib::Atom = &mut 0;
let actual_format: &mut i32 = &mut 0;
let item_count: &mut u64 = &mut 0;
let bytes_after: &mut u64 = &mut 0;
(self.xlib.XGetWindowProperty)(
self.display,
self.window,
property,
0,
std::u64::MAX as i64,
0,
typ,
actual_type,
actual_format,
item_count,
bytes_after,
value as _,
);
*item_count
}
pub fn get_window_state(&mut self) -> u32 {
unsafe {
let mut result: u32 = WITHDRAWN_STATE as u32;
#[derive(Debug)]
#[repr(C)]
struct State {
state: x11::xmd::CARD32,
icon: xlib::Window,
};
let state: *mut State = ptr::null_mut();
let r = self.get_window_property(
self.x11_wm_state,
self.x11_wm_state,
&mut (state as *mut _),
);
if r >= 2 && !state.is_null() {
result = (*state).state;
}
if !state.is_null() {
(self.xlib.XFree)(state as *mut _);
}
result
}
}
pub fn x11_mod(mods: u32) -> u32 {
let mut res = 0;
if (mods & xlib::ShiftMask) != 0 {
res |= crate::MOD_SHIFT;
}
if (mods & xlib::ControlMask) != 0 {
res |= crate::MOD_CTRL;
}
if (mods & xlib::Mod1Mask) != 0 {
res |= crate::MOD_ALT;
}
if (mods & xlib::Mod4Mask) != 0 {
res |= crate::MOD_SUPER;
}
res
}
pub fn translate_button(event: *const xlib::XEvent) -> MouseButton {
unsafe {
match (*event).button.button {
xlib::Button1 => MouseButton::Left,
xlib::Button2 => MouseButton::Middle,
xlib::Button3 => MouseButton::Right,
_ => MouseButton::Invalid,
}
}
}
pub fn mouse_event(app: &mut WFApp, typ: EventType, btn: MouseButton, mods: u32) {
let mut e = app.new_event(typ);
e.mouse_button = btn;
e.modifiers = mods;
e.mouse_x = app.mouse_x;
e.mouse_y = app.mouse_y;
app.call_event(&e);
}
pub fn scroll_event(app: &mut WFApp, x: f32, y: f32, mods: u32) {
let mut e = app.new_event(EventType::MouseScroll);
e.scroll_x = x;
e.scroll_y = y;
e.modifiers = mods;
app.call_event(&e);
}
pub fn key_event(app: &mut WFApp, typ: EventType, key: Keycode, repeat: bool, mods: u32) {
let mut e = app.new_event(typ);
e.keycode = key;
e.key_repeat = repeat;
e.modifiers = mods;
app.call_event(&e);
}
pub fn char_event(app: &mut WFApp, chr: char, repeat: bool, mods: u32) {
let mut e = app.new_event(EventType::Char);
e.char_code = chr;
e.key_repeat = repeat;
e.modifiers = mods;
app.call_event(&e);
}
pub fn translate_key(&mut self, scancode: u8) -> Keycode {
unsafe {
let dummy: &mut i32 = &mut 0;
let keysyms = (self.xlib.XGetKeyboardMapping)(self.display, scancode, 1, dummy);
assert_ne!(keysyms, ptr::null_mut());
let keysym = *keysyms as u32;
(self.xlib.XFree)(keysyms as *mut _);
match keysym {
x11::keysym::XK_Escape => Keycode::Escape,
x11::keysym::XK_Tab => Keycode::Tab,
x11::keysym::XK_Shift_L => Keycode::LeftShift,
x11::keysym::XK_Shift_R => Keycode::RightShift,
x11::keysym::XK_Control_L => Keycode::LeftControl,
x11::keysym::XK_Control_R => Keycode::RightControl,
x11::keysym::XK_Meta_L |
x11::keysym::XK_Alt_L => Keycode::LeftAlt,
x11::keysym::XK_Mode_switch |
x11::keysym::XK_ISO_Level3_Shift |
x11::keysym::XK_Meta_R|
x11::keysym::XK_Alt_R => Keycode::RightAlt,
x11::keysym::XK_Super_L => Keycode::LeftSuper,
x11::keysym::XK_Super_R => Keycode::RightSuper,
x11::keysym::XK_Menu => Keycode::Menu,
x11::keysym::XK_Num_Lock => Keycode::NumLock,
x11::keysym::XK_Caps_Lock => Keycode::CapsLock,
x11::keysym::XK_Print => Keycode::PrintScreen,
x11::keysym::XK_Scroll_Lock => Keycode::ScrollLock,
x11::keysym::XK_Pause => Keycode::Pause,
x11::keysym::XK_Delete => Keycode::Delete,
x11::keysym::XK_BackSpace => Keycode::Backspace,
x11::keysym::XK_Return => Keycode::Enter,
x11::keysym::XK_Home => Keycode::Home,
x11::keysym::XK_End => Keycode::End,
x11::keysym::XK_Page_Up => Keycode::PageUp,
x11::keysym::XK_Page_Down => Keycode::PageDown,
x11::keysym::XK_Insert => Keycode::Insert,
x11::keysym::XK_Left => Keycode::Left,
x11::keysym::XK_Right => Keycode::Right,
x11::keysym::XK_Down => Keycode::Down,
x11::keysym::XK_Up => Keycode::Up,
x11::keysym::XK_F1 => Keycode::F1,
x11::keysym::XK_F2 => Keycode::F2,
x11::keysym::XK_F3 => Keycode::F3,
x11::keysym::XK_F4 => Keycode::F4,
x11::keysym::XK_F5 => Keycode::F5,
x11::keysym::XK_F6 => Keycode::F6,
x11::keysym::XK_F7 => Keycode::F7,
x11::keysym::XK_F8 => Keycode::F8,
x11::keysym::XK_F9 => Keycode::F9,
x11::keysym::XK_F10 => Keycode::F10,
x11::keysym::XK_F11 => Keycode::F11,
x11::keysym::XK_F12 => Keycode::F12,
x11::keysym::XK_F13 => Keycode::F13,
x11::keysym::XK_F14 => Keycode::F14,
x11::keysym::XK_F15 => Keycode::F15,
x11::keysym::XK_F16 => Keycode::F16,
x11::keysym::XK_F17 => Keycode::F17,
x11::keysym::XK_F18 => Keycode::F18,
x11::keysym::XK_F19 => Keycode::F19,
x11::keysym::XK_F20 => Keycode::F20,
x11::keysym::XK_F21 => Keycode::F21,
x11::keysym::XK_F22 => Keycode::F22,
x11::keysym::XK_F23 => Keycode::F23,
x11::keysym::XK_F24 => Keycode::F24,
x11::keysym::XK_F25 => Keycode::F25,
x11::keysym::XK_KP_Divide => Keycode::KpDivide,
x11::keysym::XK_KP_Multiply => Keycode::KpMultiply,
x11::keysym::XK_KP_Subtract => Keycode::KpSubtract,
x11::keysym::XK_KP_Add => Keycode::KpAdd,
x11::keysym::XK_KP_Insert => Keycode::Kp0,
x11::keysym::XK_KP_End => Keycode::Kp1,
x11::keysym::XK_KP_Down => Keycode::Kp2,
x11::keysym::XK_KP_Page_Down => Keycode::Kp3,
x11::keysym::XK_KP_Left => Keycode::Kp4,
x11::keysym::XK_KP_Begin => Keycode::Kp5,
x11::keysym::XK_KP_Right => Keycode::Kp6,
x11::keysym::XK_KP_Home => Keycode::Kp7,
x11::keysym::XK_KP_Up => Keycode::Kp8,
x11::keysym::XK_KP_Page_Up => Keycode::Kp9,
x11::keysym::XK_KP_Delete => Keycode::KpDecimal,
x11::keysym::XK_KP_Equal => Keycode::KpEqual,
x11::keysym::XK_KP_Enter => Keycode::KpEnter,
x11::keysym::XK_a => Keycode::A,
x11::keysym::XK_b => Keycode::B,
x11::keysym::XK_c => Keycode::C,
x11::keysym::XK_d => Keycode::D,
x11::keysym::XK_e => Keycode::E,
x11::keysym::XK_f => Keycode::F,
x11::keysym::XK_g => Keycode::G,
x11::keysym::XK_h => Keycode::H,
x11::keysym::XK_i => Keycode::I,
x11::keysym::XK_j => Keycode::J,
x11::keysym::XK_k => Keycode::K,
x11::keysym::XK_l => Keycode::L,
x11::keysym::XK_m => Keycode::M,
x11::keysym::XK_n => Keycode::N,
x11::keysym::XK_o => Keycode::O,
x11::keysym::XK_p => Keycode::P,
x11::keysym::XK_q => Keycode::Q,
x11::keysym::XK_r => Keycode::R,
x11::keysym::XK_s => Keycode::S,
x11::keysym::XK_t => Keycode::T,
x11::keysym::XK_u => Keycode::U,
x11::keysym::XK_v => Keycode::V,
x11::keysym::XK_w => Keycode::W,
x11::keysym::XK_x => Keycode::X,
x11::keysym::XK_y => Keycode::Y,
x11::keysym::XK_z => Keycode::Z,
x11::keysym::XK_1 => Keycode::Num1,
x11::keysym::XK_2 => Keycode::Num2,
x11::keysym::XK_3 => Keycode::Num3,
x11::keysym::XK_4 => Keycode::Num4,
x11::keysym::XK_5 => Keycode::Num5,
x11::keysym::XK_6 => Keycode::Num6,
x11::keysym::XK_7 => Keycode::Num7,
x11::keysym::XK_8 => Keycode::Num8,
x11::keysym::XK_9 => Keycode::Num9,
x11::keysym::XK_0 => Keycode::Num0,
x11::keysym::XK_space => Keycode::Space,
x11::keysym::XK_minus => Keycode::Minus,
x11::keysym::XK_equal => Keycode::Equal,
x11::keysym::XK_bracketleft => Keycode::LeftBracket,
x11::keysym::XK_bracketright => Keycode::RightBracket,
x11::keysym::XK_backslash => Keycode::Backslash,
x11::keysym::XK_semicolon => Keycode::Semicolon,
x11::keysym::XK_apostrophe => Keycode::Apostrophe,
x11::keysym::XK_grave => Keycode::GraveAccent,
x11::keysym::XK_comma => Keycode::Comma,
x11::keysym::XK_period => Keycode::Period,
x11::keysym::XK_slash => Keycode::Slash,
x11::keysym::XK_less => Keycode::World1,
_ => Keycode::Invalid,
}
}
}
pub fn keysym_to_unicode(_keysym: xlib::KeySym) -> Option<char> {
Some('☹')
}
pub fn process_event(&mut self, app: &mut WFApp, event: *mut xlib::XEvent) {
unsafe {
match (*event).type_ {
xlib::KeyPress => {
let keycode = (*event).key.keycode as u8;
let key = self.translate_key(keycode);
let repeat = self.keycodes[keycode as usize];
self.keycodes[keycode as usize] = true;
let mods = Self::x11_mod((*event).key.state);
if key != Keycode::Invalid {
Self::key_event(app, EventType::KeyDown, key, repeat, mods);
}
let keysym: &mut xlib::KeySym = &mut 0;
(self.xlib.XLookupString)(
&mut (*event).key,
ptr::null_mut(),
0,
keysym,
ptr::null_mut(),
);
if let Some(chr) = Self::keysym_to_unicode(*keysym) {
Self::char_event(app, chr, repeat, mods);
}
}
xlib::KeyRelease => {
let keycode = (*event).key.keycode as u8;
let key = self.translate_key(keycode);
self.keycodes[keycode as usize] = false;
let mods = Self::x11_mod((*event).key.state);
if key != Keycode::Invalid {
Self::key_event(app, EventType::KeyUp, key, false, mods);
}
}
xlib::ButtonPress => {
let btn = Self::translate_button(event);
let mods = Self::x11_mod((*event).button.state);
if btn != MouseButton::Invalid {
Self::mouse_event(app, EventType::MouseDown, btn, mods);
} else {
match (*event).button.button {
4 => Self::scroll_event(app, 0.0, 1.0, mods),
5 => Self::scroll_event(app, 0.0, -1.0, mods),
6 => Self::scroll_event(app, 1.0, 0.0, mods),
7 => Self::scroll_event(app, -1.0, 0.0, mods),
_ => (),
}
}
}
xlib::ButtonRelease => {
let btn = Self::translate_button(event);
let mods = Self::x11_mod((*event).button.state);
if btn != MouseButton::Invalid {
Self::mouse_event(app, EventType::MouseUp, btn, mods);
}
}
xlib::EnterNotify => {
let mods = Self::x11_mod((*event).crossing.state);
Self::mouse_event(app, EventType::MouseEnter, MouseButton::Invalid, mods);
}
xlib::LeaveNotify => {
let mods = Self::x11_mod((*event).crossing.state);
Self::mouse_event(app, EventType::MouseLeave, MouseButton::Invalid, mods);
}
xlib::MotionNotify => {
app.mouse_x = (*event).motion.x as f32;
app.mouse_y = (*event).motion.y as f32;
let mods = Self::x11_mod((*event).motion.state);
Self::mouse_event(app, EventType::MouseMove, MouseButton::Invalid, mods);
}
xlib::ConfigureNotify => {
let width = (*event).configure.width as u32;
let height = (*event).configure.height as u32;
if width != app.window_width || height != app.window_height {
app.window_width = width;
app.window_height = height;
app.framebuffer_width = width;
app.framebuffer_height = height;
let event = app.new_event(EventType::Resized);
app.call_event(&event);
}
}
xlib::PropertyNotify => {
if (*event).property.state == xlib::PropertyNewValue
&& (*event).property.atom == self.x11_wm_state
{
let state = self.get_window_state();
if state != self.window_state {
self.window_state = state;
if state == ICONIC_STATE as u32 {
let event = app.new_event(EventType::Iconified);
app.call_event(&event);
} else if state == NORMAL_STATE as u32 {
let event = app.new_event(EventType::Restored);
app.call_event(&event);
}
}
}
}
xlib::ClientMessage => {
if (*event).client_message.message_type == self.x11_wm_protocols {
let protocol = (*event).client_message.data.as_longs()[0] as u64;
if protocol == self.x11_wm_delete_window {
app.quit_requested = true;
}
}
}
xlib::DestroyNotify => {
}
_ => (),
}
}
}
}
pub fn run(desc: &Desc) {
let mut app = WFApp::new(desc);
let xlib = xlib::Xlib::open().unwrap();
let glx = glx::Glx::open().unwrap();
unsafe {
(xlib.XInitThreads)();
(xlib.XrmInitialize)();
let display = (xlib.XOpenDisplay)(ptr::null());
if display.is_null() {
panic!("XOpenDisplay() failed!");
}
let screen = (xlib.XDefaultScreen)(display);
let root = (xlib.XDefaultRootWindow)(display);
(xlib.XkbSetDetectableAutoRepeat)(display, 1, ptr::null_mut());
let dpi = Window::query_system_dpi();
let glx_create_context_attribs_arb =
mem::transmute(Window::getprocaddr(&glx, "glXCreateContextAttribsARB"));
let glx_swap_interval_ext = mem::transmute(Window::getprocaddr(&glx, "glXSwapIntervalEXT"));
let glx_swap_interval_mesa =
mem::transmute(Window::getprocaddr(&glx, "glXSwapIntervalMESA"));
let mut win = Window {
display,
screen,
root,
colormap: 0,
window: 0,
_dpi: dpi,
window_state: 0,
error_code: 0,
xlib,
keycodes: [false; 256],
x11_utf8_string: 0,
x11_wm_protocols: 0,
x11_wm_delete_window: 0,
x11_wm_state: 0,
x11_net_wm_name: 0,
x11_net_wm_icon_name: 0,
glx_ctx: ptr::null_mut(),
glx_window: 0,
glx,
glx_create_context_attribs_arb,
glx_swap_interval_ext,
glx_swap_interval_mesa,
};
win.init_extensions();
println!("Extensions init'd");
let (visual, depth) = win.choose_visual();
win.create_window(&app, &mut *visual, depth);
println!("Window created");
win.glx_create_context();
win.show_window();
win.glx_swap_interval(app.swap_interval);
(win.xlib.XFlush)(win.display);
while !app.quit_ordered {
win.glx_make_current();
let count = (win.xlib.XPending)(win.display);
for _ in 0..count {
let event: &mut xlib::XEvent = &mut mem::zeroed();
(win.xlib.XNextEvent)(win.display, event);
win.process_event(&mut app, event);
}
app.frame();
win.glx_swap_buffers();
(win.xlib.XFlush)(win.display);
if app.quit_requested && !app.quit_ordered {
let event = app.new_event(EventType::QuitRequested);
app.call_event(&event);
if app.quit_requested {
app.quit_ordered = true;
}
}
}
win.glx_destroy_context();
win.destroy_window();
(win.xlib.XCloseDisplay)(win.display);
}
}
#[cfg(test)]
mod tests {
#[test]
fn xlib_open() {
use x11_dl::xlib;
let xl = xlib::Xlib::open().unwrap();
}
#[test]
fn glx_open() {
use x11_dl::glx;
let glx = glx::Glx::open().unwrap();
}
}