use std::ptr;
#[cfg(target_os = "linux")]
use super::PlatformType;
#[cfg(target_os = "linux")]
use std::rc::Rc;
use crate::unsafe_send::Sendable;
#[cfg(target_os = "linux")]
use crate::utils::initialization::NixDisplay;
use crate::utils::ObsError;
#[cfg(target_os = "linux")]
use crate::utils::linux::{wl_display_disconnect, XCloseDisplay};
#[derive(Debug)]
pub(crate) struct PlatformSpecificGuard {
display: Sendable<*mut std::os::raw::c_void>,
platform: PlatformType,
owned: bool,
}
impl Drop for PlatformSpecificGuard {
fn drop(&mut self) {
if !self.owned {
return;
}
match self.platform {
PlatformType::X11 => {
let result = unsafe {
XCloseDisplay(self.display.0)
};
if result != 0 {
eprintln!(
"[libobs-wrapper]: Warning: XCloseDisplay returned non-zero: {}",
result
);
}
}
PlatformType::Wayland => {
unsafe {
wl_display_disconnect(self.display.0);
};
}
_ => {}
}
}
}
#[cfg(not(target_os = "linux"))]
pub(crate) fn platform_specific_setup() -> Result<Option<Rc<PlatformSpecificGuard>>, ObsError> {
return Ok(None);
}
#[cfg(target_os = "linux")]
#[allow(unknown_lints, ensure_obs_call_in_runtime)]
pub(crate) unsafe fn platform_specific_setup(
display: Option<NixDisplay>,
) -> Result<Option<Rc<PlatformSpecificGuard>>, ObsError> {
let mut display_ptr = None;
let mut owned = true;
let platform_type = match display {
Some(NixDisplay::X11(e)) => {
display_ptr = Some(e);
owned = false;
PlatformType::X11
}
Some(NixDisplay::Wayland(e)) => {
display_ptr = Some(e);
owned = false;
PlatformType::Wayland
}
None => {
match detect_platform() {
Some(plat) => plat,
None => {
return Err(ObsError::PlatformInitError(
"Could not detect display server platform".to_string(),
))
}
}
}
};
match platform_type {
PlatformType::X11 => {
use crate::{logger::internal_log_global, utils::linux::XOpenDisplay};
unsafe {
libobs::obs_set_nix_platform(
libobs::obs_nix_platform_type_OBS_NIX_PLATFORM_X11_EGL,
);
}
let display = display_ptr.map(|e| e.0).unwrap_or_else(|| unsafe {
XOpenDisplay(ptr::null())
});
if display.is_null() {
return Err(ObsError::PlatformInitError(
"Failed to open X11 display".to_string(),
));
}
unsafe {
libobs::obs_set_nix_platform_display(display);
}
internal_log_global(
crate::enums::ObsLogLevel::Info,
"[libobs-wrapper]: Detected Platform: EGL/X11".to_string(),
);
Ok(Some(Rc::new(PlatformSpecificGuard {
display: Sendable(display),
platform: PlatformType::X11,
owned,
})))
}
PlatformType::Wayland => {
use crate::{
enums::ObsLogLevel, logger::internal_log_global, utils::linux::wl_display_connect,
};
libobs::obs_set_nix_platform(libobs::obs_nix_platform_type_OBS_NIX_PLATFORM_WAYLAND);
let display = display_ptr
.map(|e| e.0)
.unwrap_or_else(|| wl_display_connect(ptr::null()));
if display.is_null() {
return Err(ObsError::PlatformInitError(
"Failed to connect to Wayland display".to_string(),
));
}
libobs::obs_set_nix_platform_display(display);
internal_log_global(
ObsLogLevel::Info,
"[libobs-wrapper]: Detected Platform: Wayland".to_string(),
);
Ok(Some(Rc::new(PlatformSpecificGuard {
display: Sendable(display),
platform: PlatformType::Wayland,
owned,
})))
}
PlatformType::Invalid => unreachable!(),
}
}
#[cfg(target_os = "linux")]
fn detect_platform() -> Option<PlatformType> {
if std::env::var("WAYLAND_DISPLAY").is_ok() {
return Some(PlatformType::Wayland);
}
if std::env::var("DISPLAY").is_ok() {
if let Ok(session_type) = std::env::var("XDG_SESSION_TYPE") {
return match session_type.as_str() {
"wayland" => Some(PlatformType::Wayland),
"x11" => Some(PlatformType::X11),
_ => None,
};
}
return Some(PlatformType::X11);
}
None
}