baseview 0.4.2

Low-level windowing system geared towards making audio plugin UIs.
Documentation
use super::prelude::*;
use calloop::{LoopHandle, LoopSignal};
use dpi::Size;
use raw_window_handle::{DisplayHandle, XlibWindowHandle};
use std::time::Duration;
use x11rb::protocol::xproto;
use x11rb::protocol::xproto::Visualid;

/// Data that is shared between the event loop and the window handler.
pub struct WindowShared {
    pub xcb_window: XcbWindow,
    pub connection: Rc<X11Connection>,
    visual_id: Visualid,

    pub is_focused: Cell<bool>,

    pub cursor_state: CursorStateShared,
    pub present_state: PresentStateShared,
    pub sizing_state: SizingStateShared,

    loop_signal: LoopSignal,
    loop_handle: LoopHandle<'static, EventLoop>,

    pub main_thread_shared: Arc<WindowThreadShared>,

    #[cfg(feature = "opengl")]
    gl_context: Option<PlatformGlContext>,
}

impl WindowShared {
    pub(crate) fn create(
        mut settings: WindowSettings, ev_loop: &calloop::EventLoop<'static, EventLoop>,
        thread_shared: Arc<WindowThreadShared>,
    ) -> PlatformResult<Rc<Self>> {
        let connection = X11Connection::connect()?;

        let sizing_state = SizingStateShared::load(&connection, &thread_shared.sizing, &settings)?;

        let connection = Rc::new(connection);

        let visual_config =
            WindowVisualConfig::find_best_visual_config(&connection, &mut settings)?;

        let parent_id = settings.parent.map(|p| p.inner.window_id);

        let xcb_window =
            XcbWindow::new(Rc::clone(&connection), sizing_state.size(), &visual_config, parent_id)?;

        let cookies = [
            xcb_window.set_title(&settings.title)?,
            xcb_window.enable_wm_protocols()?,
            xcb_window.enable_dnd_protocols()?,
            xcb_window.set_size_hints(sizing_state.make_size_hints())?,
        ];

        for cookie in cookies {
            cookie.check()?;
        }

        Ok(Rc::new(Self {
            visual_id: visual_config.visual_id,

            #[cfg(feature = "opengl")]
            gl_context: visual_config.make_gl_context(&xcb_window, &connection)?,

            loop_signal: ev_loop.get_signal(),
            loop_handle: ev_loop.handle(),

            is_focused: false.into(),

            cursor_state: CursorStateShared::new(),
            present_state: PresentStateShared::new(),
            sizing_state,
            main_thread_shared: thread_shared,

            xcb_window,
            connection,
        }))
    }

    pub fn set_mouse_cursor(&self, mouse_cursor: MouseCursor) -> PlatformResult<()> {
        self.cursor_state.set_mouse_cursor(mouse_cursor, &self.xcb_window)
    }

    pub fn request_close(&self) {
        self.loop_signal.stop();
        self.loop_signal.wakeup();
    }

    pub fn request_redraw(&self) {
        self.present_state.request_present_notify()
    }

    pub fn request_redraw_after(&self, duration: Duration) {
        self.present_state.request_present_notify_after(duration, &self.loop_handle);
    }

    pub fn waker(&self) -> WindowWaker {
        WindowWaker {
            loop_signal: self.loop_signal.clone(),
            shared: Arc::clone(&self.main_thread_shared),
        }
    }

    pub fn has_focus(&self) -> bool {
        self.is_focused.get()
    }

    pub fn focus(&self) -> PlatformResult<()> {
        self.xcb_window.focus()
    }

    pub fn resize(&self, new_size: Size) -> PlatformResult<()> {
        self.sizing_state.resize_from_handler(new_size, &self.xcb_window)
    }

    pub fn window_handle(&self) -> Option<raw_window_handle::WindowHandle<'_>> {
        let mut handle = XlibWindowHandle::new(self.xcb_window.id().get() as _);
        handle.visual_id = self.visual_id.into();
        Some(unsafe { raw_window_handle::WindowHandle::borrow_raw(handle.into()) })
    }

    pub fn display_handle(&self) -> DisplayHandle<'_> {
        self.connection.conn.xlib_display_handle()
    }

    pub fn platform_handle(&self) -> super::PlatformHandle {
        super::PlatformHandle {
            connection: Arc::clone(&self.connection.conn),
            window_id: self.xcb_window.id(),
            visual_id: self.visual_id,
        }
    }

    #[cfg(feature = "opengl")]
    pub fn gl_context(&self) -> Option<GlContext> {
        Some(GlContext::new(Rc::clone(self.gl_context.as_ref()?)))
    }

    #[inline]
    pub fn create_timer(&self, duration: Duration) -> PlatformResult<TimerHandle> {
        insert_timer(&self.loop_handle, duration)
    }

    pub fn scale_factor(&self) -> f64 {
        self.sizing_state.scale_factor()
    }

    pub fn size(&self) -> WindowSize {
        self.sizing_state.window_size()
    }

    pub fn raw_id(&self) -> xproto::Window {
        self.xcb_window.id().get()
    }
}