Skip to content

Commit

Permalink
native/linux_x11: Better error handling
Browse files Browse the repository at this point in the history
  • Loading branch information
not-fl3 committed Jul 2, 2024
1 parent 07b614a commit 57ef15e
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 47 deletions.
5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,16 @@ where
native::linux_wayland::run(&conf, f).expect("Wayland backend failed")
}
conf::LinuxBackend::X11WithWaylandFallback => {
if native::linux_x11::run(&conf, f).is_none() {
if let Err(err) = native::linux_x11::run(&conf, f) {
eprintln!("{err:?}");
eprintln!("Failed to initialize through X11! Trying wayland instead");
native::linux_wayland::run(&conf, f);
}
}
conf::LinuxBackend::WaylandWithX11Fallback => {
if native::linux_wayland::run(&conf, f).is_none() {
eprintln!("Failed to initialize through wayland! Trying X11 instead");
native::linux_x11::run(&conf, f);
native::linux_x11::run(&conf, f).unwrap()
}
}
}
Expand Down
25 changes: 21 additions & 4 deletions src/native/linux_x11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,31 @@ mod xi_input;

use crate::{
event::EventHandler,
native::{egl, gl, NativeDisplayData, Request},
native::{egl, gl, NativeDisplayData, Request, module},
CursorIcon,
};

use libx11::*;

use std::collections::HashMap;

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum X11Error {
LibraryNotFound(module::Error),
GLXError(String),
}
impl std::fmt::Display for X11Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<module::Error> for X11Error {
fn from(error: module::Error) -> X11Error {
X11Error::LibraryNotFound(error)
}
}
impl std::error::Error for X11Error {}

pub struct X11Display {
libx11: LibX11,
libxkbcommon: LibXkbCommon,
Expand Down Expand Up @@ -352,7 +369,7 @@ where
F: 'static + FnOnce() -> Box<dyn EventHandler>,
{
let mut glx = match glx::Glx::init(&mut display.libx11, display.display, screen, conf) {
Some(glx) => glx,
Ok(glx) => glx,
_ => return Err(display),
};
let visual = glx.visual;
Expand Down Expand Up @@ -543,7 +560,7 @@ where
Ok(())
}

pub fn run<F>(conf: &crate::conf::Conf, f: &mut Option<F>) -> Option<()>
pub fn run<F>(conf: &crate::conf::Conf, f: &mut Option<F>) -> Result<(), X11Error>
where
F: 'static + FnOnce() -> Box<dyn EventHandler>,
{
Expand Down Expand Up @@ -614,5 +631,5 @@ where
}
}
}
Some(())
Ok(())
}
18 changes: 7 additions & 11 deletions src/native/linux_x11/glx.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(dead_code, non_snake_case)]

use super::libx11::*;
use super::{libx11::*, X11Error};

use crate::native::module;

Expand Down Expand Up @@ -128,7 +128,7 @@ pub struct LibGlx {
}

