### Start Xwayland and Attach X11 Window Manager Source: https://docs.rs/smithay/latest/src/smithay/xwayland/xwm/mod Initiates an Xwayland instance and attaches an X11 Window Manager (X11Wm) to it. This process involves spawning Xwayland, handling its ready event to obtain the X11 socket, and then starting the X11Wm. The X11Wm is responsible for managing X11 windows within the Wayland compositor. This requires a `LoopHandle` for event loop integration. ```rust use smithay::wayland::xwayland_shell::{XWaylandShellHandler, XWaylandShellState}; use smithay::wayland::selection::SelectionTarget; use smithay::xwayland::{XWayland, XWaylandEvent, X11Wm, X11Surface, XwmHandler, xwm::{XwmId, ResizeEdge, Reorder}}; use smithay::utils::{Rectangle, Logical}; use std::os::unix::io::OwnedFd; use std::process::Stdio; struct State { /* ... */ } # impl XWaylandShellHandler for State { # fn xwayland_shell_state(&mut self) -> &mut XWaylandShellState { # unreachable!() # } # } impl XwmHandler for State { fn xwm_state(&mut self, xwm: XwmId) -> &mut X11Wm { // ... # unreachable!() } fn new_window(&mut self, xwm: XwmId, window: X11Surface) { /* ... */ } fn new_override_redirect_window(&mut self, xwm: XwmId, window: X11Surface) { /* ... */ } fn map_window_request(&mut self, xwm: XwmId, window: X11Surface) { /* ... */ } fn mapped_override_redirect_window(&mut self, xwm: XwmId, window: X11Surface) { /* ... */ } fn unmapped_window(&mut self, xwm: XwmId, window: X11Surface) { /* ... */ } fn destroyed_window(&mut self, xwm: XwmId, window: X11Surface) { /* ... */ } fn configure_request(&mut self, xwm: XwmId, window: X11Surface, x: Option, y: Option, w: Option, h: Option, reorder: Option) { /* ... */ } fn configure_notify(&mut self, xwm: XwmId, window: X11Surface, geometry: Rectangle, above: Option) { /* ... */ } fn resize_request(&mut self, xwm: XwmId, window: X11Surface, button: u32, resize_edge: ResizeEdge) { /* ... */ } fn move_request(&mut self, xwm: XwmId, window: X11Surface, button: u32) { /* ... */ } fn send_selection(&mut self, xwm: XwmId, selection: SelectionTarget, mime_type: String, fd: OwnedFd) { /* ... */ } } # # let dh = unreachable!(); # let handle: smithay::reexports::calloop::LoopHandle<'static, State> = unreachable!(); let (xwayland, client) = XWayland::spawn( &dh, None, std::iter::empty::<(String, String)>(), true, Stdio::null(), Stdio::null(), |_| (), ) .expect("failed to start XWayland"); let ret = handle.insert_source(xwayland, move |event, _, data| match event { XWaylandEvent::Ready { x11_socket, display_number: _, } => { let wm = X11Wm::start_wm( handle.clone(), x11_socket, client.clone(), ) .expect("Failed to attach X11 Window Manager"); // store the WM somewhere } XWaylandEvent::Error => eprintln!("XWayland failed to start!"), }); if let Err(e) = ret { tracing::error!( "Failed to insert the XWaylandSource into the event loop: {}", e ); } ``` -------------------------------- ### Start Xwayland Window Manager in Rust Source: https://docs.rs/smithay/latest/src/smithay/xwayland/xwm/mod Initializes and starts a new Xwayland window manager. This function sets up the X11 connection, configures root window attributes and event masks, acquires selection ownership for WM protocols, and sets EWMH properties. It requires an event loop handle, display handle, X11 connection, and Wayland client. ```rust impl X11Wm { /// Start a new window manager for a given Xwayland connection /// /// ## Arguments /// - `handle` is an eventloop handle used to queue up and handle incoming X11 events /// - `dh` is the corresponding display handle to the wayland connection of the Xwayland instance /// - `connection` is the corresponding x11 client connection of the Xwayland instance /// - `client` is the wayland client instance of the Xwayland instance pub fn start_wm( handle: LoopHandle<'static, D>, connection: UnixStream, client: wayland_server::Client, ) -> Result> where D: XwmHandler, D: xwayland_shell::XWaylandShellHandler, D: 'static, { let id = XwmId(xwm_id::next()); let span = debug_span!("xwayland_wm", id = id.0); let _guard = span.enter(); // Create an X11 connection. XWayland only uses screen 0. let screen = 0; let stream = DefaultStream::from_unix_stream(connection)?.0; let conn = RustConnection::connect_to_stream(stream, screen)?; let atoms = Atoms::new(&conn)?.reply()?; let screen = conn.setup().roots[0].clone(); let randr_primary = conn.randr_get_output_primary(screen.root)?.reply()?.output; { let font = FontWrapper::open_font(&conn, "cursor".as_bytes())?; let cursor = CursorWrapper::create_glyph_cursor( &conn, font.font(), font.font(), 68, 69, 0, 0, 0, u16::MAX, u16::MAX, u16::MAX, )?; // Actually become the WM by redirecting some operations conn.change_window_attributes( screen.root, &ChangeWindowAttributesAux::default() .event_mask( EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY | EventMask::PROPERTY_CHANGE | EventMask::FOCUS_CHANGE, ) // and also set a default root cursor in case downstream doesn't .cursor(cursor.cursor()), )?; // Watch for primary output changes conn.randr_select_input(screen.root, NotifyMask::OUTPUT_CHANGE)?; } // Tell XWayland that we are the WM by acquiring the WM_S0 selection. No X11 clients are accepted before this. let win = conn.generate_id()?; conn.create_window( screen.root_depth, win, screen.root, // x, y, width, height, border width 0, 0, 1, 1, 0, WindowClass::INPUT_OUTPUT, x11rb::COPY_FROM_PARENT, &Default::default(), )?; conn.set_selection_owner(win, atoms.WM_S0, x11rb::CURRENT_TIME)?; conn.set_selection_owner(win, atoms._NET_WM_CM_S0, x11rb::CURRENT_TIME)?; conn.composite_redirect_subwindows(screen.root, Redirect::MANUAL)?; // Set some EWMH properties conn.change_property32( PropMode::REPLACE, screen.root, atoms._NET_SUPPORTED, AtomEnum::ATOM, &[ atoms._NET_WM_STATE, atoms._NET_WM_STATE_MAXIMIZED_HORZ, atoms._NET_WM_STATE_MAXIMIZED_VERT, atoms._NET_WM_STATE_HIDDEN, atoms._NET_WM_STATE_FULLSCREEN, atoms._NET_WM_STATE_MODAL, atoms._NET_WM_STATE_FOCUSED, atoms._NET_ACTIVE_WINDOW, atoms._NET_WM_MOVERESIZE, atoms._NET_CLIENT_LIST, atoms._NET_CLIENT_LIST_STACKING, ], )?; conn.change_property32( PropMode::REPLACE, screen.root, atoms._NET_CLIENT_LIST, // Code truncated here... ``` -------------------------------- ### Initialize X11 Backend and Create Window Source: https://docs.rs/smithay/latest/src/smithay/backend/x11/mod Demonstrates initializing the X11 backend, creating a window, and setting up surfaces for rendering. It involves obtaining the DRM node, creating a GbmDevice and EGL context for buffer allocation, and integrating the backend with the calloop event loop. This requires the `smithay` crate and its associated backend features. ```rust # use std::{sync::{Arc, Mutex}, error::Error}; # use smithay::backend::x11::{X11Backend, X11Surface, WindowBuilder}; use smithay::backend::allocator::dmabuf::DmabufAllocator; use smithay::backend::allocator::gbm::{GbmAllocator, GbmDevice, GbmBufferFlags}; use smithay::backend::egl::{EGLDisplay, EGLContext}; use smithay::utils::DeviceFd; use std::collections::HashSet; # struct CompositorState; fn init_x11_backend( handle: calloop::LoopHandle, ) -> Result<(), Box> { // Create the backend let backend = X11Backend::new()?; // Get a handle from the backend to interface with the X server let x_handle = backend.handle(); // Create a window let window = WindowBuilder::new() .title("Wayland inside X11") .build(&x_handle) .expect("Could not create window"); // To render to a window, we need to create an X11 surface. // Get the DRM node used by the X server for direct rendering. let (_drm_node, fd) = x_handle.drm_node()?; // Create the gbm device for allocating buffers let device = GbmDevice::new(DeviceFd::from(fd?))?; // Initialize EGL to retrieve the support modifier list let egl = unsafe { EGLDisplay::new(device.clone()).expect("Failed to create EGLDisplay") }; let context = EGLContext::new(&egl).expect("Failed to create EGLContext"); let modifiers = context.dmabuf_render_formats().iter().map(|format| format.modifier).collect::>(); // Finally create the X11 surface, you will use this to obtain buffers that will be presented to the // window. let surface = x_handle.create_surface(&window, DmabufAllocator(GbmAllocator::new(device, GbmBufferFlags::RENDERING)), modifiers.into_iter()); // Insert the backend into the event loop to receive events. handle.insert_source(backend, |event, _window, state| { // Process events from the X server that apply to the window. })?; Ok(()) } ``` -------------------------------- ### Get strides for Dmabuf planes Source: https://docs.rs/smithay/latest/src/smithay/backend/allocator/dmabuf Provides an iterator over the strides (in bytes) for each plane of the Dmabuf. The stride defines the number of bytes from the start of one row to the start of the next. ```Rust pub fn strides(&self) -> impl Iterator + '_ { self.0.planes.iter().map(|p| p.stride) } ``` -------------------------------- ### Rust: Get Grab Start Data Source: https://docs.rs/smithay/latest/src/smithay/input/keyboard/mod Retrieves the initial data associated with an active keyboard grab. If a grab is active, it clones and returns the start data; otherwise, it returns None. This is useful for restoring or understanding the context of a grab. ```rust pub fn grab_start_data(&self) -> Option> { let guard = self.arc.internal.lock().unwrap(); match &guard.grab { GrabStatus::Active(_, g) => Some(g.start_data().clone()), _ => None, } } ``` -------------------------------- ### Initialize X11 Backend with EGL and GBM Source: https://docs.rs/smithay/latest/smithay/backend/x11/index Demonstrates the initialization of the X11 backend, including setting up EGL for rendering and GBM for buffer allocation. This setup allows a Wayland compositor to function as an X11 client. It requires the `backend_x11` feature flag. ```rust use smithay::backend::allocator::dmabuf::DmabufAllocator; use smithay::backend::allocator::gbm::{GbmAllocator, GbmDevice, GbmBufferFlags}; use smithay::backend::egl::{EGLDisplay, EGLContext}; use smithay::utils::DeviceFd; use std::collections::HashSet; use std::error::Error; fn init_x11_backend( handle: calloop::LoopHandle, ) -> Result<(), Box> { // Create the backend let backend = X11Backend::new()?; // Get a handle from the backend to interface with the X server let x_handle = backend.handle(); // Create a window let window = WindowBuilder::new() .title("Wayland inside X11") .build(&x_handle) .expect("Could not create window"); // To render to a window, we need to create an X11 surface. // Get the DRM node used by the X server for direct rendering. let (_drm_node, fd) = x_handle.drm_node()?; // Create the gbm device for allocating buffers let device = GbmDevice::new(DeviceFd::from(fd))?; // Initialize EGL to retrieve the support modifier list let egl = unsafe { EGLDisplay::new(device.clone()).expect("Failed to create EGLDisplay") }; let context = EGLContext::new(&egl).expect("Failed to create EGLContext"); let modifiers = context.dmabuf_render_formats().iter().map(|format| format.modifier).collect::>(); // Finally create the X11 surface, you will use this to obtain buffers that will be presented to the // window. let surface = x_handle.create_surface(&window, DmabufAllocator(GbmAllocator::new(device, GbmBufferFlags::RENDERING)), modifiers.into_iter()); // Insert the backend into the event loop to receive events. handle.insert_source(backend, |event, _window, state| { // Process events from the X server that apply to the window. })?; Ok(()) } ``` -------------------------------- ### Initialize and Monitor Udev Devices in Rust Source: https://docs.rs/smithay/latest/smithay/backend/udev/index Demonstrates how to initialize the `UdevBackend` for monitoring DRM devices and integrate it into a `calloop` event loop. It shows how to process an initial list of devices and handle subsequent events like device addition, change, or removal. Requires the `backend_udev` crate feature. ```rust use smithay::backend::udev::{UdevBackend, UdevEvent}; let udev = UdevBackend::new("seat0").expect("Failed to monitor udev."); for (dev_id, node_path) in udev.device_list() { // process the initial list of devices } // setup the event source for long-term monitoring loop_handle.insert_source(udev, |event, _, _dispatch_data| match event { UdevEvent::Added { device_id, path } => { // a new device has been added }, UdevEvent::Changed { device_id } => { // a device has been changed }, UdevEvent::Removed { device_id } => { // a device has been removed } }).expect("Failed to insert the udev source into the event loop"); ``` -------------------------------- ### Get Grab Start Data (Rust) Source: https://docs.rs/smithay/latest/src/smithay/input/touch/mod Retrieves the initial data associated with an active touch grab. This function locks the inner state, checks for an active grab, and returns a clone of its start data if available. It is part of the touch handling mechanism for managing input events. ```rust /// Returns the start data for the grab, if any. pub fn grab_start_data(&self) -> Option> { let guard = self.inner.lock().unwrap(); match &guard.grab { GrabStatus::Active(_, g) => Some(g.start_data().clone()), _ => None, } } ``` -------------------------------- ### Example Usage of wp_content_type Protocol with Smithay Source: https://docs.rs/smithay/latest/src/smithay/wayland/content_type/mod Demonstrates how to use the wp_content_type protocol within a Smithay compositor. It shows the setup required for the compositor and content type states, and how to access content type information during a surface commit event. This example requires `wayland-server` and Smithay dependencies. ```rust # extern crate wayland_server; # use wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle}; use smithay::{ delegate_content_type, delegate_compositor, wayland::compositor::{self, CompositorState, CompositorClientState, CompositorHandler}, wayland::content_type::{ContentTypeSurfaceCachedState, ContentTypeState}, }; pub struct State { compositor_state: CompositorState, }; struct ClientState { compositor_state: CompositorClientState } impl wayland_server::backend::ClientData for ClientState {} delegate_content_type!(State); delegate_compositor!(State); impl CompositorHandler for State { fn compositor_state(&mut self) -> &mut CompositorState { &mut self.compositor_state } fn client_compositor_state<'a>(&self, client: &'a wayland_server::Client) -> &'a CompositorClientState { &client.get_data::().unwrap().compositor_state } fn commit(&mut self, surface: &WlSurface) { compositor::with_states(&surface, |states| { let mut guard = states.cached_state.get::(); let current = guard.current(); dbg!(current.content_type()); }); } } let mut display = wayland_server::Display::::new().unwrap(); let compositor_state = CompositorState::new::(&display.handle()); ContentTypeState::new::(&display.handle()); let state = State { compositor_state, }; ``` -------------------------------- ### Initialize and Monitor Udev Backend Source: https://docs.rs/smithay/latest/src/smithay/backend/udev Demonstrates how to initialize the UdevBackend to monitor DRM devices and integrate it with the calloop event loop. It includes handling initial device lists and processing UdevEvents like Added, Changed, and Removed. ```rust use smithay::backend::udev::{UdevBackend, UdevEvent}; let udev = UdevBackend::new("seat0").expect("Failed to monitor udev."); for (dev_id, node_path) in udev.device_list() { // process the initial list of devices } # let event_loop = smithay::reexports::calloop::EventLoop::<()>::try_new().unwrap(); # let loop_handle = event_loop.handle(); // setup the event source for long-term monitoring loop_handle.insert_source(udev, |event, _, _dispatch_data| match event { UdevEvent::Added { device_id, path } => { // a new device has been added }, UdevEvent::Changed { device_id } => { // a device has been changed }, UdevEvent::Removed { device_id } => { // a device has been removed } }).expect("Failed to insert the udev source into the event loop"); ``` -------------------------------- ### Get Vulkan Physical Device Type (Rust) Source: https://docs.rs/smithay/latest/src/smithay/backend/vulkan/mod Retrieves the type of the Vulkan physical device (e.g., integrated GPU, discrete GPU). This can be used for selecting a preferred device during application setup. ```rust pub fn ty(&self) -> vk::PhysicalDeviceType { self.info.properties.device_type } ``` -------------------------------- ### Initialize LibinputInputBackend in Rust Source: https://docs.rs/smithay/latest/src/smithay/backend/libinput/mod Creates a new `LibinputInputBackend` instance from an existing `libinput` context. This backend tracks input devices managed by `libinput`. ```rust use crate::backend::input::{self as backend, Axis, AxisRelativeDirection, AxisSource, InputBackend, InputEvent}; use input as libinput; use std::{io, os::unix::io::{AsFd, BorrowedFd}, path::PathBuf}; use calloop::{EventSource, Interest, Mode, Poll, PostAction, Readiness, Token, TokenFactory}; use tracing::{debug_span, info, trace}; /// Libinput based [`InputBackend`]. /// /// Tracks input of all devices given manually or via a udev seat to a provided libinput /// context. #[derive(Debug)] pub struct LibinputInputBackend { context: libinput::Libinput, token: Option, span: tracing::Span, } impl LibinputInputBackend { /// Initialize a new [`LibinputInputBackend`] from a given already initialized /// [libinput context](libinput::Libinput). pub fn new(context: libinput::Libinput) -> Self { let span = debug_span!("backend_libinput"); let _guard = span.enter(); info!("Initializing a libinput backend"); drop(_guard); LibinputInputBackend { context, token: None, span, } } /// Returns a reference to the underlying libinput context pub fn context(&self) -> &libinput::Libinput { &self.context } } ``` -------------------------------- ### Winit Backend Initialization Source: https://docs.rs/smithay/latest/src/smithay/backend/winit/mod Provides functions to initialize the winit backend, returning a WinitGraphicsBackend and WinitEventLoop. ```APIDOC ## `init` ### Description Creates a new [`WinitGraphicsBackend`] which implements the [`Renderer`] trait, and a corresponding [`WinitEventLoop`]. Uses default window attributes. ### Method `fn init() -> Result<(WinitGraphicsBackend, WinitEventLoop), Error>` ### Parameters None ### Type Parameters * `R`: A type that implements `From` and `Bind`. `crate::backend::SwapBuffersError` must be convertible from `R::Error`. ### Response - `Ok((WinitGraphicsBackend, WinitEventLoop))`: On successful initialization. - `Err(Error)`: If initialization fails. ### Request Example ```rust // Example usage, assuming R is GlesRenderer let (backend, event_loop): (WinitGraphicsBackend, WinitEventLoop) = smithay::backend::winit::init().unwrap(); ``` ## `init_from_attributes` ### Description Creates a new [`WinitGraphicsBackend`] which implements the [`Renderer`] trait, from a given [`WindowAttributes`] struct and a corresponding [`WinitEventLoop`]. ### Method `fn init_from_attributes(attributes: WindowAttributes) -> Result<(WinitGraphicsBackend, WinitEventLoop), Error>` ### Parameters * `attributes` (`WindowAttributes`): The attributes to use for creating the winit window. ### Type Parameters * `R`: A type that implements `From` and `Bind`. `crate::backend::SwapBuffersError` must be convertible from `R::Error`. ### Response - `Ok((WinitGraphicsBackend, WinitEventLoop))`: On successful initialization. - `Err(Error)`: If initialization fails. ### Request Example ```rust use winit::window::WindowAttributes; let attributes = WindowAttributes::default() .with_inner_size(winit::dpi::LogicalSize::new(800.0, 600.0)) .with_title("My Smithay Window"); let (backend, event_loop): (WinitGraphicsBackend, WinitEventLoop) = smithay::backend::winit::init_from_attributes(attributes).unwrap(); ``` ## `init_from_attributes_with_gl_attr` ### Description Creates a new [`WinitGraphicsBackend`] which implements the [`Renderer`] trait, from a given [`WindowAttributes`] struct, as well as given [`GlAttributes`] for further customization of the rendering pipeline and a corresponding [`WinitEventLoop`]. ### Method `fn init_from_attributes_with_gl_attr(attributes: WindowAttributes, gl_attributes: GlAttributes) -> Result<(WinitGraphicsBackend, WinitEventLoop), Error>` ### Parameters * `attributes` (`WindowAttributes`): The attributes to use for creating the winit window. * `gl_attributes` (`GlAttributes`): The OpenGL attributes for customizing the rendering context. ### Type Parameters * `R`: A type that implements `From` and `Bind`. `crate::backend::SwapBuffersError` must be convertible from `R::Error`. ### Response - `Ok((WinitGraphicsBackend, WinitEventLoop))`: On successful initialization. - `Err(Error)`: If initialization fails. ### Request Example ```rust use winit::window::WindowAttributes; use smithay::backend::egl::GlAttributes; let attributes = WindowAttributes::default() .with_inner_size(winit::dpi::LogicalSize::new(1024.0, 768.0)); let gl_attributes = GlAttributes { version: (3, 3), profile: None, debug: true, vsync: true, }; let (backend, event_loop): (WinitGraphicsBackend, WinitEventLoop) = smithay::backend::winit::init_from_attributes_with_gl_attr(attributes, gl_attributes).unwrap(); ``` ``` -------------------------------- ### Get Metadata of Paths with Error Handling in Rust Source: https://docs.rs/smithay/latest/smithay/backend/drm/output/type Shows how to use `Path::metadata()` and `and_then` to safely retrieve file metadata, handling potential I/O errors like 'NotFound'. This example illustrates robust path manipulation. ```rust use std::{io::ErrorKind, path::Path}; // Note: on Windows "/" maps to "C:\" let root_modified_time = Path::new("/").metadata().and_then(|md| md.modified()); assert!(root_modified_time.is_ok()); let should_fail = Path::new("/bad/path").metadata().and_then(|md| md.modified()); assert!(should_fail.is_err()); assert_eq!(should_fail.unwrap_err().kind(), ErrorKind::NotFound); ``` -------------------------------- ### Get Raw EGLSurface Handle in Rust Source: https://docs.rs/smithay/latest/smithay/backend/egl/surface/struct Retrieves a raw EGLSurface handle. Note that this handle might become invalid if the surface is recreated, for example, during a buffer swap. The handle is also invalidated when the EGLSurface struct is destroyed. ```rust pub fn get_surface_handle(&self) -> EGLSurface ``` -------------------------------- ### Select EGL Platform and Display Source: https://docs.rs/smithay/latest/src/smithay/backend/egl/display Selects a suitable EGL platform and retrieves the corresponding EGL display handle. It iterates through available platforms, attempts to create an EGL display for each, and returns the first successful one. Errors during display creation are logged, and unsupported platforms are skipped. ```rust unsafe fn select_platform_display(native: &N, dp_extensions: &[&str]) -> Result<(ffi::egl::types::EGLDisplay, &'static str), Error> where N: EGLNativeDisplay + 'static, { let supported_platforms: Vec<(&'static str, ffi::egl::types::EGLenum)> = vec![ ("X11", ffi::egl::X11_PLATFORM), ("DRM", ffi::egl::DRM_PLATFORM), ("WAYLAND", ffi::egl::WAYLAND_PLATFORM), ("HEADLESS", ffi::egl::PLATFORM_ANDROID), ("HEADLESS", ffi::egl::PLATFORM_HEADLESS), ]; for platform in supported_platforms { info!("Trying EGL platform: {}", platform.0); if !dp_extensions.contains(&"EGL_EXT_platform_base") || !dp_extensions.contains(&"EGL_EXT_platform_xcb") && platform.1 == ffi::egl::X11_PLATFORM { info!("Skipping platform because of missing extensions"); continue; } let display = ffi::egl::GetPlatformDisplay( platform.1, native.get_native_display(), platform.attrib_list.as_ptr(), ) .map_err(Error::DisplayCreationError); let display = match display { Ok(display) => { if display == ffi::egl::NO_DISPLAY { info!("Skipping platform because the display is not supported"); continue; } display } Err(err) => { info!("Skipping platform because of an display creation error: {:?}", err); continue; } }; info!("Successfully selected EGL platform: {}", platform.0); return Ok((display, platform.0)); } error!("Unable to find suitable EGL platform"); Err(Error::DisplayNotSupported) } ``` -------------------------------- ### Retrieve Alpha Multiplier from WlSurface State Source: https://docs.rs/smithay/latest/src/smithay/wayland/alpha_modifier/mod Provides an example of how to access and retrieve the alpha multiplier set for a Wayland surface using Smithay's compositor state management. It demonstrates using `with_states` to get cached state. ```rust use smithay::wayland::compositor; use smithay::wayland::alpha_modifier::AlphaModifierSurfaceCachedState; # let wl_surface = todo!(); compositor::with_states(&wl_surface, |states| { let mut modifier_state = states.cached_state.get::(); dbg!(modifier_state.current().multiplier()); }); ``` -------------------------------- ### Initialize and Render with DrmCompositor (Rust) Source: https://docs.rs/smithay/latest/smithay/backend/drm/compositor/index Demonstrates how to initialize a DrmCompositor for a given output, DRM device, and allocator. It then shows the process of rendering a frame with provided elements, clearing the screen, and queuing the frame for display. This requires a Wayland output, DRM surface, allocator, and renderer. ```rust use smithay::{ backend::drm:: compositor::{DrmCompositor, FrameFlags}, exporter::gbm::GbmFramebufferExporter, DrmSurface, }, output::{Output, PhysicalProperties, Subpixel}, utils::Size, }; // ...initialize the output, drm device, drm surface and allocator let output = Output::new( "e-DP".into(), PhysicalProperties { size: Size::from((800, 600)), make: "N/A".into(), model: "N/A".into(), subpixel: Subpixel::Unknown, }, ); let mut compositor: DrmCompositor<_, _, (), _> = DrmCompositor::new( &output, surface, None, allocator, exporter, color_formats, renderer_formats, device.cursor_size(), Some(gbm), ) .expect("failed to initialize drm compositor"); let render_frame_result = compositor .render_frame::<_, _>(&mut renderer, &elements, CLEAR_COLOR, FrameFlags::DEFAULT) .expect("failed to render frame"); if !render_frame_result.is_empty { compositor.queue_frame(()).expect("failed to queue frame"); // ...wait for VBlank event compositor .frame_submitted() .expect("failed to mark frame as submitted"); } else { // ...re-schedule frame } ``` -------------------------------- ### Get Pointer Grab Start Data Source: https://docs.rs/smithay/latest/src/smithay/desktop/wayland/popup/grab Returns the `PointerGrabStartData` for the current popup grab. Similar to keyboard grab data, the focus is fixed on the root surface to maintain the grab's active state and prevent unintended disengagement. ```rust /// Convenience method for getting a [`PointerGrabStartData`] for this grab. /// /// The focus of the [`PointerGrabStartData`] will always be the root /// of the popup grab, e.g. the surface of the toplevel, to make sure /// the grab is not automatically unset. pub fn pointer_grab_start_data(&self) -> &PointerGrabStartData { &self.pointer_grab_start_data } ``` -------------------------------- ### Create and Configure a Smithay Output Source: https://docs.rs/smithay/latest/src/smithay/output Demonstrates how to instantiate an `Output` with physical properties and then change its current state, including resolution, transformation, scaling, and position. It also shows how to set the preferred mode and add other supported modes. ```rust use smithay::output::{Output, PhysicalProperties, Scale, Mode, Subpixel}; use smithay::utils::Transform; // Create the Output with given name and physical properties. let output = Output::new( "output-0".into(), // the name of this output, PhysicalProperties { size: (200, 150).into(), // dimensions (width, height) in mm subpixel: Subpixel::HorizontalRgb, // subpixel information make: "Screens Inc".into(), // make of the monitor model: "Monitor Ultra".into(), // model of the monitor }, ); // Now you can configure it output.change_current_state( Some(Mode { size: (1920, 1080).into(), refresh: 60000 }), // the resolution mode, Some(Transform::Normal), // global screen transformation Some(Scale::Integer(1)), // global screen scaling factor Some((0,0).into()) // output position ); // set the preferred mode output.set_preferred(Mode { size: (1920, 1080).into(), refresh: 60000 }); // add other supported modes output.add_mode(Mode { size: (800, 600).into(), refresh: 60000 }); output.add_mode(Mode { size: (1024, 768).into(), refresh: 60000 }); ``` -------------------------------- ### Instance Creation API Source: https://docs.rs/smithay/latest/src/smithay/backend/vulkan/mod Provides methods for creating a Vulkan Instance, with options to specify application information and extensions. ```APIDOC ## POST /instance/new ### Description Creates a new Vulkan Instance with the specified maximum version and optional application information. ### Method POST ### Endpoint /instance/new ### Parameters #### Query Parameters - **max_version** (Version) - Required - The maximum Vulkan version supported by the application. - **app_info** (AppInfo) - Optional - Information about the application, including its name and version. ### Request Body (Not applicable for this endpoint, parameters are passed via query) ### Request Example ```json { "max_version": "1.2", "app_info": { "name": "MyVulkanApp", "version": "1.0.0" } } ``` ### Response #### Success Response (200) - **Instance** (Instance) - A handle to the created Vulkan Instance. #### Response Example ```json { "instance": "" } ``` ## POST /instance/with_extensions ### Description Creates a new Vulkan Instance with specified extensions. This method is unsafe and requires careful adherence to Vulkan's valid usage requirements. ### Method POST ### Endpoint /instance/with_extensions ### Parameters #### Query Parameters - **max_version** (Version) - Required - The maximum Vulkan version supported by the application. - **app_info** (AppInfo) - Optional - Information about the application, including its name and version. - **extensions** (Array) - Optional - An array of static C strings representing the desired instance extensions. ### Request Body (Not applicable for this endpoint, parameters are passed via query) ### Request Example ```json { "max_version": "1.3", "app_info": { "name": "MyAdvancedApp", "version": "0.1.0" }, "extensions": [ "VK_EXT_debug_utils", "VK_KHR_surface" ] } ``` ### Response #### Success Response (200) - **Instance** (Instance) - A handle to the created Vulkan Instance. #### Response Example ```json { "instance": "" } ``` ### Error Handling - **InstanceError::UnsupportedVersion**: Returned if the Vulkan driver does not support at least version 1.1. - **LoadError**: Returned if the Vulkan library cannot be loaded or if there are allocation errors during instance creation. - **UnsupportedProperty**: Returned if required extensions are not available. ``` -------------------------------- ### Get Keyboard Grab Start Data Source: https://docs.rs/smithay/latest/src/smithay/desktop/wayland/popup/grab Provides access to the `KeyboardGrabStartData` associated with this grab. The focus within this data is consistently set to the root surface of the popup grab to ensure the grab's integrity, preventing automatic unsetting. ```rust /// Convenience method for getting a [`KeyboardGrabStartData`] for this grab. /// /// The focus of the [`KeyboardGrabStartData`] will always be the root /// of the popup grab, e.g. the surface of the toplevel, to make sure /// the grab is not automatically unset. pub fn keyboard_grab_start_data(&self) -> &KeyboardGrabStartData { &self.keyboard_grab_start_data } ``` -------------------------------- ### Initialize LibinputInputBackend (Rust) Source: https://docs.rs/smithay/latest/smithay/backend/libinput/struct Provides a constructor function `new` for `LibinputInputBackend`. It takes an already initialized libinput context and returns a new instance of the backend. This is the primary way to set up libinput-based input handling. ```rust pub fn new(context: Libinput) -> Self ``` -------------------------------- ### Get PointerGrabStartData in Rust Source: https://docs.rs/smithay/latest/src/smithay/wayland/selection/data_device/dnd_grab This Rust code defines a method to retrieve a reference to the `PointerGrabStartData` associated with a `PointerGrab` implementation. This data structure likely holds information about the initial state of the pointer grab, such as the starting focus and button states. ```rust fn start_data(&self) -> &PointerGrabStartData { ``` -------------------------------- ### XKB Context Management Source: https://docs.rs/smithay/latest/smithay/input/keyboard/xkb/ffi/index Functions for creating, configuring, and managing XKB contexts. ```APIDOC ## XKB Context Management ### Description Provides functions for creating, configuring, and managing XKB contexts, which are essential for handling keyboard input. ### Functions - **xkb_context_new()**: Creates a new XKB context. - **xkb_context_unref()**: Decrements the reference count of an XKB context. - **xkb_context_ref()**: Increments the reference count of an XKB context. - **xkb_context_set_user_data()**: Sets user data for the XKB context. - **xkb_context_get_user_data()**: Retrieves user data from the XKB context. - **xkb_context_set_log_fn()**: Sets a custom logging function for the XKB context. - **xkb_context_set_log_level()**: Sets the log level for the XKB context. - **xkb_context_get_log_level()**: Retrieves the current log level of the XKB context. - **xkb_context_set_log_verbosity()**: Sets the log verbosity for the XKB context. - **xkb_context_get_log_verbosity()**: Retrieves the current log verbosity of the XKB context. - **xkb_context_include_path_append()**: Appends a directory to the XKB include path. - **xkb_context_include_path_append_default()**: Appends default XKB include directories. - **xkb_context_include_path_clear()**: Clears the XKB include path. - **xkb_context_include_path_get()**: Retrieves the XKB include path. - **xkb_context_include_path_reset_defaults()**: Resets the XKB include path to defaults. - **xkb_context_num_include_paths()**: Returns the number of directories in the XKB include path. ### Type Aliases - **xkb_context_flags**: Flags for configuring XKB context creation. - **xkb_log_fn_t**: Type for a custom logging function. ``` -------------------------------- ### Example Usage of XdgDialogHandler and XdgShellHandler in Smithay Source: https://docs.rs/smithay/latest/src/smithay/wayland/shell/xdg/dialog Demonstrates how to integrate XdgDialogState and XdgShellState within a compositor's state. It includes implementing necessary traits like XdgShellHandler and XdgDialogHandler, and using delegate macros for event handling. This setup is crucial for enabling xdg-dialog functionality. ```rust # extern crate wayland_server; # use smithay::{delegate_xdg_dialog, delegate_xdg_shell}; use smithay::wayland::shell::xdg::{ToplevelSurface, XdgShellHandler}; # use smithay::utils::Serial; # use smithay::wayland::shell::xdg::{XdgShellState, PopupSurface, PositionerState}; # use smithay::reexports::wayland_server::protocol::{wl_seat, wl_surface}; use smithay::wayland::shell::xdg::dialog::{XdgDialogState, XdgDialogHandler}; # struct State { dialog_state: XdgDialogState, seat_state: SeatState } # let mut display = wayland_server::Display::::new().unwrap(); // Create a dialog state let dialog_state = XdgDialogState::new::( &display.handle(), ); // store that state inside your compositor state // ... // implement the necessary traits impl XdgShellHandler for State { # fn xdg_shell_state(&mut self) -> &mut XdgShellState { unimplemented!() } # fn new_toplevel(&mut self, surface: ToplevelSurface) { unimplemented!() } # fn new_popup( # &mut self, # surface: PopupSurface, # positioner: PositionerState, # ) { unimplemented!() } # fn grab( # &mut self, # surface: PopupSurface, # seat: wl_seat::WlSeat, # serial: Serial, # ) { unimplemented!() } # fn reposition_request( # &mut self, # surface: PopupSurface, # positioner: PositionerState, # token: u32, # ) { unimplemented!() } // ... } impl XdgDialogHandler for State { fn modal_changed(&mut self, toplevel: ToplevelSurface, is_modal: bool) { /* ... */ } } use smithay::input::{Seat, SeatState, SeatHandler, pointer::CursorImageStatus}; type Target = wl_surface::WlSurface; impl SeatHandler for State { type KeyboardFocus = Target; type PointerFocus = Target; type TouchFocus = Target; fn seat_state(&mut self) -> &mut SeatState { &mut self.seat_state } fn focus_changed(&mut self, seat: &Seat, focused: Option<&Target>) { // handle focus changes, if you need to ... } fn cursor_image(&mut self, seat: &Seat, image: CursorImageStatus) { // handle new images for the cursor ... } } delegate_xdg_shell!(State); delegate_xdg_dialog!(State); // You are ready to go! ``` -------------------------------- ### Prepare X11 Sockets and Locks in Rust Source: https://docs.rs/smithay/latest/src/smithay/xwayland/x11_sockets This function finds a free X11 display, acquires a lock file to ensure exclusive access, and then opens the necessary Unix domain sockets for communication. It can either use a provided display number or iterate through common display numbers (0-32) to find an available one. Errors during lock acquisition or socket creation are handled and returned. ```Rust use std::io::{Read, Write}; use std::os::unix::net::UnixStream; use tracing::{debug, info, warn}; use rustix::{io::Errno, net::SocketAddrUnix}; /// Find a free X11 display slot and setup pub(crate) fn prepare_x11_sockets( display: Option, open_abstract_socket: bool, ) -> Result<(X11Lock, Vec), std::io::Error> { match display { Some(d) => { if let Ok(lock) = X11Lock::grab(d) { // we got a lockfile, try and create the socket match open_x11_sockets_for_display(d, open_abstract_socket) { Ok(sockets) => return Ok((lock, sockets)), Err(err) => return Err(std::io::Error::from(err)), }; } } None => { for d in 0..33 { // if fails, try the next one if let Ok(lock) = X11Lock::grab(d) { // we got a lockfile, try and create the socket match open_x11_sockets_for_display(d, open_abstract_socket) { Ok(sockets) => return Ok((lock, sockets)), Err(err) => warn!(display = d, "Failed to create sockets: {}", err), } } } // If we reach here, all values from 0 to 32 failed // we need to stop trying at some point } } Err(std::io::Error::new( std::io::ErrorKind::AddrInUse, "Could not find a free socket for the XServer.", )) } ``` -------------------------------- ### Mutex Initialization Example Source: https://docs.rs/smithay/latest/smithay/wayland/shell/wlr_layer/type Provides a basic example of creating a new Mutex instance with an initial value. ```rust use std::sync::Mutex; let mutex = Mutex::new(0); ``` -------------------------------- ### Create and Configure X11 Window with Builder Source: https://docs.rs/smithay/latest/src/smithay/backend/x11/mod Demonstrates the use of `WindowBuilder` to create a new X11 window. It allows setting window properties such as title and size before building the window. The builder handles default values if properties are not explicitly set. ```rust let window = WindowBuilder::new() .title("My Window") .size((800, 600).into()) .build(&x11_handle)?; window.map(); ```