#![cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "netbsd", target_os = "openbsd"))]
use std::{os::raw, ptr, sync::Arc};
use smithay_client_toolkit::window::{ButtonState as SCTKButtonState, Theme as SCTKTheme};
use crate::{
dpi::Size,
event_loop::{EventLoop, EventLoopWindowTarget},
monitor::MonitorHandle,
window::{Window, WindowBuilder},
};
use crate::platform_impl::{
x11::{ffi::XVisualInfo, XConnection},
EventLoop as LinuxEventLoop, EventLoopWindowTarget as LinuxEventLoopWindowTarget,
Window as LinuxWindow,
};
#[doc(hidden)]
pub use crate::platform_impl::x11;
pub use crate::platform_impl::{x11::util::WindowType as XWindowType, XNotSupported};
pub trait EventLoopWindowTargetExtUnix {
fn is_wayland(&self) -> bool;
fn is_x11(&self) -> bool;
#[doc(hidden)]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
fn wayland_display(&self) -> Option<*mut raw::c_void>;
}
impl<T> EventLoopWindowTargetExtUnix for EventLoopWindowTarget<T> {
#[inline]
fn is_wayland(&self) -> bool {
self.p.is_wayland()
}
#[inline]
fn is_x11(&self) -> bool {
!self.p.is_wayland()
}
#[inline]
#[doc(hidden)]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
match self.p {
LinuxEventLoopWindowTarget::X(ref e) => Some(e.x_connection().clone()),
_ => None,
}
}
#[inline]
fn wayland_display(&self) -> Option<*mut raw::c_void> {
match self.p {
LinuxEventLoopWindowTarget::Wayland(ref p) => {
Some(p.display().get_display_ptr() as *mut _)
}
_ => None,
}
}
}
pub trait EventLoopExtUnix {
fn new_x11() -> Result<Self, XNotSupported>
where
Self: Sized;
fn new_wayland() -> Self
where
Self: Sized;
fn new_any_thread() -> Self
where
Self: Sized;
fn new_x11_any_thread() -> Result<Self, XNotSupported>
where
Self: Sized;
fn new_wayland_any_thread() -> Self
where
Self: Sized;
}
fn wrap_ev<T>(event_loop: LinuxEventLoop<T>) -> EventLoop<T> {
EventLoop {
event_loop,
_marker: std::marker::PhantomData,
}
}
impl<T> EventLoopExtUnix for EventLoop<T> {
#[inline]
fn new_any_thread() -> Self {
wrap_ev(LinuxEventLoop::new_any_thread())
}
#[inline]
fn new_x11_any_thread() -> Result<Self, XNotSupported> {
LinuxEventLoop::new_x11_any_thread().map(wrap_ev)
}
#[inline]
fn new_wayland_any_thread() -> Self {
wrap_ev(
LinuxEventLoop::new_wayland_any_thread()
.expect("failed to open Wayland connection"),
)
}
#[inline]
fn new_x11() -> Result<Self, XNotSupported> {
LinuxEventLoop::new_x11().map(wrap_ev)
}
#[inline]
fn new_wayland() -> Self {
wrap_ev(
LinuxEventLoop::new_wayland()
.expect("failed to open Wayland connection"),
)
}
}
pub trait WindowExtUnix {
fn xlib_window(&self) -> Option<raw::c_ulong>;
fn xlib_display(&self) -> Option<*mut raw::c_void>;
fn xlib_screen_id(&self) -> Option<raw::c_int>;
#[doc(hidden)]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>>;
fn set_urgent(&self, is_urgent: bool);
fn xcb_connection(&self) -> Option<*mut raw::c_void>;
fn wayland_surface(&self) -> Option<*mut raw::c_void>;
fn wayland_display(&self) -> Option<*mut raw::c_void>;
fn set_wayland_theme<T: Theme>(&self, theme: T);
#[deprecated]
fn is_ready(&self) -> bool;
}
impl WindowExtUnix for Window {
#[inline]
fn xlib_window(&self) -> Option<raw::c_ulong> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_window()),
_ => None,
}
}
#[inline]
fn xlib_display(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_display()),
_ => None,
}
}
#[inline]
fn xlib_screen_id(&self) -> Option<raw::c_int> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_screen_id()),
_ => None,
}
}
#[inline]
#[doc(hidden)]
fn xlib_xconnection(&self) -> Option<Arc<XConnection>> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xlib_xconnection()),
_ => None,
}
}
#[inline]
fn set_urgent(&self, is_urgent: bool) {
if let LinuxWindow::X(ref w) = self.window {
w.set_urgent(is_urgent);
}
}
#[inline]
fn xcb_connection(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::X(ref w) => Some(w.xcb_connection()),
_ => None,
}
}
#[inline]
fn wayland_surface(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::Wayland(ref w) => Some(w.surface().as_ref().c_ptr() as *mut _),
_ => None,
}
}
#[inline]
fn wayland_display(&self) -> Option<*mut raw::c_void> {
match self.window {
LinuxWindow::Wayland(ref w) => Some(w.display().as_ref().c_ptr() as *mut _),
_ => None,
}
}
#[inline]
fn set_wayland_theme<T: Theme>(&self, theme: T) {
match self.window {
LinuxWindow::Wayland(ref w) => w.set_theme(WaylandTheme(theme)),
_ => {}
}
}
#[inline]
fn is_ready(&self) -> bool {
true
}
}
pub trait WindowBuilderExtUnix {
fn with_x11_visual<T>(self, visual_infos: *const T) -> Self;
fn with_x11_screen(self, screen_id: i32) -> Self;
fn with_class(self, class: String, instance: String) -> Self;
fn with_override_redirect(self, override_redirect: bool) -> Self;
fn with_x11_window_type(self, x11_window_type: Vec<XWindowType>) -> Self;
fn with_gtk_theme_variant(self, variant: String) -> Self;
fn with_resize_increments<S: Into<Size>>(self, increments: S) -> Self;
fn with_base_size<S: Into<Size>>(self, base_size: S) -> Self;
fn with_app_id(self, app_id: String) -> Self;
}
impl WindowBuilderExtUnix for WindowBuilder {
#[inline]
fn with_x11_visual<T>(mut self, visual_infos: *const T) -> Self {
self.platform_specific.visual_infos =
Some(unsafe { ptr::read(visual_infos as *const XVisualInfo) });
self
}
#[inline]
fn with_x11_screen(mut self, screen_id: i32) -> Self {
self.platform_specific.screen_id = Some(screen_id);
self
}
#[inline]
fn with_class(mut self, instance: String, class: String) -> Self {
self.platform_specific.class = Some((instance, class));
self
}
#[inline]
fn with_override_redirect(mut self, override_redirect: bool) -> Self {
self.platform_specific.override_redirect = override_redirect;
self
}
#[inline]
fn with_x11_window_type(mut self, x11_window_types: Vec<XWindowType>) -> Self {
self.platform_specific.x11_window_types = x11_window_types;
self
}
#[inline]
fn with_gtk_theme_variant(mut self, variant: String) -> Self {
self.platform_specific.gtk_theme_variant = Some(variant);
self
}
#[inline]
fn with_resize_increments<S: Into<Size>>(mut self, increments: S) -> Self {
self.platform_specific.resize_increments = Some(increments.into());
self
}
#[inline]
fn with_base_size<S: Into<Size>>(mut self, base_size: S) -> Self {
self.platform_specific.base_size = Some(base_size.into());
self
}
#[inline]
fn with_app_id(mut self, app_id: String) -> Self {
self.platform_specific.app_id = Some(app_id);
self
}
}
pub trait MonitorHandleExtUnix {
fn native_id(&self) -> u32;
}
impl MonitorHandleExtUnix for MonitorHandle {
#[inline]
fn native_id(&self) -> u32 {
self.inner.native_identifier()
}
}
struct WaylandTheme<T: Theme>(T);
pub trait Theme: Send + 'static {
fn primary_color(&self, window_active: bool) -> [u8; 4];
fn secondary_color(&self, window_active: bool) -> [u8; 4];
fn close_button_color(&self, status: ButtonState) -> [u8; 4];
#[allow(unused_variables)]
fn close_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
self.secondary_color(true)
}
fn maximize_button_color(&self, status: ButtonState) -> [u8; 4];
#[allow(unused_variables)]
fn maximize_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
self.secondary_color(true)
}
fn minimize_button_color(&self, status: ButtonState) -> [u8; 4];
#[allow(unused_variables)]
fn minimize_button_icon_color(&self, status: ButtonState) -> [u8; 4] {
self.secondary_color(true)
}
}
impl<T: Theme> SCTKTheme for WaylandTheme<T> {
fn get_primary_color(&self, active: bool) -> [u8; 4] {
self.0.primary_color(active)
}
fn get_secondary_color(&self, active: bool) -> [u8; 4] {
self.0.secondary_color(active)
}
fn get_close_button_color(&self, status: SCTKButtonState) -> [u8; 4] {
self.0.close_button_color(ButtonState::from_sctk(status))
}
fn get_close_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4] {
self.0.close_button_color(ButtonState::from_sctk(status))
}
fn get_maximize_button_color(&self, status: SCTKButtonState) -> [u8; 4] {
self.0.maximize_button_color(ButtonState::from_sctk(status))
}
fn get_maximize_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4] {
self.0
.maximize_button_icon_color(ButtonState::from_sctk(status))
}
fn get_minimize_button_color(&self, status: SCTKButtonState) -> [u8; 4] {
self.0.minimize_button_color(ButtonState::from_sctk(status))
}
fn get_minimize_button_icon_color(&self, status: SCTKButtonState) -> [u8; 4] {
self.0
.minimize_button_icon_color(ButtonState::from_sctk(status))
}
}
pub enum ButtonState {
Hovered,
Idle,
Disabled,
}
impl ButtonState {
fn from_sctk(button_state: SCTKButtonState) -> Self {
match button_state {
SCTKButtonState::Hovered => Self::Hovered,
SCTKButtonState::Idle => Self::Idle,
SCTKButtonState::Disabled => Self::Disabled,
}
}
}