impl LibGlx {
pub fn try_load() -> Option<LibGlx> {
pub fn try_load() -> Result<LibGlx, module::Error> {
module::Module::load("libGL.so")
.or_else(|_| module::Module::load("libGL.so.1"))
.map(|module| LibGlx {
Expand All @@ -149,7 +149,6 @@ impl LibGlx {
glxGetVisualFromFBConfig: module.get_symbol("glXGetVisualFromFBConfig").ok(),
module,
})
.ok()
}

pub unsafe fn get_procaddr(&self, procname: &str) -> Option<unsafe extern "C" fn() -> ()> {
Expand Down Expand Up @@ -217,27 +216,24 @@ impl Glx {
display: *mut Display,
screen: i32,
conf: &crate::conf::Conf,
) -> Option<Glx> {
) -> Result<Glx, X11Error> {
let mut libgl = LibGlx::try_load()?;

let mut errorbase = 0;
let mut eventbase = 0;

if (libgl.glxQueryExtension.unwrap())(display, &mut errorbase, &mut eventbase) == 0 {
eprintln!("GLX: GLX extension not found");
return None;
return Err(X11Error::GLXError("GLX extension not found".to_string()));
}

let mut glx_major = 0;
let mut glx_minor = 0;

if (libgl.glxQueryVersion.unwrap())(display, &mut glx_major, &mut glx_minor) == 0 {
eprintln!("GLX: Failed to query GLX version");
return None;
return Err(X11Error::GLXError("Failed to query GLX version".to_string()));
}
if glx_major == 1 && glx_minor < 3 {
eprintln!("GLX: GLX version 1.3 is required");
return None;
return Err(X11Error::GLXError("GLX version 1.3 is required".to_string()));
}

let exts = (libgl.glxQueryExtensionsString.unwrap())(display, screen);
Expand Down Expand Up @@ -303,7 +299,7 @@ impl Glx {
std::mem::transmute_copy(&libgl.get_procaddr("glXCreateContextAttribsARB"))
};

Some(Glx {
Ok(Glx {
libgl,
multisample,
visual,
Expand Down
7 changes: 3 additions & 4 deletions src/native/linux_x11/libx11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1041,7 +1041,7 @@ pub struct LibX11 {
}

impl LibX11 {
pub fn try_load() -> Option<LibX11> {
pub fn try_load() -> Result<LibX11, module::Error> {
crate::native::module::Module::load("libX11.so")
.or_else(|_| crate::native::module::Module::load("libX11.so.6"))
.map(|module| LibX11 {
Expand Down Expand Up @@ -1095,7 +1095,6 @@ impl LibX11 {
extensions: X11Extensions::default(),
module: std::rc::Rc::new(module),
})
.ok()
}

pub unsafe fn load_extensions(&mut self, display: *mut Display) {
Expand Down Expand Up @@ -1143,14 +1142,14 @@ pub struct LibXkbCommon {
}

impl LibXkbCommon {
pub fn try_load() -> Option<Self> {
pub fn try_load() -> Result<Self, module::Error> {
crate::native::module::Module::load("libxkbcommon.so")
.or_else(|_| crate::native::module::Module::load("libxkbcommon.so.0"))
.or_else(|_| crate::native::module::Module::load("libxkbcommon.so.0.0.0"))
.or_else(|_| crate::native::module::Module::load("libxkbcommon.so.0.0.0.0"))
.map(|module| LibXkbCommon {
xkb_keysym_to_utf32: module.get_symbol("xkb_keysym_to_utf32").unwrap(),
module: std::rc::Rc::new(module),
})
.ok()
}
}
10 changes: 5 additions & 5 deletions src/native/linux_x11/xi_input.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![allow(non_upper_case_globals, non_snake_case)]

use crate::native::module;
use super::{
libx11::{self, Display, Window, _XPrivDisplay},
xi_input,
Expand Down Expand Up @@ -64,7 +65,7 @@ type XFreeEventData = fn(_: *mut Display, _: *mut libx11::XGenericEventCookie);

#[derive(Clone)]
pub struct LibXi {
_module: std::rc::Rc<crate::native::module::Module>,
_module: std::rc::Rc<module::Module>,
_XQueryExtension: XQueryExtension,
XIQueryVersion: XIQueryVersion,
XISelectEvents: XISelectEvents,
Expand All @@ -74,9 +75,9 @@ pub struct LibXi {
}

impl LibXi {
pub fn try_load() -> Option<LibXi> {
crate::native::module::Module::load("libXi.so")
.or_else(|_| crate::native::module::Module::load("libXi.so.6"))
pub fn try_load() -> Result<LibXi, module::Error> {
module::Module::load("libXi.so")
.or_else(|_| module::Module::load("libXi.so.6"))
.map(|module| LibXi {
_XQueryExtension: module.get_symbol("XQueryExtension").unwrap(),
XIQueryVersion: module.get_symbol("XIQueryVersion").unwrap(),
Expand All @@ -86,7 +87,6 @@ impl LibXi {
xi_extension_opcode: None,
_module: std::rc::Rc::new(module),
})
.ok()
}

pub unsafe fn query_xi_extension(
Expand Down
36 changes: 15 additions & 21 deletions src/native/module.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Error {
DlOpenError,
DlSymError,
DlOpenError(String),
DlSymError(String),
}

#[cfg(any(target_os = "linux", target_os = "android"))]
Expand All @@ -17,25 +17,21 @@ pub mod linux {

impl Module {
pub fn load(path: &str) -> Result<Self, Error> {
let path = CString::new(path).unwrap();

let module = unsafe { dlopen(path.as_ptr(), RTLD_LAZY | RTLD_LOCAL) };
let cpath = CString::new(path).unwrap();
let module = unsafe { dlopen(cpath.as_ptr(), RTLD_LAZY | RTLD_LOCAL) };
if module.is_null() {
Err(Error::DlOpenError)
Err(Error::DlOpenError(path.to_string()))
} else {
Ok(Module(unsafe { NonNull::new_unchecked(module) }))
}
}

pub fn get_symbol<F: Sized>(&self, name: &str) -> Result<F, Error> {
let name = CString::new(name).unwrap();

let symbol = unsafe { dlsym(self.0.as_ptr(), name.as_ptr()) };

let cname = CString::new(name).unwrap();
let symbol = unsafe { dlsym(self.0.as_ptr(), cname.as_ptr()) };
if symbol.is_null() {
return Err(Error::DlSymError);
return Err(Error::DlSymError(name.to_string()));
}

Ok(unsafe { std::mem::transmute_copy::<_, F>(&symbol) })
}
}
Expand All @@ -59,20 +55,18 @@ mod windows {

impl Module {
pub fn load(path: &str) -> Result<Self, Error> {
let path = std::ffi::CString::new(path).unwrap();
let library = unsafe { LoadLibraryA(path.as_ptr()) };

let cpath = std::ffi::CString::new(path).unwrap();
let library = unsafe { LoadLibraryA(cpath.as_ptr()) };
if library.is_null() {
return Err(Error::DlOpenError);
return Err(Error::DlOpenError(path.to_string()));
}
Ok(Self(library))
}
pub fn get_symbol<F: Sized>(&self, name: &str) -> Result<F, Error> {
let name = std::ffi::CString::new(name).unwrap();
let proc = unsafe { GetProcAddress(self.0, name.as_ptr() as *const _) };

let cname = std::ffi::CString::new(name).unwrap();
let proc = unsafe { GetProcAddress(self.0, cname.as_ptr() as *const _) };
if proc.is_null() {
return Err(Error::DlSymError);
return Err(Error::DlSymError(name.to_string()));
}
return Ok(unsafe { std::mem::transmute_copy(&proc) });
}
Expand Down

0 comments on commit 57ef15e

Please sign in to comment.