├── .build.yml ├── .gitignore ├── .gitmodules ├── .rustfmt.toml ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── cat.data ├── minimal.rs ├── pointer.rs ├── rotation.rs ├── tablet.rs ├── touch.rs └── xdg_shell_v6_test.rs ├── makefile ├── src ├── backend │ ├── backend.rs │ ├── drm.rs │ ├── headless.rs │ ├── libinput.rs │ ├── mod.rs │ ├── multi.rs │ ├── session.rs │ ├── wayland.rs │ └── x11.rs ├── compositor.rs ├── events │ ├── key_events.rs │ ├── mod.rs │ ├── pointer_events.rs │ ├── seat_events.rs │ ├── switch_events.rs │ ├── tablet_pad_events.rs │ ├── tablet_tool_events.rs │ ├── touch_events.rs │ ├── xdg_shell_events.rs │ ├── xdg_shell_v6_events.rs │ └── xwayland_events.rs ├── extensions │ ├── gamma_control.rs │ ├── gtk_primary_selection.rs │ ├── idle.rs │ ├── idle_inhibit.rs │ ├── input_inhibit.rs │ ├── mod.rs │ ├── screencopy.rs │ ├── screenshooter.rs │ └── server_decoration.rs ├── lib.rs ├── macros.rs ├── manager │ ├── drag_icon_handler.rs │ ├── input_manager.rs │ ├── keyboard_handler.rs │ ├── mod.rs │ ├── output_handler.rs │ ├── output_manager.rs │ ├── pointer_handler.rs │ ├── switch_handler.rs │ ├── tablet_pad_handler.rs │ ├── tablet_tool_handler.rs │ ├── touch_handler.rs │ ├── xdg_shell_handler.rs │ ├── xdg_shell_manager.rs │ ├── xdg_shell_v6_handler.rs │ └── xdg_shell_v6_manager.rs ├── render │ ├── image.rs │ ├── matrix.rs │ ├── mod.rs │ ├── pixman_region.rs │ ├── renderer.rs │ └── texture.rs ├── types │ ├── area.rs │ ├── cursor │ │ ├── cursor.rs │ │ ├── mod.rs │ │ ├── xcursor.rs │ │ └── xcursor_manager.rs │ ├── data_device │ │ ├── data_source.rs │ │ ├── manager.rs │ │ └── mod.rs │ ├── dmabuf.rs │ ├── input │ │ ├── input_device.rs │ │ ├── keyboard.rs │ │ ├── mod.rs │ │ ├── pointer.rs │ │ ├── switch.rs │ │ ├── tablet_pad.rs │ │ ├── tablet_tool.rs │ │ └── touch.rs │ ├── mod.rs │ ├── output │ │ ├── cursor.rs │ │ ├── damage.rs │ │ ├── layout.rs │ │ ├── mod.rs │ │ ├── mode.rs │ │ └── output.rs │ ├── seat │ │ ├── drag_icon.rs │ │ ├── grab.rs │ │ ├── mod.rs │ │ ├── seat.rs │ │ ├── seat_client.rs │ │ └── touch_point.rs │ ├── shell │ │ ├── mod.rs │ │ ├── xdg_shell.rs │ │ └── xdg_shell_v6.rs │ └── surface │ │ ├── mod.rs │ │ ├── subsurface.rs │ │ ├── subsurface_manager.rs │ │ ├── surface.rs │ │ └── surface_state.rs ├── utils │ ├── edges.rs │ ├── handle.rs │ ├── log.rs │ ├── mod.rs │ ├── region.rs │ ├── string.rs │ └── time.rs └── xwayland │ ├── hints.rs │ ├── manager.rs │ ├── mod.rs │ ├── server.rs │ └── surface.rs ├── wlroots-dehandle ├── Cargo.toml └── src │ └── lib.rs └── wlroots-sys ├── Cargo.toml ├── build.rs └── src ├── lib.rs └── wlroots.h /.build.yml: -------------------------------------------------------------------------------- 1 | image: archlinux 2 | packages: 3 | - meson 4 | - ninja 5 | - wayland 6 | - wayland-protocols 7 | - mesa 8 | - libinput 9 | - pixman 10 | - libxkbcommon 11 | - xcb-util-image 12 | - libcap 13 | - rustup 14 | - clang 15 | - libxcb 16 | - xorg-xinput 17 | - xcb-util-image 18 | - xcb-util-cursor 19 | - xcb-util-wm 20 | sources: 21 | - https://github.com/swaywm/wlroots-rs 22 | tasks: 23 | - setup: | 24 | rustup install stable 25 | export CC=clang 26 | rustup default stable 27 | export RUST_BACKTRACE=full 28 | cd wlroots-rs 29 | git submodule update --init --recursive 30 | - build: | 31 | export RUSTFLAGS="-D warnings" 32 | cd wlroots-rs 33 | cd wlroots-sys 34 | cd wlroots 35 | 36 | meson build 37 | ninja -C build 38 | cd ../ 39 | 40 | cargo build --verbose --features static 41 | cd ../ 42 | 43 | cargo build --verbose 44 | cargo build --verbose --features="static, unstable" 45 | # Test dynamic building as well 46 | cargo build --verbose --features="unstable" 47 | cargo build --examples 48 | cargo build --examples --features="static, unstable" 49 | # For doc tests 50 | cargo doc 51 | cargo doc --features="static, unstable" 52 | cargo test --all --features="static, unstable" 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | gen.rs 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "wlroots-sys/wlroots"] 2 | path = wlroots-sys/wlroots 3 | url = https://github.com/SirCmpwn/wlroots 4 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | # line length 2 | error_on_line_overflow = true 3 | max_width = 110 4 | 5 | # comments 6 | comment_width = 100 7 | wrap_comments = false # rustfmt is broken currently and doesn't softwrap 8 | normalize_comments = true 9 | 10 | # commas 11 | trailing_comma = "Never" 12 | match_block_trailing_comma = true 13 | 14 | # code 15 | use_try_shorthand = true 16 | binop_separator = "Back" 17 | format_strings = false # rustfmt string handling is horribly busted 18 | 19 | # imports 20 | reorder_imports = true 21 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["wlroots-sys", "wlroots-dehandle"] 3 | 4 | [package] 5 | name = "wlroots" 6 | version = "0.4.0" 7 | authors = ["Timidger "] 8 | repository = "https://github.com/swaywm/wlroots-rs" 9 | documentation = "https://docs.rs/wlroots" 10 | description = "Wayland compositor framework" 11 | keywords = ["wayland", "compositor", "bindings"] 12 | categories = ["external-ffi-bindings", "gui"] 13 | license = "MIT" 14 | exclude = [".travis.yml"] 15 | autoexamples = true 16 | edition = "2018" 17 | 18 | [dependencies] 19 | wlroots-sys = { path = "wlroots-sys", default-features = false, version = "0.4.0" } 20 | wlroots-dehandle = { path = "wlroots-dehandle", version = "2.0" } 21 | xkbcommon = "0.3" 22 | bitflags = "1.0" 23 | vsprintf = "1.0.1" 24 | log = "0.4" 25 | 26 | [features] 27 | default = ["libcap", "systemd", "elogind", "xwayland", "x11_backend"] 28 | static = ["wlroots-sys/static"] 29 | libcap = ["wlroots-sys/libcap"] 30 | systemd = ["wlroots-sys/systemd"] 31 | elogind = ["wlroots-sys/elogind"] 32 | x11_backend = ["wlroots-sys/x11_backend"] 33 | xwayland = ["wlroots-sys/xwayland"] 34 | xcb_errors = ["wlroots-sys/xcb_errors"] 35 | xcb_icccm = ["wlroots-sys/xcb_icccm"] 36 | unstable = ["wlroots-sys/unstable"] 37 | 38 | [[example]] 39 | name = "minimal" 40 | required-features = ["unstable"] 41 | 42 | [[example]] 43 | name = "pointer" 44 | required-features = ["unstable"] 45 | 46 | [[example]] 47 | name = "rotation" 48 | required-features = ["unstable"] 49 | 50 | [[example]] 51 | name = "touch" 52 | required-features = ["unstable"] 53 | 54 | [[example]] 55 | name = "tablet" 56 | required-features = ["unstable"] 57 | 58 | [[example]] 59 | name = "xdg_shell_v6_test" 60 | required-features = ["unstable"] 61 | 62 | # This will build the unstable features for documentation on docs.rs 63 | [package.metadata.docs.rs] 64 | features = ["libcap", "systemd", "elogind", "unstable"] 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Immington Industries 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # wlroots-rs 2 | [![Crates.io](https://img.shields.io/crates/v/wlroots.svg)](https://crates.io/crates/wlroots) 3 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/way-cooler/wlroots-rs/) 4 | 5 | **This is no longer maintained.** As an alternative consider 6 | [smithay](https://github.com/Smithay/smithay). 7 | 8 | Safe Rust bindings for [wlroots](https://github.com/SirCmpwn/wlroots). 9 | 10 | This library is currently tracking the wlroots version for its minor version. Patch versions are wlroots-rs specific. 11 | 12 | # [Documentation](http://way-cooler.org/docs/wlroots/index.html) 13 | 14 | # Building 15 | To build wlroots-rs you have to init the wlroots submodule first and have all wlroots dependencies. 16 | 17 | git submodule update --init 18 | cargo build 19 | 20 | If you want to compile against wlroots statically, add the `"static"` flag. 21 | 22 | If you want use unstable wlroots features then add the `"unstable"` flag. 23 | 24 | # Examples 25 | See [the examples directory](https://github.com/swaywm/wlroots-rs/tree/master/examples) for basic examples. 26 | 27 | You can run an example using the following command: 28 | ```bash 29 | cargo run --example 30 | ``` 31 | -------------------------------------------------------------------------------- /examples/cat.data: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaywm/wlroots-rs/05c373002451a5abc5728ca672f3e67fddd12fbc/examples/cat.data -------------------------------------------------------------------------------- /examples/minimal.rs: -------------------------------------------------------------------------------- 1 | extern crate log; 2 | extern crate wlroots; 3 | 4 | use log::LevelFilter; 5 | 6 | fn main() { 7 | wlroots::utils::log::Logger::init(LevelFilter::Debug, None); 8 | wlroots::compositor::Builder::new().build_auto(()).run() 9 | } 10 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | default: unstable_static_build 2 | 3 | unstable_static_build: 4 | cargo build --features "unstable static" 5 | 6 | .PHONY: examples 7 | examples: 8 | cargo build --examples --features "unstable static" 9 | 10 | clippy: 11 | cargo clippy --features "unstable static" --examples 12 | 13 | build: 14 | cargo build 15 | 16 | -------------------------------------------------------------------------------- /src/backend/backend.rs: -------------------------------------------------------------------------------- 1 | //! A backend contains information about how clients connected and rendered. 2 | //! 3 | //! In nested environments such as Wayland and X11 the compositor is a client to 4 | //! the hosh process. 5 | //! 6 | //! In the headless backend clients aren't rendered and the only OS resources 7 | //! used are the Wayland file descriptor. This is useful for testing. 8 | //! 9 | //! On the DRM backend the compositor controls an entire TTY. This is the most 10 | //! invasive, but also the most useful backend. If there's an infinite loop here 11 | //! then it is very easy to get into a place where the only course of action is 12 | //! restarting the computer. 13 | //! 14 | //! On the multi backend multiple backends could be running at the same time. 15 | 16 | use crate::libc; 17 | use wlroots_sys::{ 18 | self, wlr_backend, wlr_backend_get_session, wlr_backend_is_drm, wlr_backend_is_headless, 19 | wlr_backend_is_libinput, wlr_backend_is_multi, wlr_backend_is_wl, wlr_backend_is_x11 20 | }; 21 | 22 | use crate::backend; 23 | 24 | /// A custom function to set up the renderer. 25 | pub type UnsafeRenderSetupFunction = unsafe extern "C" fn( 26 | egl: *mut wlroots_sys::wlr_egl, 27 | platform: u32, 28 | remote_display: *mut libc::c_void, 29 | config_attribs: *mut i32, 30 | visual_id: i32 31 | ) -> *mut wlroots_sys::wlr_renderer; 32 | 33 | #[derive(Debug, Hash, Eq, PartialEq)] 34 | pub enum Backend { 35 | Wayland(backend::Wayland), 36 | X11(backend::X11), 37 | DRM(backend::Drm), 38 | Headless(backend::Headless), 39 | LibInput(backend::Libinput), 40 | Multi(backend::Multi) 41 | } 42 | 43 | impl Backend { 44 | /// Obtains the wlr_session reference from this backend if there is any. 45 | /// 46 | /// Might return None for backends that don't use a session. 47 | pub fn get_session(&self) -> Option { 48 | unsafe { 49 | let session_ptr = wlr_backend_get_session(self.as_ptr()); 50 | if session_ptr.is_null() { 51 | None 52 | } else { 53 | Some(backend::Session::from_ptr(session_ptr)) 54 | } 55 | } 56 | } 57 | 58 | /// Create a backend from a `*mut wlr_backend`. 59 | pub unsafe fn from_backend(backend: *mut wlr_backend) -> Self { 60 | if wlr_backend_is_wl(backend) { 61 | Backend::Wayland(backend::Wayland { backend }) 62 | } else if wlr_backend_is_x11(backend) { 63 | Backend::X11(backend::X11 { backend }) 64 | } else if wlr_backend_is_drm(backend) { 65 | Backend::DRM(backend::Drm { backend }) 66 | } else if wlr_backend_is_headless(backend) { 67 | Backend::Headless(backend::Headless { backend }) 68 | } else if wlr_backend_is_multi(backend) { 69 | Backend::Multi(backend::Multi { backend }) 70 | } else if wlr_backend_is_libinput(backend) { 71 | Backend::LibInput(backend::Libinput { backend }) 72 | } else { 73 | panic!("Unknown backend {:p}", backend) 74 | } 75 | } 76 | 77 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_backend { 78 | match *self { 79 | Backend::Wayland(backend::Wayland { backend }) | 80 | Backend::X11(backend::X11 { backend }) | 81 | Backend::DRM(backend::Drm { backend }) | 82 | Backend::Headless(backend::Headless { backend }) | 83 | Backend::Multi(backend::Multi { backend }) | 84 | Backend::LibInput(backend::Libinput { backend }) => backend 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/backend/drm.rs: -------------------------------------------------------------------------------- 1 | use std::ptr; 2 | 3 | use crate::libc::c_int; 4 | use wlroots_sys::{wl_display, wlr_backend, wlr_drm_backend_create, wlr_output_is_drm}; 5 | 6 | use crate::{ 7 | backend::{Session, UnsafeRenderSetupFunction}, 8 | output::Output, 9 | utils::Handleable 10 | }; 11 | 12 | /// When the compositor is ran on a TTY and has full control of the system 13 | /// resources. 14 | /// 15 | /// This is primarily the backend that end users will use, as they usually want 16 | /// the compositor to run standalone. 17 | /// 18 | /// Note that because you have full control of the TTY (and the keyboard, the 19 | /// mouse, and just about everything else) that if there's an infinite loop then 20 | /// you could hard-lock yourself out of the system. At that point you must 21 | /// reboot your computer (or use SysRq). 22 | /// 23 | /// Note that if the process exits for any reason (a panic, an abort, or a clean 24 | /// exit) all of the resource handles will automatically be cleaned up properly 25 | /// by the OS. 26 | #[derive(Debug, Hash, Eq, PartialEq)] 27 | pub struct Drm { 28 | pub(crate) backend: *mut wlr_backend 29 | } 30 | 31 | impl Drm { 32 | /// Creates a DRM backend using the specified GPU file descriptor (typically 33 | /// from a device node in /dev/dri). 34 | /// 35 | /// To slave this to another DRM backend, pass it as the parent (which 36 | /// _must_ be a DRM backend, other kinds of backends raise SIGABRT). 37 | pub unsafe fn new( 38 | display: *mut wl_display, 39 | session: Session, 40 | gpu_fd: c_int, 41 | parent: Option, 42 | render_setup_func: Option 43 | ) -> Self { 44 | let parent_ptr = parent 45 | .map(|backend| backend.as_ptr()) 46 | .unwrap_or_else(ptr::null_mut); 47 | let backend = 48 | wlr_drm_backend_create(display, session.as_ptr(), gpu_fd, parent_ptr, render_setup_func); 49 | if backend.is_null() { 50 | panic!("Could not construct X11 backend"); 51 | } 52 | Drm { backend } 53 | } 54 | 55 | pub fn output_is_drm(&self, output: &Output) -> bool { 56 | unsafe { wlr_output_is_drm(output.as_ptr()) } 57 | } 58 | 59 | pub unsafe fn as_ptr(&self) -> *mut wlr_backend { 60 | self.backend 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/backend/headless.rs: -------------------------------------------------------------------------------- 1 | use std::ptr::NonNull; 2 | 3 | use crate::libc; 4 | use wlroots_sys::{ 5 | wl_display, wlr_backend, wlr_headless_add_input_device, wlr_headless_add_output, 6 | wlr_headless_backend_create, wlr_input_device_is_headless, wlr_input_device_type, wlr_output_is_headless 7 | }; 8 | 9 | use crate::{ 10 | backend::UnsafeRenderSetupFunction, 11 | input, 12 | output::{self, Output}, 13 | utils::Handleable 14 | }; 15 | 16 | /// In this backend the only resource the compositor uses is the Wayland file 17 | /// descriptor. It doesn't try to grab actual keyboard/pointers and it doesn't 18 | /// render anything. 19 | /// 20 | /// This backend is useful for testing as you can easily add "fake" inputs and 21 | /// outputs. 22 | #[derive(Debug, Hash, Eq, PartialEq)] 23 | pub struct Headless { 24 | pub(crate) backend: *mut wlr_backend 25 | } 26 | 27 | impl Headless { 28 | /// Creates a headless backend. 29 | /// 30 | /// A headless backend has no outputs or inputs by default. 31 | pub unsafe fn new( 32 | display: *mut wl_display, 33 | render_setup_func: Option 34 | ) -> Self { 35 | let backend = wlr_headless_backend_create(display, render_setup_func); 36 | if backend.is_null() { 37 | panic!("Could not construct Headless backend"); 38 | } 39 | Headless { backend } 40 | } 41 | 42 | /// Create a new headless output backed by an in-memory EGL framebuffer. 43 | /// 44 | /// You can read pixels from this framebuffer via `Renderer::read_pixels` 45 | /// but it is otherwise not displayed. 46 | pub fn add_output(&self, width: libc::c_uint, height: libc::c_uint) -> Option { 47 | unsafe { 48 | let output_ptr = wlr_headless_add_output(self.backend, width, height); 49 | if output_ptr.is_null() { 50 | None 51 | } else { 52 | Some(output::Handle::from_ptr(output_ptr)) 53 | } 54 | } 55 | } 56 | 57 | /// Creates a new input device. 58 | /// 59 | /// The caller is responsible for manually raising any event signals on the 60 | /// new input device if it wants to simulate input events. 61 | pub fn add_input_device(&self, input_type: wlr_input_device_type) -> Option { 62 | unsafe { 63 | let device = wlr_headless_add_input_device(self.backend, input_type); 64 | let device = NonNull::new(device)?; 65 | Some(input::Device { device }.device()) 66 | } 67 | } 68 | 69 | pub fn is_headless_input_device(&self, input_device: &input::Device) -> bool { 70 | unsafe { wlr_input_device_is_headless(input_device.as_ptr()) } 71 | } 72 | 73 | pub fn is_headless_output(&self, output: &Output) -> bool { 74 | unsafe { wlr_output_is_headless(output.as_ptr()) } 75 | } 76 | 77 | pub unsafe fn as_ptr(&self) -> *mut wlr_backend { 78 | self.backend 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/backend/libinput.rs: -------------------------------------------------------------------------------- 1 | use wlroots_sys::{ 2 | libinput_device, wl_display, wlr_backend, wlr_input_device_is_libinput, wlr_libinput_backend_create, 3 | wlr_libinput_get_device_handle 4 | }; 5 | 6 | use crate::{backend::Session, input}; 7 | 8 | #[derive(Debug, Hash, Eq, PartialEq)] 9 | pub struct Libinput { 10 | pub(crate) backend: *mut wlr_backend 11 | } 12 | 13 | impl Libinput { 14 | pub unsafe fn new(display: *mut wl_display, session: Session) -> Self { 15 | let backend = wlr_libinput_backend_create(display, session.as_ptr()); 16 | if backend.is_null() { 17 | panic!("Could not construct Wayland backend"); 18 | } 19 | Libinput { backend } 20 | } 21 | 22 | /// Get the underlying libinput_device handle for the given input device. 23 | pub unsafe fn device_handle(input_device: &input::Device) -> *mut libinput_device { 24 | wlr_libinput_get_device_handle(input_device.as_ptr()) 25 | } 26 | 27 | pub fn is_libinput_input_device(&self, input_device: &input::Device) -> bool { 28 | unsafe { wlr_input_device_is_libinput(input_device.as_ptr()) } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/backend/mod.rs: -------------------------------------------------------------------------------- 1 | #[allow(clippy::module_inception)] 2 | mod backend; 3 | mod drm; 4 | mod headless; 5 | mod libinput; 6 | mod multi; 7 | mod session; 8 | mod wayland; 9 | mod x11; 10 | 11 | pub use self::backend::*; 12 | pub use self::drm::*; 13 | pub use self::headless::*; 14 | pub use self::libinput::*; 15 | pub use self::multi::*; 16 | pub use self::session::*; 17 | pub use self::wayland::*; 18 | pub use self::x11::*; 19 | -------------------------------------------------------------------------------- /src/backend/multi.rs: -------------------------------------------------------------------------------- 1 | use wlroots_sys::{ 2 | wl_display, wlr_backend, wlr_backend_autocreate, wlr_multi_backend_add, wlr_multi_backend_remove, 3 | wlr_multi_is_empty 4 | }; 5 | 6 | use crate::backend::UnsafeRenderSetupFunction; 7 | 8 | /// When multiple backends are running or when the compositor writer doesn't 9 | /// care and just used the auto create option in the `CompositorBuilder`. 10 | #[derive(Debug, Hash, Eq, PartialEq)] 11 | pub struct Multi { 12 | pub(crate) backend: *mut wlr_backend 13 | } 14 | 15 | impl Multi { 16 | /// Auto create a backend based on the environment. 17 | pub unsafe fn auto_create( 18 | display: *mut wl_display, 19 | render_setup_func: Option 20 | ) -> Self { 21 | let backend = wlr_backend_autocreate(display, render_setup_func); 22 | if backend.is_null() { 23 | panic!("Could not auto construct backend"); 24 | } 25 | Multi { backend } 26 | } 27 | 28 | /// Adds the given backend to the multi backend. 29 | /// 30 | /// # Safety 31 | /// 32 | /// This should be done before the new backend is started. 33 | pub unsafe fn add_backend(&self, new_backend: *mut wlr_backend) -> bool { 34 | wlr_multi_backend_add(self.backend, new_backend) 35 | } 36 | 37 | /// Removes the backend. 38 | /// 39 | /// # Safety 40 | /// 41 | /// Doesn't check if that backend is valid. 42 | pub unsafe fn remove_backend(&self, backend: *mut wlr_backend) { 43 | wlr_multi_backend_remove(self.backend, backend) 44 | } 45 | 46 | pub fn is_empty(&self) -> bool { 47 | unsafe { wlr_multi_is_empty(self.backend) } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/backend/session.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | use std::path::Path; 3 | 4 | use crate::libc::{c_char, c_int, c_uint}; 5 | use wlroots_sys::{ 6 | dev_t, udev, udev_monitor, wl_display, wl_listener, wl_signal, wlr_device, wlr_session, 7 | wlr_session_change_vt, wlr_session_close_file, wlr_session_create, wlr_session_destroy, 8 | wlr_session_open_file, wlr_session_signal_add 9 | }; 10 | 11 | use crate::utils::safe_as_cstring; 12 | 13 | pub struct Device<'session> { 14 | device: *mut wlr_device, 15 | phantom: PhantomData<&'session ()> 16 | } 17 | 18 | pub struct Session<'session> { 19 | session: *mut wlr_session, 20 | phantom: PhantomData<&'session ()> 21 | } 22 | 23 | impl<'session> Device<'session> { 24 | unsafe fn from_ptr<'unbound>(device: *mut wlr_device) -> Device<'unbound> { 25 | Device { 26 | device, 27 | phantom: PhantomData 28 | } 29 | } 30 | 31 | pub fn fd(&self) -> c_int { 32 | unsafe { (*self.device).fd } 33 | } 34 | 35 | pub fn dev(&self) -> dev_t { 36 | unsafe { (*self.device).dev } 37 | } 38 | } 39 | 40 | impl<'session> Session<'session> { 41 | /// Signal for when the session becomes active/inactive. 42 | /// It's called when we swap virtual terminal. 43 | pub fn session_signal(&self) -> wl_signal { 44 | unsafe { (*self.session).session_signal } 45 | } 46 | 47 | pub fn active(&self) -> bool { 48 | unsafe { (*self.session).active } 49 | } 50 | 51 | pub fn vtnr(&self) -> c_uint { 52 | unsafe { (*self.session).vtnr } 53 | } 54 | 55 | pub fn seat(&self) -> [c_char; 256] { 56 | unsafe { (*self.session).seat } 57 | } 58 | 59 | pub fn udev(&self) -> *mut udev { 60 | unsafe { (*self.session).udev } 61 | } 62 | 63 | pub fn udev_monitor(&self) -> *mut udev_monitor { 64 | unsafe { (*self.session).mon } 65 | } 66 | 67 | pub fn devices(&self) -> Vec> { 68 | unsafe { 69 | let mut devices = Vec::new(); 70 | wl_list_for_each!((*self.session).devices, 71 | link, 72 | (device: wlr_device) => { 73 | devices.push(Device::from_ptr(device)) 74 | }); 75 | devices 76 | } 77 | } 78 | 79 | /// Changes the virtual terminal. 80 | pub fn change_vt(&mut self, vt: c_uint) -> bool { 81 | unsafe { wlr_session_change_vt(self.session, vt) } 82 | } 83 | 84 | /// Opens a session, taking control of the current virtual terminal. 85 | /// This should not be called if another program is already in control 86 | /// of the terminal (Xorg, another Wayland compositor, etc.). 87 | /// 88 | /// If logind support is not enabled, you must have CAP_SYS_ADMIN or be 89 | /// root. It is safe to drop privileges after this is called. 90 | /// 91 | /// Returns `None` on error. 92 | pub unsafe fn new(display: *mut wl_display) -> Option { 93 | let session = wlr_session_create(display); 94 | if session.is_null() { 95 | None 96 | } else { 97 | Some(Session { 98 | session, 99 | phantom: PhantomData 100 | }) 101 | } 102 | } 103 | 104 | /// Closes a previously opened session and restores the virtual terminal. 105 | /// You should call Session::close_file on each files you opened 106 | /// with Session::open_file before you call this. 107 | pub unsafe fn destroy(self) { 108 | wlr_session_destroy(self.session) 109 | } 110 | 111 | /// Opens the file at path. 112 | /// This can only be used to open DRM or evdev (input) devices. 113 | /// 114 | /// When the session becomes inactive: 115 | /// - DRM files lose their DRM master status 116 | /// - evdev files become invalid and should be closed 117 | /// 118 | /// Returns -errno on error. 119 | pub unsafe fn open_file>(&mut self, path: P) -> c_int { 120 | let path_c = safe_as_cstring(path.as_ref().to_str().expect("Path was not UTF-8")); 121 | wlr_session_open_file(self.session, path_c.as_ptr()) 122 | } 123 | 124 | pub unsafe fn close_file>(&mut self, fd: c_int) { 125 | wlr_session_close_file(self.session, fd); 126 | } 127 | 128 | pub unsafe fn signal_add(&mut self, fd: c_int, listener: *mut wl_listener) { 129 | wlr_session_signal_add(self.session, fd, listener) 130 | } 131 | 132 | pub unsafe fn as_ptr(&self) -> *mut wlr_session { 133 | self.session 134 | } 135 | 136 | pub unsafe fn from_ptr(session: *mut wlr_session) -> Self { 137 | Session { 138 | session, 139 | phantom: PhantomData 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/backend/wayland.rs: -------------------------------------------------------------------------------- 1 | use std::ptr; 2 | 3 | use wlroots_sys::{ 4 | wl_display, wlr_backend, wlr_input_device_is_wl, wlr_output_is_wl, wlr_wl_backend_create, 5 | wlr_wl_output_create 6 | }; 7 | 8 | use crate::{ 9 | backend::UnsafeRenderSetupFunction, 10 | input, 11 | output::{self, Output}, 12 | utils::{safe_as_cstring, Handleable} 13 | }; 14 | 15 | /// When the compositor is running in a nested Wayland environment. 16 | /// e.g. your compositor is executed while the user is running Gnome+Mutter or 17 | /// Weston. 18 | /// 19 | /// This is useful for testing and iterating on the design of the compositor. 20 | #[derive(Debug, Hash, Eq, PartialEq)] 21 | pub struct Wayland { 22 | pub(crate) backend: *mut wlr_backend 23 | } 24 | 25 | impl Wayland { 26 | /// Creates a new wlr_wl_backend. This backend will be created with no 27 | /// outputs; you must use wlr_wl_output_create to add them. 28 | /// 29 | /// The `remote` argument is the name of the host compositor wayland socket. 30 | /// Set to `None` for the default behaviour (WAYLAND_DISPLAY env 31 | /// variable or wayland-0 default) 32 | pub unsafe fn new( 33 | display: *mut wl_display, 34 | remote: Option, 35 | render_setup_func: Option 36 | ) -> Self { 37 | let remote_cstr = remote.map(safe_as_cstring); 38 | let remote_ptr = remote_cstr 39 | .as_ref() 40 | .map(|s| s.as_ptr()) 41 | .unwrap_or_else(|| ptr::null_mut()); 42 | let backend = wlr_wl_backend_create(display, remote_ptr, render_setup_func); 43 | if backend.is_null() { 44 | panic!("Could not construct Wayland backend"); 45 | } 46 | Wayland { backend } 47 | } 48 | 49 | /// Adds a new output to this backend. 50 | /// 51 | /// You may remove outputs by destroying them. 52 | /// 53 | /// Note that if called before initializing the backend, this will return 54 | /// None and your outputs will be created during initialization (and 55 | /// given to you via the output_add signal). 56 | pub fn create_output(&self) -> Option { 57 | unsafe { 58 | let output_ptr = wlr_wl_output_create(self.backend); 59 | if output_ptr.is_null() { 60 | None 61 | } else { 62 | Some(output::Handle::from_ptr(output_ptr)) 63 | } 64 | } 65 | } 66 | 67 | /// True if the given input device is a wlr_wl_input_device. 68 | pub fn is_wl_input_device(&self, input_device: &input::Device) -> bool { 69 | unsafe { wlr_input_device_is_wl(input_device.as_ptr()) } 70 | } 71 | 72 | /// True if the given output is a wlr_wl_output. 73 | pub fn is_wl_output_device(&self, output: &Output) -> bool { 74 | unsafe { wlr_output_is_wl(output.as_ptr()) } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/backend/x11.rs: -------------------------------------------------------------------------------- 1 | use std::ptr; 2 | 3 | use wlroots_sys::{ 4 | wl_display, wlr_backend, wlr_input_device_is_x11, wlr_output_is_x11, wlr_x11_backend_create, 5 | wlr_x11_output_create 6 | }; 7 | 8 | use crate::{ 9 | backend::UnsafeRenderSetupFunction, 10 | input, 11 | output::{self, Output}, 12 | utils::{safe_as_cstring, Handleable} 13 | }; 14 | 15 | /// When the compositor is running in a nested X11 environment. 16 | /// e.g. your compositor is executed while the user is running an X11 window 17 | /// manager. 18 | /// 19 | /// This is useful for testing and iteration on the design of the compositor. 20 | #[derive(Debug, Hash, Eq, PartialEq)] 21 | pub struct X11 { 22 | pub(crate) backend: *mut wlr_backend 23 | } 24 | 25 | impl X11 { 26 | pub unsafe fn new( 27 | display: *mut wl_display, 28 | x11_display: Option, 29 | render_setup_func: Option 30 | ) -> Self { 31 | let x11_display_cstr = x11_display.map(safe_as_cstring); 32 | let x11_display_ptr = x11_display_cstr 33 | .as_ref() 34 | .map(|s| s.as_ptr()) 35 | .unwrap_or_else(|| ptr::null_mut()); 36 | let backend = wlr_x11_backend_create(display, x11_display_ptr, render_setup_func); 37 | if backend.is_null() { 38 | panic!("Could not construct X11 backend"); 39 | } 40 | X11 { backend } 41 | } 42 | 43 | pub fn create_output(&self) -> Option { 44 | unsafe { 45 | let output_ptr = wlr_x11_output_create(self.backend); 46 | if output_ptr.is_null() { 47 | None 48 | } else { 49 | Some(output::Handle::from_ptr(output_ptr)) 50 | } 51 | } 52 | } 53 | 54 | pub fn is_x11_input_device(&self, input_device: &input::Device) -> bool { 55 | unsafe { wlr_input_device_is_x11(input_device.as_ptr()) } 56 | } 57 | 58 | pub fn is_x11_output_device(&self, output: &Output) -> bool { 59 | unsafe { wlr_output_is_x11(output.as_ptr()) } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/events/key_events.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use wlroots_sys::{wlr_event_keyboard_key, wlr_key_state, xkb_keysym_t, xkb_state, xkb_state_key_get_syms}; 4 | 5 | use crate::input::keyboard; 6 | 7 | #[derive(Debug)] 8 | pub struct Key { 9 | key: *mut wlr_event_keyboard_key, 10 | xkb_state: *mut xkb_state 11 | } 12 | 13 | impl Key { 14 | /// Constructs a Key from the raw key event pointer information. 15 | pub(crate) unsafe fn new(key: *mut wlr_event_keyboard_key, xkb_state: *mut xkb_state) -> Self { 16 | Key { key, xkb_state } 17 | } 18 | 19 | /// Gets the raw keycode from the device. 20 | /// 21 | /// Usually you want to use `Key::input_keys` since you care about what 22 | /// value XKB says this is. 23 | pub fn keycode(&self) -> u32 { 24 | unsafe { (*self.key).keycode } 25 | } 26 | 27 | /// Get how long the key has been pressed down, in milliseconds. 28 | pub fn time_msec(&self) -> Duration { 29 | Duration::from_millis(u64::from(unsafe { (*self.key).time_msec })) 30 | } 31 | 32 | /// TODO What is this? 33 | pub fn update_state(&self) -> bool { 34 | unsafe { (*self.key).update_state } 35 | } 36 | 37 | /// Get the pressed/released state of the key. 38 | pub fn key_state(&self) -> wlr_key_state { 39 | unsafe { (*self.key).state } 40 | } 41 | 42 | /// Gets the keys that are pressed using XKB to convert them to a more 43 | /// programmer friendly form. 44 | pub fn pressed_keys(&self) -> Vec { 45 | unsafe { 46 | let mut syms = 0 as *const xkb_keysym_t; 47 | let key_length = xkb_state_key_get_syms(self.xkb_state, self.keycode() + 8, &mut syms); 48 | (0..key_length) 49 | .map(|index| *syms.offset(index as isize)) 50 | .collect() 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/events/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod key_events; 2 | pub mod pointer_events; 3 | pub mod seat_events; 4 | pub mod switch_events; 5 | pub mod tablet_pad_events; 6 | pub mod tablet_tool_events; 7 | pub mod touch_events; 8 | pub mod xdg_shell_events; 9 | pub mod xdg_shell_v6_events; 10 | pub mod xwayland_events; 11 | 12 | pub use self::key_events::Key; 13 | -------------------------------------------------------------------------------- /src/events/seat_events.rs: -------------------------------------------------------------------------------- 1 | use wlroots_sys::wlr_seat_pointer_request_set_cursor_event; 2 | 3 | use crate::{seat, surface}; 4 | 5 | #[derive(Debug)] 6 | pub struct SetCursor { 7 | event: *mut wlr_seat_pointer_request_set_cursor_event 8 | } 9 | 10 | impl SetCursor { 11 | pub(crate) unsafe fn from_ptr(event: *mut wlr_seat_pointer_request_set_cursor_event) -> Self { 12 | SetCursor { event } 13 | } 14 | /// Get the seat client associated with the seat where this 15 | /// event is occurring. 16 | pub fn seat_client(&self) -> seat::Client { 17 | unsafe { seat::Client::from_ptr((*self.event).seat_client) } 18 | } 19 | 20 | /// Get the surface that is providing the cursor to the seat. 21 | pub fn surface(&self) -> Option { 22 | unsafe { 23 | let surface = (*self.event).surface; 24 | if surface.is_null() { 25 | None 26 | } else { 27 | Some(surface::Handle::from_ptr(surface)) 28 | } 29 | } 30 | } 31 | 32 | pub fn serial(&self) -> u32 { 33 | unsafe { (*self.event).serial } 34 | } 35 | 36 | pub fn location(&self) -> (i32, i32) { 37 | unsafe { ((*self.event).hotspot_x, (*self.event).hotspot_y) } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/events/switch_events.rs: -------------------------------------------------------------------------------- 1 | use wlroots_sys::{wlr_event_switch_toggle, wlr_switch_state, wlr_switch_type}; 2 | 3 | use crate::input; 4 | 5 | pub struct Toggle { 6 | event: *mut wlr_event_switch_toggle, 7 | device: input::Device 8 | } 9 | 10 | impl Toggle { 11 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_switch_toggle) -> Self { 12 | Toggle { 13 | event, 14 | device: input::Device::from_ptr((*event).device) 15 | } 16 | } 17 | 18 | pub fn device(&self) -> &input::Device { 19 | &self.device 20 | } 21 | 22 | /// Get the timestamp of this event. 23 | pub fn time_msec(&self) -> u32 { 24 | unsafe { (*self.event).time_msec } 25 | } 26 | 27 | /// Get the type of switch this is. 28 | pub fn switch_type(&self) -> wlr_switch_type { 29 | unsafe { (*self.event).switch_type } 30 | } 31 | 32 | /// Get the state the switch is in. 33 | pub fn switch_state(&self) -> wlr_switch_state { 34 | unsafe { (*self.event).switch_state } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/events/tablet_pad_events.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use crate::libc::{c_double, c_uint}; 4 | 5 | use wlroots_sys::{wlr_event_tablet_pad_button, wlr_event_tablet_pad_ring, wlr_event_tablet_pad_strip}; 6 | 7 | pub use wlroots_sys::{wlr_button_state, wlr_tablet_pad_ring_source, wlr_tablet_pad_strip_source}; 8 | 9 | #[derive(Debug)] 10 | /// Event that is triggered when a tablet pad button event occurs. 11 | pub struct Button { 12 | event: *mut wlr_event_tablet_pad_button 13 | } 14 | 15 | #[derive(Debug)] 16 | /// Event that is triggered when a ring event occurs. 17 | pub struct Ring { 18 | event: *mut wlr_event_tablet_pad_ring 19 | } 20 | 21 | #[derive(Debug)] 22 | /// Event that is triggered wen a strip event occurs 23 | pub struct Strip { 24 | event: *mut wlr_event_tablet_pad_strip 25 | } 26 | 27 | impl Button { 28 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_tablet_pad_button) -> Self { 29 | Button { event } 30 | } 31 | 32 | pub fn time_msec(&self) -> u32 { 33 | unsafe { (*self.event).time_msec } 34 | } 35 | 36 | pub fn button(&self) -> u32 { 37 | unsafe { (*self.event).button } 38 | } 39 | 40 | pub fn state(&self) -> wlr_button_state { 41 | unsafe { (*self.event).state } 42 | } 43 | 44 | pub fn mode(&self) -> c_uint { 45 | unsafe { (*self.event).mode } 46 | } 47 | } 48 | 49 | impl Ring { 50 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_tablet_pad_ring) -> Self { 51 | Ring { event } 52 | } 53 | 54 | pub fn time_msec(&self) -> u32 { 55 | unsafe { (*self.event).time_msec } 56 | } 57 | 58 | pub fn source(&self) -> wlr_tablet_pad_ring_source { 59 | unsafe { (*self.event).source } 60 | } 61 | 62 | pub fn ring(&self) -> u32 { 63 | unsafe { (*self.event).ring } 64 | } 65 | 66 | pub fn position(&self) -> c_double { 67 | unsafe { (*self.event).position } 68 | } 69 | 70 | pub fn mode(&self) -> c_uint { 71 | unsafe { (*self.event).mode } 72 | } 73 | } 74 | 75 | impl Strip { 76 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_tablet_pad_strip) -> Self { 77 | Strip { event } 78 | } 79 | 80 | pub fn time_msec(&self) -> u32 { 81 | unsafe { (*self.event).time_msec } 82 | } 83 | 84 | pub fn source(&self) -> wlr_tablet_pad_strip_source { 85 | unsafe { (*self.event).source } 86 | } 87 | 88 | pub fn strip(&self) -> u32 { 89 | unsafe { (*self.event).strip } 90 | } 91 | 92 | pub fn position(&self) -> c_double { 93 | unsafe { (*self.event).position } 94 | } 95 | 96 | pub fn mode(&self) -> c_uint { 97 | unsafe { (*self.event).mode } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/events/tablet_tool_events.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use crate::input::tablet_tool; 4 | use wlroots_sys::{ 5 | wlr_button_state, wlr_event_tablet_tool_axis, wlr_event_tablet_tool_button, 6 | wlr_event_tablet_tool_proximity, wlr_event_tablet_tool_tip, wlr_tablet_tool_proximity_state, 7 | wlr_tablet_tool_tip_state 8 | }; 9 | 10 | #[derive(Debug)] 11 | /// Event that is triggered when a tablet tool axis event occurs. 12 | pub struct Axis { 13 | event: *mut wlr_event_tablet_tool_axis 14 | } 15 | 16 | #[derive(Debug)] 17 | /// Event that is triggered when a tablet tool proximity event occurs. 18 | pub struct Proximity { 19 | event: *mut wlr_event_tablet_tool_proximity 20 | } 21 | 22 | /// Event that is triggered when a tablet tool tip event occurs. 23 | pub struct Tip { 24 | event: *mut wlr_event_tablet_tool_tip 25 | } 26 | 27 | /// Event that is triggered when a tablet tool button event occurs. 28 | pub struct Button { 29 | event: *mut wlr_event_tablet_tool_button 30 | } 31 | 32 | impl Axis { 33 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_tablet_tool_axis) -> Self { 34 | Axis { event } 35 | } 36 | 37 | pub fn time_msec(&self) -> u32 { 38 | unsafe { (*self.event).time_msec } 39 | } 40 | 41 | pub fn updated_axes(&self) -> tablet_tool::Axis { 42 | unsafe { tablet_tool::Axis::from_bits_truncate((*self.event).updated_axes) } 43 | } 44 | 45 | /// Gets the position of the event. 46 | /// 47 | /// Return value is in (x, y) format. 48 | pub fn position(&self) -> (f64, f64) { 49 | unsafe { ((*self.event).x, (*self.event).y) } 50 | } 51 | 52 | pub fn pressure(&self) -> f64 { 53 | unsafe { (*self.event).pressure } 54 | } 55 | 56 | pub fn distance(&self) -> f64 { 57 | unsafe { (*self.event).distance } 58 | } 59 | 60 | /// Gets the tilt of the event. 61 | /// 62 | /// Return value is in (x, y) format. 63 | pub fn tilt(&self) -> (f64, f64) { 64 | unsafe { ((*self.event).tilt_x, (*self.event).tilt_y) } 65 | } 66 | 67 | pub fn slider(&self) -> f64 { 68 | unsafe { (*self.event).slider } 69 | } 70 | 71 | pub fn wheel_delta(&self) -> f64 { 72 | unsafe { (*self.event).wheel_delta } 73 | } 74 | } 75 | 76 | impl Proximity { 77 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_tablet_tool_proximity) -> Self { 78 | Proximity { event } 79 | } 80 | 81 | pub fn time_msec(&self) -> u32 { 82 | unsafe { (*self.event).time_msec } 83 | } 84 | 85 | /// Gets the position of the event in mm. 86 | /// 87 | /// Return value is in (x, y) format. 88 | pub fn position(&self) -> (f64, f64) { 89 | unsafe { ((*self.event).x, (*self.event).y) } 90 | } 91 | 92 | pub fn state(&self) -> wlr_tablet_tool_proximity_state { 93 | unsafe { (*self.event).state } 94 | } 95 | } 96 | 97 | impl Tip { 98 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_tablet_tool_tip) -> Self { 99 | Tip { event } 100 | } 101 | 102 | pub fn time_msec(&self) -> u32 { 103 | unsafe { (*self.event).time_msec } 104 | } 105 | 106 | /// Gets the position of the event in mm. 107 | /// 108 | /// Return value is in (x, y) format. 109 | pub fn position(&self) -> (f64, f64) { 110 | unsafe { ((*self.event).x, (*self.event).y) } 111 | } 112 | 113 | pub fn state(&self) -> wlr_tablet_tool_tip_state { 114 | unsafe { (*self.event).state } 115 | } 116 | } 117 | 118 | impl Button { 119 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_tablet_tool_button) -> Self { 120 | Button { event } 121 | } 122 | 123 | pub fn time_msec(&self) -> u32 { 124 | unsafe { (*self.event).time_msec } 125 | } 126 | 127 | pub fn button(&self) -> u32 { 128 | unsafe { (*self.event).button } 129 | } 130 | 131 | pub fn state(&self) -> wlr_button_state { 132 | unsafe { (*self.event).state } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/events/touch_events.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use wlroots_sys::{wlr_event_touch_cancel, wlr_event_touch_down, wlr_event_touch_motion, wlr_event_touch_up}; 4 | 5 | #[derive(Debug)] 6 | /// Event that is triggered when a touch down event occurs. 7 | pub struct Down { 8 | event: *mut wlr_event_touch_down 9 | } 10 | 11 | #[derive(Debug)] 12 | /// Event that is triggered when a touch up event occurs. 13 | pub struct Up { 14 | event: *mut wlr_event_touch_up 15 | } 16 | 17 | #[derive(Debug)] 18 | /// Event that is triggered when a touch motion event occurs. 19 | pub struct Motion { 20 | event: *mut wlr_event_touch_motion 21 | } 22 | 23 | #[derive(Debug)] 24 | /// Event that is triggered when a touch cancel event occurs. 25 | pub struct Cancel { 26 | event: *mut wlr_event_touch_cancel 27 | } 28 | 29 | impl Down { 30 | /// Constructs a `Down` from a raw event pointer. 31 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_touch_down) -> Self { 32 | Down { event } 33 | } 34 | 35 | /// Gets how long the touch event has been going on for. 36 | pub fn time_msec(&self) -> u32 { 37 | unsafe { (*self.event).time_msec } 38 | } 39 | 40 | /// Gets the touch id associated with this event. 41 | pub fn touch_id(&self) -> i32 { 42 | unsafe { (*self.event).touch_id } 43 | } 44 | 45 | /// Gets the location of the touch event in mm. 46 | /// 47 | /// Return value is in (x, y) format. 48 | pub fn location(&self) -> (f64, f64) { 49 | unsafe { ((*self.event).x, (*self.event).y) } 50 | } 51 | } 52 | 53 | impl Up { 54 | /// Constructs a `Up` from a raw event pointer. 55 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_touch_up) -> Self { 56 | Up { event } 57 | } 58 | 59 | pub fn time_msec(&self) -> u32 { 60 | unsafe { (*self.event).time_msec } 61 | } 62 | 63 | /// Gets the touch id associated with this event. 64 | pub fn touch_id(&self) -> i32 { 65 | unsafe { (*self.event).touch_id } 66 | } 67 | } 68 | 69 | impl Motion { 70 | /// Constructs a `Motion` from a raw event pointer. 71 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_touch_motion) -> Self { 72 | Motion { event } 73 | } 74 | 75 | /// Gets how long the touch event has been going on for. 76 | pub fn time_msec(&self) -> u32 { 77 | unsafe { (*self.event).time_msec } 78 | } 79 | 80 | /// Gets the touch id associated with this event. 81 | pub fn touch_id(&self) -> i32 { 82 | unsafe { (*self.event).touch_id } 83 | } 84 | 85 | /// Gets the location of the touch event in mm. 86 | /// 87 | /// Return value is in (x, y) format. 88 | pub fn location(&self) -> (f64, f64) { 89 | unsafe { ((*self.event).x, (*self.event).y) } 90 | } 91 | } 92 | 93 | impl Cancel { 94 | /// Constructs a `Cancel` from a raw event pointe 95 | pub(crate) unsafe fn from_ptr(event: *mut wlr_event_touch_cancel) -> Self { 96 | Cancel { event } 97 | } 98 | 99 | pub fn time_msec(&self) -> u32 { 100 | unsafe { (*self.event).time_msec } 101 | } 102 | 103 | /// Gets the touch id associated with this event. 104 | pub fn touch_id(&self) -> i32 { 105 | unsafe { (*self.event).touch_id } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/events/xdg_shell_events.rs: -------------------------------------------------------------------------------- 1 | //! Events for stable XDG shell 2 | 3 | use wlroots_sys::{ 4 | wlr_xdg_toplevel_move_event, wlr_xdg_toplevel_resize_event, wlr_xdg_toplevel_set_fullscreen_event, 5 | wlr_xdg_toplevel_show_window_menu_event 6 | }; 7 | 8 | use crate::{output, shell::xdg_shell, utils::edges::Edges}; 9 | 10 | /// Event that triggers when the surface has been moved in coordinate space. 11 | #[derive(Debug, PartialEq, Eq)] 12 | pub struct Move { 13 | event: *mut wlr_xdg_toplevel_move_event 14 | } 15 | 16 | /// Event that triggers when the suface has been resized. 17 | #[derive(Debug, PartialEq, Eq)] 18 | pub struct Resize { 19 | event: *mut wlr_xdg_toplevel_resize_event 20 | } 21 | 22 | /// Event that is triggered when the surface toggles between being fullscreen 23 | /// or not. 24 | #[derive(Debug, PartialEq, Eq)] 25 | pub struct SetFullscreen { 26 | event: *mut wlr_xdg_toplevel_set_fullscreen_event 27 | } 28 | 29 | /// Event that is triggered when the surface shows the window menu. 30 | #[derive(Debug, PartialEq, Eq)] 31 | pub struct ShowWindowMenu { 32 | event: *mut wlr_xdg_toplevel_show_window_menu_event 33 | } 34 | 35 | impl Move { 36 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_move_event) -> Self { 37 | Move { event } 38 | } 39 | 40 | /// Get a handle to the surface associated with this event. 41 | pub fn surface(&self) -> xdg_shell::Handle { 42 | unsafe { xdg_shell::Handle::from_ptr((*self.event).surface) } 43 | } 44 | 45 | // TODO Get seat client 46 | 47 | pub fn serial(&self) -> u32 { 48 | unsafe { (*self.event).serial } 49 | } 50 | } 51 | 52 | impl Resize { 53 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_resize_event) -> Self { 54 | Resize { event } 55 | } 56 | 57 | /// Get a handle to the surface associated with this event. 58 | pub fn surface(&self) -> xdg_shell::Handle { 59 | unsafe { xdg_shell::Handle::from_ptr((*self.event).surface) } 60 | } 61 | 62 | // TODO Get seat client 63 | 64 | pub fn serial(&self) -> u32 { 65 | unsafe { (*self.event).serial } 66 | } 67 | 68 | pub fn edges(&self) -> Edges { 69 | unsafe { 70 | let edges_bits = (*self.event).edges; 71 | match Edges::from_bits(edges_bits) { 72 | Some(edges) => edges, 73 | None => panic!("got invalid edges: {}", edges_bits) 74 | } 75 | } 76 | } 77 | } 78 | 79 | impl SetFullscreen { 80 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_set_fullscreen_event) -> Self { 81 | SetFullscreen { event } 82 | } 83 | 84 | /// Get a handle to the surface associated with this event. 85 | pub fn surface(&self) -> xdg_shell::Handle { 86 | unsafe { xdg_shell::Handle::from_ptr((*self.event).surface) } 87 | } 88 | 89 | /// Determine if the event is to trigger fullscreen or to stop being 90 | /// fullscreen. 91 | pub fn fullscreen(&self) -> bool { 92 | unsafe { (*self.event).fullscreen } 93 | } 94 | 95 | /// Get a handle to the output that this fullscreen event refers to. 96 | pub fn output(&self) -> output::Handle { 97 | unsafe { output::Handle::from_ptr((*self.event).output) } 98 | } 99 | } 100 | 101 | impl ShowWindowMenu { 102 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_show_window_menu_event) -> Self { 103 | ShowWindowMenu { event } 104 | } 105 | 106 | /// Get a handle to the surface associated with this event. 107 | pub fn surface(&self) -> xdg_shell::Handle { 108 | unsafe { xdg_shell::Handle::from_ptr((*self.event).surface) } 109 | } 110 | 111 | // TODO seat client 112 | 113 | pub fn serial(&self) -> u32 { 114 | unsafe { (*self.event).serial } 115 | } 116 | 117 | /// Get the coordinates for where this show menu event takes place. 118 | /// 119 | /// Return value is in (x, y) format. 120 | pub fn coords(&self) -> (u32, u32) { 121 | unsafe { ((*self.event).x, (*self.event).y) } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/events/xdg_shell_v6_events.rs: -------------------------------------------------------------------------------- 1 | //! Events for XDG shell v6 2 | 3 | use wlroots_sys::{ 4 | wlr_xdg_toplevel_v6_move_event, wlr_xdg_toplevel_v6_resize_event, 5 | wlr_xdg_toplevel_v6_set_fullscreen_event, wlr_xdg_toplevel_v6_show_window_menu_event 6 | }; 7 | 8 | use crate::{output, shell::xdg_shell_v6, utils::edges::Edges}; 9 | 10 | /// Event that triggers when the surface has been moved in coordinate space. 11 | #[derive(Debug, PartialEq, Eq)] 12 | pub struct Move { 13 | event: *mut wlr_xdg_toplevel_v6_move_event 14 | } 15 | 16 | /// Event that triggers when the suface has been resized. 17 | #[derive(Debug, PartialEq, Eq)] 18 | pub struct Resize { 19 | event: *mut wlr_xdg_toplevel_v6_resize_event 20 | } 21 | 22 | /// Event that is triggered when the surface toggles between being fullscreen 23 | /// or not. 24 | #[derive(Debug, PartialEq, Eq)] 25 | pub struct SetFullscreen { 26 | event: *mut wlr_xdg_toplevel_v6_set_fullscreen_event 27 | } 28 | 29 | /// Event that is triggered when the surface shows the window menu. 30 | #[derive(Debug, PartialEq, Eq)] 31 | pub struct ShowWindowMenu { 32 | event: *mut wlr_xdg_toplevel_v6_show_window_menu_event 33 | } 34 | 35 | impl Move { 36 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_v6_move_event) -> Self { 37 | Move { event } 38 | } 39 | 40 | /// Get a handle to the surface associated with this event. 41 | pub fn surface(&self) -> xdg_shell_v6::Handle { 42 | unsafe { xdg_shell_v6::Handle::from_ptr((*self.event).surface) } 43 | } 44 | 45 | // TODO Get seat client 46 | 47 | pub fn serial(&self) -> u32 { 48 | unsafe { (*self.event).serial } 49 | } 50 | } 51 | 52 | impl Resize { 53 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_v6_resize_event) -> Self { 54 | Resize { event } 55 | } 56 | 57 | /// Get a handle to the surface associated with this event. 58 | pub fn surface(&self) -> xdg_shell_v6::Handle { 59 | unsafe { xdg_shell_v6::Handle::from_ptr((*self.event).surface) } 60 | } 61 | 62 | // TODO Get seat client 63 | 64 | pub fn serial(&self) -> u32 { 65 | unsafe { (*self.event).serial } 66 | } 67 | 68 | pub fn edges(&self) -> Edges { 69 | unsafe { 70 | let edges_bits = (*self.event).edges; 71 | match Edges::from_bits(edges_bits) { 72 | Some(edges) => edges, 73 | None => panic!("got invalid edges: {}", edges_bits) 74 | } 75 | } 76 | } 77 | } 78 | 79 | impl SetFullscreen { 80 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_v6_set_fullscreen_event) -> Self { 81 | SetFullscreen { event } 82 | } 83 | 84 | /// Get a handle to the surface associated with this event. 85 | pub fn surface(&self) -> xdg_shell_v6::Handle { 86 | unsafe { xdg_shell_v6::Handle::from_ptr((*self.event).surface) } 87 | } 88 | 89 | /// Determine if the event is to trigger fullscreen or to stop being 90 | /// fullscreen. 91 | pub fn fullscreen(&self) -> bool { 92 | unsafe { (*self.event).fullscreen } 93 | } 94 | 95 | /// Get a handle to the output that this fullscreen event refers to. 96 | pub fn output(&self) -> output::Handle { 97 | unsafe { output::Handle::from_ptr((*self.event).output) } 98 | } 99 | } 100 | 101 | impl ShowWindowMenu { 102 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xdg_toplevel_v6_show_window_menu_event) -> Self { 103 | ShowWindowMenu { event } 104 | } 105 | 106 | /// Get a handle to the surface associated with this event. 107 | pub fn surface(&self) -> xdg_shell_v6::Handle { 108 | unsafe { xdg_shell_v6::Handle::from_ptr((*self.event).surface) } 109 | } 110 | 111 | // TODO seat client 112 | 113 | pub fn serial(&self) -> u32 { 114 | unsafe { (*self.event).serial } 115 | } 116 | 117 | /// Get the coordinates for where this show menu event takes place. 118 | /// 119 | /// Return value is in (x, y) format. 120 | pub fn coords(&self) -> (u32, u32) { 121 | unsafe { ((*self.event).x, (*self.event).y) } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/events/xwayland_events.rs: -------------------------------------------------------------------------------- 1 | use crate::libc::{int16_t, uint16_t}; 2 | use wlroots_sys::{wlr_xwayland_move_event, wlr_xwayland_resize_event, wlr_xwayland_surface_configure_event}; 3 | 4 | use crate::{utils::edges::Edges, xwayland}; 5 | 6 | /// Event for when XWayland surface needs to be configured. 7 | pub struct Configure { 8 | event: *mut wlr_xwayland_surface_configure_event 9 | } 10 | 11 | /// Event for when an XWayland surface is moved. 12 | pub struct Move { 13 | event: *mut wlr_xwayland_move_event 14 | } 15 | 16 | /// Event for when an XWayland surface is resized. 17 | pub struct Resize { 18 | event: *mut wlr_xwayland_resize_event 19 | } 20 | 21 | impl Configure { 22 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xwayland_surface_configure_event) -> Self { 23 | Configure { event } 24 | } 25 | 26 | /// Get the surface associated with this configure event. 27 | pub fn surface(&self) -> Option { 28 | unsafe { 29 | if (*self.event).surface.is_null() { 30 | None 31 | } else { 32 | Some(xwayland::surface::Handle::from_ptr((*self.event).surface)) 33 | } 34 | } 35 | } 36 | 37 | /// Get the coordinates for where the XWayland surface wants to be. 38 | /// 39 | /// Return format is (x, y). 40 | pub fn coords(&self) -> (int16_t, int16_t) { 41 | unsafe { ((*self.event).x, (*self.event).y) } 42 | } 43 | 44 | /// Get the dimensions the XWayland surface wants to have. 45 | /// 46 | /// Return format is (width, height). 47 | pub fn dimensions(&self) -> (uint16_t, uint16_t) { 48 | unsafe { ((*self.event).width, (*self.event).height) } 49 | } 50 | } 51 | 52 | impl Move { 53 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xwayland_move_event) -> Self { 54 | Move { event } 55 | } 56 | 57 | /// Get the surface associated with this move event. 58 | pub fn surface(&self) -> Option { 59 | unsafe { 60 | if (*self.event).surface.is_null() { 61 | None 62 | } else { 63 | Some(xwayland::surface::Handle::from_ptr((*self.event).surface)) 64 | } 65 | } 66 | } 67 | } 68 | 69 | impl Resize { 70 | pub(crate) unsafe fn from_ptr(event: *mut wlr_xwayland_resize_event) -> Self { 71 | Resize { event } 72 | } 73 | 74 | /// Get the surface associated with this resize event. 75 | pub fn surface(&self) -> Option { 76 | unsafe { 77 | if (*self.event).surface.is_null() { 78 | None 79 | } else { 80 | Some(xwayland::surface::Handle::from_ptr((*self.event).surface)) 81 | } 82 | } 83 | } 84 | 85 | /// Get the resize edge information for the resize action. 86 | pub fn edges(&self) -> Edges { 87 | unsafe { 88 | let edges_bits = (*self.event).edges; 89 | match Edges::from_bits(edges_bits) { 90 | Some(edges) => edges, 91 | None => panic!("got invalid edges: {}", edges_bits) 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/extensions/gamma_control.rs: -------------------------------------------------------------------------------- 1 | //! Support for the wlroots Gamma Control Protocol 2 | //! 3 | //! Warning: This protocol is unstable and can change in the future 4 | //! Current Protocol: https://github.com/swaywm/wlroots/blob/master/protocol/wlr-gamma-control-unstable-v1.xml 5 | 6 | use crate::wayland_sys::server::wl_display as wl_server_display; 7 | use wlroots_sys::{ 8 | wl_display, wlr_gamma_control_manager_v1, wlr_gamma_control_manager_v1_create, 9 | wlr_gamma_control_manager_v1_destroy 10 | }; 11 | 12 | #[derive(Debug)] 13 | /// Manager that can adjust gamma controls for an output 14 | pub struct ZManagerV1 { 15 | manager: *mut wlr_gamma_control_manager_v1 16 | } 17 | 18 | impl ZManagerV1 { 19 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 20 | let manager_raw = wlr_gamma_control_manager_v1_create(display as *mut wl_display); 21 | 22 | if !manager_raw.is_null() { 23 | Some(ZManagerV1 { manager: manager_raw }) 24 | } else { 25 | None 26 | } 27 | } 28 | } 29 | 30 | impl Drop for ZManagerV1 { 31 | fn drop(&mut self) { 32 | unsafe { wlr_gamma_control_manager_v1_destroy(self.manager) } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/extensions/gtk_primary_selection.rs: -------------------------------------------------------------------------------- 1 | //! Support for the GTK Primary Selection Protocol 2 | 3 | use crate::wayland_sys::server::wl_display as wl_server_display; 4 | use wlroots_sys::{ 5 | wl_display, wlr_gtk_primary_selection_device_manager, wlr_gtk_primary_selection_device_manager_create, 6 | wlr_gtk_primary_selection_device_manager_destroy 7 | }; 8 | 9 | #[derive(Debug)] 10 | /// Manager that implements GTK primary selection 11 | pub struct Manager { 12 | manager: *mut wlr_gtk_primary_selection_device_manager 13 | } 14 | 15 | impl Manager { 16 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 17 | let manager_raw = wlr_gtk_primary_selection_device_manager_create(display as *mut wl_display); 18 | 19 | if !manager_raw.is_null() { 20 | Some(Manager { manager: manager_raw }) 21 | } else { 22 | None 23 | } 24 | } 25 | } 26 | 27 | impl Drop for Manager { 28 | fn drop(&mut self) { 29 | unsafe { wlr_gtk_primary_selection_device_manager_destroy(self.manager) } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/extensions/idle.rs: -------------------------------------------------------------------------------- 1 | //! Support for the KDE Idle Protocol 2 | 3 | use crate::seat::Seat; 4 | 5 | use crate::wayland_sys::server::wl_display as wl_server_display; 6 | use wlroots_sys::{ 7 | wl_display, wlr_idle, wlr_idle_create, wlr_idle_destroy, wlr_idle_notify_activity, wlr_idle_set_enabled 8 | }; 9 | 10 | #[derive(Debug)] 11 | pub struct Manager { 12 | manager: *mut wlr_idle 13 | } 14 | 15 | impl Manager { 16 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 17 | let manager_raw = wlr_idle_create(display as *mut wl_display); 18 | 19 | if !manager_raw.is_null() { 20 | Some(Manager { manager: manager_raw }) 21 | } else { 22 | None 23 | } 24 | } 25 | 26 | /// Restart the timers for the seat 27 | pub fn notify_activity(&mut self, seat: &Seat) { 28 | unsafe { wlr_idle_notify_activity(self.manager, seat.as_ptr()) } 29 | } 30 | 31 | /// If we are passed a null pointer, update timers for all seats. 32 | pub fn set_enabled(&mut self, seat: &Seat, enabled: bool) { 33 | unsafe { wlr_idle_set_enabled(self.manager, seat.as_ptr(), enabled) } 34 | } 35 | } 36 | 37 | impl Drop for Manager { 38 | fn drop(&mut self) { 39 | unsafe { wlr_idle_destroy(self.manager) } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/extensions/idle_inhibit.rs: -------------------------------------------------------------------------------- 1 | //! Support for the wlroots Idle Inhibit Protocol 2 | //! 3 | //! Warning: This protocol is unstable and can change in the future 4 | 5 | use crate::wayland_sys::server::wl_display as wl_server_display; 6 | use wlroots_sys::{ 7 | wl_display, wlr_idle_inhibit_manager_v1, wlr_idle_inhibit_v1_create, wlr_idle_inhibit_v1_destroy 8 | }; 9 | 10 | #[derive(Debug)] 11 | pub struct ZManagerV1 { 12 | manager: *mut wlr_idle_inhibit_manager_v1 13 | } 14 | 15 | impl ZManagerV1 { 16 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 17 | let manager_raw = wlr_idle_inhibit_v1_create(display as *mut wl_display); 18 | 19 | if !manager_raw.is_null() { 20 | Some(ZManagerV1 { manager: manager_raw }) 21 | } else { 22 | None 23 | } 24 | } 25 | } 26 | 27 | impl Drop for ZManagerV1 { 28 | fn drop(&mut self) { 29 | unsafe { wlr_idle_inhibit_v1_destroy(self.manager) } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/extensions/input_inhibit.rs: -------------------------------------------------------------------------------- 1 | //! Support for the wlroots Input Inhibit Protocol 2 | //! 3 | //! Warning: This protocol is unstable and can change in the future 4 | 5 | use crate::wayland_sys::server::wl_display as wl_server_display; 6 | use wlroots_sys::{ 7 | wl_display, wlr_input_inhibit_manager, wlr_input_inhibit_manager_create, wlr_input_inhibit_manager_destroy 8 | }; 9 | 10 | #[derive(Debug)] 11 | pub struct ZManagerV1 { 12 | manager: *mut wlr_input_inhibit_manager 13 | } 14 | 15 | impl ZManagerV1 { 16 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 17 | let manager_raw = wlr_input_inhibit_manager_create(display as *mut wl_display); 18 | 19 | if !manager_raw.is_null() { 20 | Some(ZManagerV1 { manager: manager_raw }) 21 | } else { 22 | None 23 | } 24 | } 25 | } 26 | 27 | impl Drop for ZManagerV1 { 28 | fn drop(&mut self) { 29 | unsafe { wlr_input_inhibit_manager_destroy(self.manager) } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/extensions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod gamma_control; 2 | pub mod gtk_primary_selection; 3 | pub mod idle; 4 | pub mod idle_inhibit; 5 | pub mod input_inhibit; 6 | pub mod screencopy; 7 | pub mod screenshooter; 8 | pub mod server_decoration; 9 | -------------------------------------------------------------------------------- /src/extensions/screencopy.rs: -------------------------------------------------------------------------------- 1 | //! Support for the wlroots Screencopy (Version 1) Protocol 2 | //! 3 | //! Warning: This protocol is unstable and can change in the future 4 | //! Current Protocol: https://github.com/swaywm/wlroots/blob/master/protocol/wlr-screencopy-unstable-v1.xml 5 | 6 | use crate::wayland_sys::server::wl_display as wl_server_display; 7 | use wlroots_sys::{ 8 | wl_display, wlr_screencopy_manager_v1, wlr_screencopy_manager_v1_create, 9 | wlr_screencopy_manager_v1_destroy 10 | }; 11 | 12 | #[derive(Debug)] 13 | /// Manager that offers requests to start capturing from a source 14 | pub struct ZManagerV1 { 15 | manager: *mut wlr_screencopy_manager_v1 16 | } 17 | 18 | impl ZManagerV1 { 19 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 20 | let manager_raw = wlr_screencopy_manager_v1_create(display as *mut wl_display); 21 | 22 | if !manager_raw.is_null() { 23 | Some(ZManagerV1 { manager: manager_raw }) 24 | } else { 25 | None 26 | } 27 | } 28 | } 29 | 30 | impl Drop for ZManagerV1 { 31 | fn drop(&mut self) { 32 | unsafe { wlr_screencopy_manager_v1_destroy(self.manager) } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/extensions/screenshooter.rs: -------------------------------------------------------------------------------- 1 | //! Support for the Orbital Screenshooter Protocol 2 | 3 | use crate::wayland_sys::server::wl_display as wl_server_display; 4 | use wlroots_sys::{wl_display, wlr_screenshooter, wlr_screenshooter_create, wlr_screenshooter_destroy}; 5 | 6 | #[derive(Debug)] 7 | pub struct Screenshooter { 8 | screenshooter: *mut wlr_screenshooter 9 | } 10 | 11 | impl Screenshooter { 12 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 13 | let screenshooter_raw = wlr_screenshooter_create(display as *mut wl_display); 14 | 15 | if !screenshooter_raw.is_null() { 16 | Some(Screenshooter { 17 | screenshooter: screenshooter_raw 18 | }) 19 | } else { 20 | None 21 | } 22 | } 23 | } 24 | 25 | impl Drop for Screenshooter { 26 | fn drop(&mut self) { 27 | unsafe { wlr_screenshooter_destroy(self.screenshooter) } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/extensions/server_decoration.rs: -------------------------------------------------------------------------------- 1 | //! Support for the KDE Server Decoration Protocol 2 | 3 | use crate::wayland_sys::server::wl_display as wl_server_display; 4 | pub use wlroots_sys::protocols::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode; 5 | use wlroots_sys::{ 6 | wl_display, wlr_server_decoration_manager, wlr_server_decoration_manager_create, 7 | wlr_server_decoration_manager_destroy, wlr_server_decoration_manager_set_default_mode 8 | }; 9 | 10 | #[derive(Debug)] 11 | /// Coordinates whether the server should create 12 | /// server-side window decorations. 13 | pub struct Manager { 14 | manager: *mut wlr_server_decoration_manager 15 | } 16 | 17 | impl Manager { 18 | pub(crate) unsafe fn new(display: *mut wl_server_display) -> Option { 19 | let manager_raw = wlr_server_decoration_manager_create(display as *mut wl_display); 20 | 21 | if !manager_raw.is_null() { 22 | Some(Manager { manager: manager_raw }) 23 | } else { 24 | None 25 | } 26 | } 27 | 28 | /// Given a mode, set the server decoration mode 29 | pub fn set_default_mode(&mut self, mode: Mode) { 30 | wlr_log!(WLR_INFO, "New server decoration mode: {:?}", mode); 31 | unsafe { wlr_server_decoration_manager_set_default_mode(self.manager, mode.to_raw()) } 32 | } 33 | } 34 | 35 | impl Drop for Manager { 36 | fn drop(&mut self) { 37 | unsafe { wlr_server_decoration_manager_destroy(self.manager) } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides safe bindings to 2 | //! [wlroots](https://github.com/swaywm/wlroots). 3 | #![cfg_attr(not(feature = "unstable"), allow(unused_imports, unused_macros))] 4 | #![allow(clippy::zero_ptr, clippy::cast_ptr_alignment)] 5 | #![allow(unused_unsafe)] 6 | #[macro_use] 7 | extern crate bitflags; 8 | extern crate log; 9 | extern crate vsprintf; 10 | #[macro_use] 11 | pub extern crate wlroots_sys; 12 | extern crate wlroots_dehandle; 13 | #[cfg(feature = "unstable")] 14 | pub extern crate xkbcommon; 15 | 16 | #[cfg(feature = "unstable")] 17 | pub use wlroots_dehandle::wlroots_dehandle; 18 | pub(crate) use wlroots_sys::libc; 19 | pub(crate) use wlroots_sys::wayland_sys; 20 | 21 | #[macro_use] 22 | mod macros; 23 | #[cfg(feature = "unstable")] 24 | pub mod backend; 25 | #[cfg(feature = "unstable")] 26 | pub mod compositor; 27 | #[cfg(feature = "unstable")] 28 | pub(crate) mod events; 29 | #[cfg(feature = "unstable")] 30 | pub mod extensions; 31 | #[cfg(feature = "unstable")] 32 | pub(crate) mod manager; 33 | #[cfg(feature = "unstable")] 34 | pub mod render; 35 | mod types; 36 | pub mod utils; 37 | #[cfg(feature = "unstable")] 38 | pub mod xwayland; 39 | 40 | pub use crate::types::*; 41 | 42 | #[cfg(feature = "unstable")] 43 | pub use wlroots_sys::{ 44 | wl_shm_format::{self, *}, 45 | wlr_axis_orientation::{self, *}, 46 | wlr_axis_source::{self, *}, 47 | wlr_button_state::{self, *}, 48 | wlr_input_device_type::{self, *}, 49 | wlr_key_state::{self, *}, 50 | wlr_keyboard_modifier::{self, *}, 51 | wlr_tablet_pad_ring_source::{self, *}, 52 | wlr_tablet_pad_strip_source::{self, *}, 53 | wlr_tablet_tool_axes as TabletToolAxes, 54 | wlr_tablet_tool_proximity_state::{self, *} 55 | }; 56 | -------------------------------------------------------------------------------- /src/manager/drag_icon_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handler for drag icons 2 | 3 | use crate::{compositor, seat::drag_icon}; 4 | 5 | /// Handles events from the wlr drag icon 6 | #[allow(unused_variables)] 7 | pub trait Handler { 8 | /// Called when the drag icon is ready to be displayed. 9 | fn on_map(&mut self, compositor_handle: compositor::Handle, drag_icon_handle: drag_icon::Handle); 10 | 11 | /// Called when the drag icon should no longer be displayed 12 | fn on_unmap(&mut self, compositor_handle: compositor::Handle, drag_icon_handle: drag_icon::Handle); 13 | 14 | /// Called when the drag icon is about to be destroyed. 15 | fn destroyed(&mut self, compositor_handle: compositor::Handle, drag_icon_handle: drag_icon::Handle); 16 | } 17 | -------------------------------------------------------------------------------- /src/manager/keyboard_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handler for keyboards 2 | 3 | use crate::libc; 4 | use crate::wayland_sys::server::WAYLAND_SERVER_HANDLE; 5 | use wlroots_sys::{wlr_event_keyboard_key, wlr_input_device}; 6 | 7 | use crate::{ 8 | compositor, 9 | input::keyboard::{self, Keyboard}, 10 | utils::Handleable 11 | }; 12 | 13 | #[allow(unused_variables)] 14 | pub trait Handler { 15 | /// Callback that is triggered when a key is pressed. 16 | fn on_key( 17 | &mut self, 18 | compositor_handle: compositor::Handle, 19 | keyboard_handle: keyboard::Handle, 20 | event: &keyboard::event::Key 21 | ) { 22 | } 23 | 24 | /// Callback that is triggered when modifiers are pressed. 25 | fn modifiers(&mut self, compositor_handle: compositor::Handle, keyboard_handle: keyboard::Handle) {} 26 | 27 | /// Callback that is triggered when the keymap is updated. 28 | fn keymap(&mut self, compositor_handle: compositor::Handle, keyboard_handle: keyboard::Handle) {} 29 | 30 | /// Callback that is triggered when repeat info is updated. 31 | fn repeat_info(&mut self, compositor_handle: compositor::Handle, keyboard_handle: keyboard::Handle) {} 32 | 33 | /// Callback that is triggered when the keyboard is destroyed. 34 | fn destroyed(&mut self, compositor_handle: compositor::Handle, keyboard_handle: keyboard::Handle) {} 35 | } 36 | 37 | wayland_listener!(pub(crate) KeyboardWrapper, (Keyboard, Box), [ 38 | on_destroy_listener => on_destroy_notify: |this: &mut KeyboardWrapper, data: *mut libc::c_void,| 39 | unsafe { 40 | let input_device_ptr = data as *mut wlr_input_device; 41 | { 42 | let (ref mut keyboard, ref mut keyboard_handler) = this.data; 43 | let compositor = match compositor::handle() { 44 | Some(handle) => handle, 45 | None => return 46 | }; 47 | keyboard_handler.destroyed(compositor, keyboard.weak_reference()); 48 | } 49 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 50 | wl_list_remove, 51 | &mut (*this.on_destroy_listener()).link as *mut _ as _); 52 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 53 | wl_list_remove, 54 | &mut (*this.key_listener()).link as *mut _ as _); 55 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 56 | wl_list_remove, 57 | &mut (*this.modifiers_listener()).link as *mut _ as _); 58 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 59 | wl_list_remove, 60 | &mut (*this.keymap_listener()).link as *mut _ as _); 61 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 62 | wl_list_remove, 63 | &mut (*this.repeat_listener()).link as *mut _ as _); 64 | Box::from_raw((*input_device_ptr).data as *mut KeyboardWrapper); 65 | }; 66 | key_listener => key_notify: |this: &mut KeyboardWrapper, data: *mut libc::c_void,| unsafe { 67 | let (ref mut keyboard, ref mut keyboard_handler) = this.data; 68 | let compositor = match compositor::handle() { 69 | Some(handle) => handle, 70 | None => return 71 | }; 72 | let xkb_state = (*keyboard.as_ptr()).xkb_state; 73 | let key = keyboard::event::Key::new(data as *mut wlr_event_keyboard_key, xkb_state); 74 | 75 | keyboard_handler.on_key(compositor, keyboard.weak_reference(), &key); 76 | }; 77 | modifiers_listener => modifiers_notify: |this: &mut KeyboardWrapper, _data: *mut libc::c_void,| 78 | unsafe { 79 | let (ref mut keyboard, ref mut keyboard_handler) = this.data; 80 | let compositor = match compositor::handle() { 81 | Some(handle) => handle, 82 | None => return 83 | }; 84 | 85 | keyboard_handler.modifiers(compositor, keyboard.weak_reference()); 86 | }; 87 | keymap_listener => keymap_notify: |this: &mut KeyboardWrapper, _data: *mut libc::c_void,| 88 | unsafe { 89 | let (ref mut keyboard, ref mut keyboard_handler) = this.data; 90 | let compositor = match compositor::handle() { 91 | Some(handle) => handle, 92 | None => return 93 | }; 94 | 95 | keyboard_handler.keymap(compositor, keyboard.weak_reference()); 96 | }; 97 | repeat_listener => repeat_notify: |this: &mut KeyboardWrapper, _data: *mut libc::c_void,| 98 | unsafe { 99 | let (ref mut keyboard, ref mut keyboard_handler) = this.data; 100 | let compositor = match compositor::handle() { 101 | Some(handle) => handle, 102 | None => return 103 | }; 104 | 105 | keyboard_handler.repeat_info(compositor, keyboard.weak_reference()); 106 | }; 107 | ]); 108 | -------------------------------------------------------------------------------- /src/manager/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod drag_icon_handler; 2 | pub(crate) mod input_manager; 3 | pub(crate) mod keyboard_handler; 4 | pub(crate) mod output_handler; 5 | pub(crate) mod output_manager; 6 | pub(crate) mod pointer_handler; 7 | pub(crate) mod switch_handler; 8 | pub(crate) mod tablet_pad_handler; 9 | pub(crate) mod tablet_tool_handler; 10 | pub(crate) mod touch_handler; 11 | pub(crate) mod xdg_shell_handler; 12 | pub(crate) mod xdg_shell_manager; 13 | pub(crate) mod xdg_shell_v6_handler; 14 | pub(crate) mod xdg_shell_v6_manager; 15 | -------------------------------------------------------------------------------- /src/manager/output_manager.rs: -------------------------------------------------------------------------------- 1 | //! Manager that is called when an output is created or destroyed. 2 | 3 | use std::{marker::PhantomData, panic, ptr::NonNull}; 4 | 5 | use crate::libc; 6 | use crate::wayland_sys::server::signal::wl_signal_add; 7 | use wlroots_sys::wlr_output; 8 | 9 | use crate::{ 10 | compositor, 11 | output::{self, Output, OutputState, UserOutput}, 12 | utils::Handleable 13 | }; 14 | 15 | /// Used to ensure the output sets the mode before doing any other 16 | /// operation on the Output. 17 | pub struct OutputBuilder<'output> { 18 | output: output::Handle, 19 | phantom: PhantomData<&'output Output> 20 | } 21 | 22 | /// Used to ensure that the builder is used to construct 23 | /// the output::Handler instance. 24 | pub struct BuilderResult<'output> { 25 | pub output: output::Handle, 26 | result: Box, 27 | phantom: PhantomData<&'output Output> 28 | } 29 | 30 | /// Wrapper around Output destruction so that you can't call 31 | /// unsafe methods (e.g anything like setting the mode). 32 | pub struct Destroyed(output::Handle); 33 | 34 | impl<'output> OutputBuilder<'output> { 35 | /// Build the output with the best mode. 36 | /// 37 | /// To complete construction, return this in your implementation of 38 | /// `output::ManagerHandler::output_added`. 39 | pub fn build_best_mode(mut self, data: T) -> BuilderResult<'output> { 40 | with_handles!([(output: {&mut self.output})] => { 41 | output.choose_best_mode(); 42 | }) 43 | .expect("Output was borrowed"); 44 | BuilderResult { 45 | output: self.output, 46 | result: Box::new(data), 47 | phantom: PhantomData 48 | } 49 | } 50 | } 51 | 52 | impl Destroyed { 53 | // TODO Functions which are safe to use 54 | } 55 | 56 | pub type OutputAdded = 57 | fn(compositor_handle: compositor::Handle, output_builder: OutputBuilder) -> Option; 58 | 59 | wayland_listener_static! { 60 | static mut MANAGER; 61 | (Manager, Builder): [ 62 | (OutputAdded, add_listener, output_added) => (add_notify, add_callback): 63 | |manager: &mut Manager, data: *mut libc::c_void,| unsafe { 64 | let data = data as *mut wlr_output; 65 | let output = Output::new(data as *mut wlr_output); 66 | // NOTE 67 | // This clone is required because we pass it mutably to the output builder, 68 | // but due to lack of NLL there's no way to tell Rust it's safe to use it in 69 | // in the if branch. 70 | // 71 | // Thus, we need to clone it here and then drop the original once at the end. 72 | // 73 | // This is not a real clone, but an pub(crate) unsafe one we added, so it doesn't 74 | // break safety concerns in user code. Just an unfortunate hack we have to put here. 75 | let output_clone = output.clone(); 76 | let builder = OutputBuilder { output: output.weak_reference(), phantom: PhantomData }; 77 | let compositor = match compositor::handle() { 78 | Some(handle) => handle, 79 | None => return 80 | }; 81 | let res = panic::catch_unwind( 82 | panic::AssertUnwindSafe(|| manager.add_callback 83 | .map(|f| f(compositor, builder)) 84 | .unwrap_or(None))); 85 | let build_result = match res { 86 | Ok(res) => res, 87 | // NOTE 88 | // Either Wayland or wlroots does not handle failure to set up output correctly. 89 | // Calling wl_display_terminate does not work if output is incorrectly set up. 90 | // 91 | // Instead, execution keeps going with an eventual segfault (if lucky). 92 | // 93 | // To fix this, we abort the process if there was a panic in output setup. 94 | Err(_) => ::std::process::abort() 95 | }; 96 | if let Some(BuilderResult {result: output_ptr, .. }) = build_result { 97 | let mut output = UserOutput::new((output_clone, output_ptr)); 98 | wl_signal_add(&mut (*data).events.frame as *mut _ as _, 99 | output.frame_listener() as _); 100 | wl_signal_add(&mut (*data).events.mode as *mut _ as _, 101 | output.mode_listener() as _); 102 | wl_signal_add(&mut (*data).events.enable as *mut _ as _, 103 | output.enable_listener() as _); 104 | wl_signal_add(&mut (*data).events.scale as *mut _ as _, 105 | output.scale_listener() as _); 106 | wl_signal_add(&mut (*data).events.transform as *mut _ as _, 107 | output.transform_listener() as _); 108 | wl_signal_add(&mut (*data).events.swap_buffers as *mut _ as _, 109 | output.swap_buffers_listener() as _); 110 | wl_signal_add(&mut (*data).events.needs_swap as *mut _ as _, 111 | output.need_swap_listener() as _); 112 | wl_signal_add(&mut (*data).events.destroy as *mut _ as _, 113 | output.on_destroy_listener() as _); 114 | let output_data = (*data).data as *mut OutputState; 115 | (*output_data).output = NonNull::new(Box::into_raw(output)); 116 | } 117 | }; 118 | ] 119 | } 120 | -------------------------------------------------------------------------------- /src/manager/pointer_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handler for pointers 2 | 3 | use crate::libc; 4 | use crate::wayland_sys::server::WAYLAND_SERVER_HANDLE; 5 | use wlroots_sys::{ 6 | wlr_event_pointer_axis, wlr_event_pointer_button, wlr_event_pointer_motion, wlr_input_device 7 | }; 8 | 9 | use crate::{ 10 | compositor, 11 | input::pointer::{self, Pointer}, 12 | utils::Handleable 13 | }; 14 | 15 | #[allow(unused_variables)] 16 | pub trait Handler { 17 | /// Callback that is triggered when the pointer moves. 18 | fn on_motion( 19 | &mut self, 20 | compositor_handle: compositor::Handle, 21 | pointer_handle: pointer::Handle, 22 | event: &pointer::event::Motion 23 | ) { 24 | } 25 | 26 | fn on_motion_absolute( 27 | &mut self, 28 | compositor_handle: compositor::Handle, 29 | pointer_handle: pointer::Handle, 30 | event: &pointer::event::AbsoluteMotion 31 | ) { 32 | } 33 | 34 | /// Callback that is triggered when the buttons on the pointer are pressed. 35 | fn on_button( 36 | &mut self, 37 | compositor_handle: compositor::Handle, 38 | pointer_handle: pointer::Handle, 39 | event: &pointer::event::Button 40 | ) { 41 | } 42 | 43 | /// Callback that is triggered when an axis event fires. 44 | fn on_axis( 45 | &mut self, 46 | compositor_handle: compositor::Handle, 47 | pointer_handle: pointer::Handle, 48 | event: &pointer::event::Axis 49 | ) { 50 | } 51 | 52 | /// Callback that is triggered when the pointer is destroyed. 53 | fn destroyed(&mut self, compositor_handle: compositor::Handle, pointer_handle: pointer::Handle) {} 54 | } 55 | 56 | wayland_listener!(pub(crate) PointerWrapper, (Pointer, Box), [ 57 | on_destroy_listener => on_destroy_notify: |this: &mut PointerWrapper, data: *mut libc::c_void,| 58 | unsafe { 59 | let input_device_ptr = data as *mut wlr_input_device; 60 | { 61 | let (ref mut pointer, ref mut pointer_handler) = this.data; 62 | let compositor = match compositor::handle() { 63 | Some(handle) => handle, 64 | None => return 65 | }; 66 | pointer_handler.destroyed(compositor, pointer.weak_reference()); 67 | } 68 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 69 | wl_list_remove, 70 | &mut (*this.on_destroy_listener()).link as *mut _ as _); 71 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 72 | wl_list_remove, 73 | &mut (*this.button_listener()).link as *mut _ as _); 74 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 75 | wl_list_remove, 76 | &mut (*this.motion_listener()).link as *mut _ as _); 77 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 78 | wl_list_remove, 79 | &mut (*this.motion_absolute_listener()).link as *mut _ as _); 80 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 81 | wl_list_remove, 82 | &mut (*this.axis_listener()).link as *mut _ as _); 83 | Box::from_raw((*input_device_ptr).data as *mut PointerWrapper); 84 | }; 85 | button_listener => key_notify: |this: &mut PointerWrapper, data: *mut libc::c_void,| unsafe { 86 | let pointer = &mut this.data.0; 87 | let event = pointer::event::Button::from_ptr(data as *mut wlr_event_pointer_button); 88 | let compositor = match compositor::handle() { 89 | Some(handle) => handle, 90 | None => return 91 | }; 92 | 93 | this.data.1.on_button(compositor, pointer.weak_reference(), &event); 94 | }; 95 | motion_listener => motion_notify: |this: &mut PointerWrapper, data: *mut libc::c_void,| 96 | unsafe { 97 | let pointer = &mut this.data.0; 98 | let event = pointer::event::Motion::from_ptr(data as *mut wlr_event_pointer_motion); 99 | let compositor = match compositor::handle() { 100 | Some(handle) => handle, 101 | None => return 102 | }; 103 | 104 | this.data.1.on_motion(compositor, pointer.weak_reference(), &event); 105 | }; 106 | motion_absolute_listener => motion_absolute_notify: 107 | |this: &mut PointerWrapper, data: *mut libc::c_void,| unsafe { 108 | let pointer = &mut this.data.0; 109 | let event = pointer::event::AbsoluteMotion::from_ptr(data as *mut _); 110 | let compositor = match compositor::handle() { 111 | Some(handle) => handle, 112 | None => return 113 | }; 114 | 115 | this.data.1.on_motion_absolute(compositor, pointer.weak_reference(), &event); 116 | }; 117 | axis_listener => axis_notify: |this: &mut PointerWrapper, data: *mut libc::c_void,| unsafe { 118 | let pointer = &mut this.data.0; 119 | let event = pointer::event::Axis::from_ptr(data as *mut wlr_event_pointer_axis); 120 | let compositor = match compositor::handle() { 121 | Some(handle) => handle, 122 | None => return 123 | }; 124 | 125 | this.data.1.on_axis(compositor, pointer.weak_reference(), &event); 126 | }; 127 | ]); 128 | -------------------------------------------------------------------------------- /src/manager/switch_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handler for lid switches 2 | 3 | use crate::libc; 4 | use crate::wayland_sys::server::WAYLAND_SERVER_HANDLE; 5 | use wlroots_sys::{wlr_event_switch_toggle, wlr_input_device}; 6 | 7 | use crate::{ 8 | compositor, 9 | input::switch::{self, Switch}, 10 | utils::Handleable 11 | }; 12 | 13 | #[allow(unused_variables)] 14 | pub trait Handler { 15 | /// Callback that is triggered when the switch moves. 16 | fn on_toggle( 17 | &mut self, 18 | compositor_handle: compositor::Handle, 19 | switch_handle: switch::Handle, 20 | event: &switch::event::Toggle 21 | ) { 22 | } 23 | 24 | /// Callback that is triggered when the switch is destroyed. 25 | fn destroyed(&mut self, compositor_handle: compositor::Handle, switch_handle: switch::Handle) {} 26 | } 27 | 28 | wayland_listener!(pub(crate) SwitchWrapper, (Switch, Box), [ 29 | on_destroy_listener => on_destroy_notify: |this: &mut SwitchWrapper, data: *mut libc::c_void,| 30 | unsafe { 31 | let input_device_ptr = data as *mut wlr_input_device; 32 | { 33 | let (ref mut switch, ref mut switch_handler) = this.data; 34 | let compositor = match compositor::handle() { 35 | Some(handle) => handle, 36 | None => return 37 | }; 38 | switch_handler.destroyed(compositor, switch.weak_reference()); 39 | } 40 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 41 | wl_list_remove, 42 | &mut (*this.on_toggle_listener()).link as *mut _ as _); 43 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 44 | wl_list_remove, 45 | &mut (*this.on_destroy_listener()).link as *mut _ as _); 46 | Box::from_raw((*input_device_ptr).data as *mut SwitchWrapper); 47 | }; 48 | on_toggle_listener => on_toggle_notify: |this: &mut SwitchWrapper, data: *mut libc::c_void,| 49 | unsafe { 50 | let (ref mut switch, ref mut switch_handler) = this.data; 51 | let event = switch::event::Toggle::from_ptr(data as *mut wlr_event_switch_toggle); 52 | let compositor = match compositor::handle() { 53 | Some(handle) => handle, 54 | None => return 55 | }; 56 | switch_handler.on_toggle(compositor, switch.weak_reference(), &event); 57 | }; 58 | ]); 59 | -------------------------------------------------------------------------------- /src/manager/tablet_pad_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handler for tablet pads 2 | 3 | use crate::libc; 4 | use crate::wayland_sys::server::WAYLAND_SERVER_HANDLE; 5 | use wlroots_sys::wlr_input_device; 6 | 7 | use crate::{ 8 | compositor, 9 | input::tablet_pad::{self, TabletPad}, 10 | utils::Handleable 11 | }; 12 | 13 | #[allow(unused_variables)] 14 | pub trait Handler { 15 | /// Callback that is triggered when a button is pressed on the tablet pad. 16 | fn on_button( 17 | &mut self, 18 | compositor_handle: compositor::Handle, 19 | tablet_pad_handle: tablet_pad::Handle, 20 | event: &tablet_pad::event::Button 21 | ) { 22 | } 23 | 24 | /// Callback that is triggered when the touch strip is used. 25 | fn on_strip( 26 | &mut self, 27 | compositor_handle: compositor::Handle, 28 | tablet_pad_handle: tablet_pad::Handle, 29 | event: &tablet_pad::event::Strip 30 | ) { 31 | } 32 | 33 | /// Callback that is triggered when the ring is touched. 34 | fn on_ring( 35 | &mut self, 36 | compositor_handle: compositor::Handle, 37 | tablet_pad_handle: tablet_pad::Handle, 38 | event: &tablet_pad::event::Ring 39 | ) { 40 | } 41 | 42 | /// Callback that is triggered when the pad device is destroyed. 43 | fn destroyed(&mut self, compositor_handle: compositor::Handle, tablet_pad_handle: tablet_pad::Handle) {} 44 | } 45 | 46 | wayland_listener!(pub(crate) TabletPadWrapper, (TabletPad, Box), [ 47 | on_destroy_listener => on_destroy_notify: |this: &mut TabletPadWrapper, data: *mut libc::c_void,| 48 | unsafe { 49 | let input_device_ptr = data as *mut wlr_input_device; 50 | { 51 | let (ref mut pad, ref mut tablet_pad_handler) = this.data; 52 | let compositor = match compositor::handle() { 53 | Some(handle) => handle, 54 | None => return 55 | }; 56 | tablet_pad_handler.destroyed(compositor, pad.weak_reference()); 57 | } 58 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 59 | wl_list_remove, 60 | &mut (*this.on_destroy_listener()).link as *mut _ as _); 61 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 62 | wl_list_remove, 63 | &mut (*this.button_listener()).link as *mut _ as _); 64 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 65 | wl_list_remove, 66 | &mut (*this.ring_listener()).link as *mut _ as _); 67 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 68 | wl_list_remove, 69 | &mut (*this.strip_listener()).link as *mut _ as _); 70 | Box::from_raw((*input_device_ptr).data as *mut TabletPadWrapper); 71 | }; 72 | button_listener => button_notify: |this: &mut TabletPadWrapper, data: *mut libc::c_void,| 73 | unsafe { 74 | let (ref pad, ref mut handler) = this.data; 75 | let event = tablet_pad::event::Button::from_ptr(data as *mut _); 76 | let compositor = match compositor::handle() { 77 | Some(handle) => handle, 78 | None => return 79 | }; 80 | 81 | handler.on_button(compositor, 82 | pad.weak_reference(), 83 | &event); 84 | }; 85 | strip_listener => strip_notify: |this: &mut TabletPadWrapper, data: *mut libc::c_void,| 86 | unsafe { 87 | let (ref pad, ref mut handler) = this.data; 88 | let event = tablet_pad::event::Strip::from_ptr(data as *mut _); 89 | let compositor = match compositor::handle() { 90 | Some(handle) => handle, 91 | None => return 92 | }; 93 | 94 | handler.on_strip(compositor, 95 | pad.weak_reference(), 96 | &event); 97 | }; 98 | ring_listener => ring_notify: |this: &mut TabletPadWrapper, data: *mut libc::c_void,| 99 | unsafe { 100 | let (ref pad, ref mut handler) = this.data; 101 | let event = tablet_pad::event::Ring::from_ptr(data as *mut _); 102 | let compositor = match compositor::handle() { 103 | Some(handle) => handle, 104 | None => return 105 | }; 106 | 107 | handler.on_ring(compositor, 108 | pad.weak_reference(), 109 | &event); 110 | }; 111 | ]); 112 | -------------------------------------------------------------------------------- /src/manager/tablet_tool_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handler for tablet tools 2 | 3 | use crate::libc; 4 | use crate::wayland_sys::server::WAYLAND_SERVER_HANDLE; 5 | use wlroots_sys::wlr_input_device; 6 | 7 | use crate::{ 8 | compositor, 9 | input::tablet_tool::{self, TabletTool}, 10 | utils::Handleable 11 | }; 12 | 13 | #[allow(unused_variables)] 14 | pub trait Handler { 15 | /// Callback that is triggered when an axis event fires 16 | fn on_axis( 17 | &mut self, 18 | compositor_handle: compositor::Handle, 19 | tablet_tool_handle: tablet_tool::Handle, 20 | event: &tablet_tool::event::Axis 21 | ) { 22 | } 23 | 24 | /// Callback that is triggered when a table tool is brought close to the 25 | /// input source. 26 | fn on_proximity( 27 | &mut self, 28 | compositor_handle: compositor::Handle, 29 | tablet_tool_handle: tablet_tool::Handle, 30 | event: &tablet_tool::event::Proximity 31 | ) { 32 | } 33 | 34 | /// Callback that is triggered when a table tool's tip touches the input 35 | /// source. 36 | fn on_tip( 37 | &mut self, 38 | compositor_handle: compositor::Handle, 39 | tablet_tool_handle: tablet_tool::Handle, 40 | event: &tablet_tool::event::Tip 41 | ) { 42 | } 43 | 44 | /// Callback that is triggered when a button is pressed on the tablet tool. 45 | fn on_button( 46 | &mut self, 47 | compositor_handle: compositor::Handle, 48 | tablet_tool_handle: tablet_tool::Handle, 49 | event: &tablet_tool::event::Button 50 | ) { 51 | } 52 | 53 | /// Callback that is triggered when a tablet tool is destroyed. 54 | fn destroyed(&mut self, compositor_handle: compositor::Handle, tablet_tool_handle: tablet_tool::Handle) {} 55 | } 56 | 57 | wayland_listener!(pub(crate) TabletToolWrapper, (TabletTool, Box), [ 58 | on_destroy_listener => on_destroy_notify: |this: &mut TabletToolWrapper, data: *mut libc::c_void,| 59 | unsafe { 60 | let input_device_ptr = data as *mut wlr_input_device; 61 | { 62 | let (ref mut tool, ref mut tablet_tool_handler) = this.data; 63 | let compositor = match compositor::handle() { 64 | Some(handle) => handle, 65 | None => return 66 | }; 67 | tablet_tool_handler.destroyed(compositor, tool.weak_reference()); 68 | } 69 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 70 | wl_list_remove, 71 | &mut (*this.on_destroy_listener()).link as *mut _ as _); 72 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 73 | wl_list_remove, 74 | &mut (*this.axis_listener()).link as *mut _ as _); 75 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 76 | wl_list_remove, 77 | &mut (*this.proximity_listener()).link as *mut _ as _); 78 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 79 | wl_list_remove, 80 | &mut (*this.tip_listener()).link as *mut _ as _); 81 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 82 | wl_list_remove, 83 | &mut (*this.button_listener()).link as *mut _ as _); 84 | Box::from_raw((*input_device_ptr).data as *mut TabletToolWrapper); 85 | }; 86 | axis_listener => axis_notify: |this: &mut TabletToolWrapper, data: *mut libc::c_void,| unsafe { 87 | let (ref tool, ref mut handler) = this.data; 88 | let event = tablet_tool::event::Axis::from_ptr(data as *mut _); 89 | let compositor = match compositor::handle() { 90 | Some(handle) => handle, 91 | None => return 92 | }; 93 | 94 | handler.on_axis(compositor, 95 | tool.weak_reference(), 96 | &event); 97 | }; 98 | proximity_listener => proximity_notify: |this: &mut TabletToolWrapper, 99 | data: *mut libc::c_void,| 100 | unsafe { 101 | let (ref tool, ref mut handler) = this.data; 102 | let event = tablet_tool::event::Proximity::from_ptr(data as *mut _); 103 | let compositor = match compositor::handle() { 104 | Some(handle) => handle, 105 | None => return 106 | }; 107 | 108 | handler.on_proximity(compositor, 109 | tool.weak_reference(), 110 | &event); 111 | }; 112 | tip_listener => tip_notify: |this: &mut TabletToolWrapper, data: *mut libc::c_void,| unsafe { 113 | let (ref tool, ref mut handler) = this.data; 114 | let event = tablet_tool::event::Tip::from_ptr(data as *mut _); 115 | let compositor = match compositor::handle() { 116 | Some(handle) => handle, 117 | None => return 118 | }; 119 | 120 | handler.on_tip(compositor, 121 | tool.weak_reference(), 122 | &event); 123 | }; 124 | button_listener => button_notify: |this: &mut TabletToolWrapper, data: *mut libc::c_void,| 125 | unsafe { 126 | let (ref tool, ref mut handler) = this.data; 127 | let event = tablet_tool::event::Button::from_ptr(data as *mut _); 128 | let compositor = match compositor::handle() { 129 | Some(handle) => handle, 130 | None => return 131 | }; 132 | 133 | handler.on_button(compositor, 134 | tool.weak_reference(), 135 | &event); 136 | }; 137 | ]); 138 | -------------------------------------------------------------------------------- /src/manager/touch_handler.rs: -------------------------------------------------------------------------------- 1 | //! Handler for touch input 2 | 3 | use crate::libc; 4 | use crate::wayland_sys::server::WAYLAND_SERVER_HANDLE; 5 | use wlroots_sys::wlr_input_device; 6 | 7 | use crate::{ 8 | compositor, 9 | input::touch::{self, Touch}, 10 | utils::Handleable 11 | }; 12 | 13 | #[allow(unused_variables)] 14 | pub trait Handler { 15 | /// Callback that is triggered when the user starts touching the 16 | /// screen/input device. 17 | fn on_down( 18 | &mut self, 19 | compositor_handle: compositor::Handle, 20 | touch_handle: touch::Handle, 21 | event: &touch::event::Down 22 | ) { 23 | } 24 | 25 | /// Callback that is triggered when the user stops touching the 26 | /// screen/input device. 27 | fn on_up( 28 | &mut self, 29 | compositor_handle: compositor::Handle, 30 | touch_handle: touch::Handle, 31 | event: &touch::event::Up 32 | ) { 33 | } 34 | 35 | /// Callback that is triggered when the user moves his fingers along the 36 | /// screen/input device. 37 | fn on_motion( 38 | &mut self, 39 | compositor_handle: compositor::Handle, 40 | touch_handle: touch::Handle, 41 | event: &touch::event::Motion 42 | ) { 43 | } 44 | 45 | /// Callback triggered when the touch is canceled. 46 | fn on_cancel( 47 | &mut self, 48 | compositor_handle: compositor::Handle, 49 | touch_handle: touch::Handle, 50 | event: &touch::event::Cancel 51 | ) { 52 | } 53 | 54 | /// Callback that is triggered when the touch is destroyed. 55 | fn destroyed(&mut self, compositor_handle: compositor::Handle, touch_handle: touch::Handle) {} 56 | } 57 | 58 | wayland_listener!(pub(crate) TouchWrapper, (Touch, Box), [ 59 | on_destroy_listener => on_destroy_notify: |this: &mut TouchWrapper, data: *mut libc::c_void,| 60 | unsafe { 61 | let input_device_ptr = data as *mut wlr_input_device; 62 | { 63 | let (ref mut touch, ref mut touch_handler) = this.data; 64 | let compositor = match compositor::handle() { 65 | Some(handle) => handle, 66 | None => return 67 | }; 68 | touch_handler.destroyed(compositor, touch.weak_reference()); 69 | } 70 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 71 | wl_list_remove, 72 | &mut (*this.on_destroy_listener()).link as *mut _ as _); 73 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 74 | wl_list_remove, 75 | &mut (*this.down_listener()).link as *mut _ as _); 76 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 77 | wl_list_remove, 78 | &mut (*this.up_listener()).link as *mut _ as _); 79 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 80 | wl_list_remove, 81 | &mut (*this.motion_listener()).link as *mut _ as _); 82 | ffi_dispatch!(WAYLAND_SERVER_HANDLE, 83 | wl_list_remove, 84 | &mut (*this.cancel_listener()).link as *mut _ as _); 85 | Box::from_raw((*input_device_ptr).data as *mut TouchWrapper); 86 | }; 87 | down_listener => down_notify: |this: &mut TouchWrapper, data: *mut libc::c_void,| unsafe { 88 | let (ref touch, ref mut handler) = this.data; 89 | let event = touch::event::Down::from_ptr(data as *mut _); 90 | let compositor = match compositor::handle() { 91 | Some(handle) => handle, 92 | None => return 93 | }; 94 | 95 | handler.on_down(compositor, 96 | touch.weak_reference(), 97 | &event); 98 | }; 99 | up_listener => up_notify: |this: &mut TouchWrapper, data: *mut libc::c_void,| unsafe { 100 | let (ref touch, ref mut handler) = this.data; 101 | let event = touch::event::Up::from_ptr(data as *mut _); 102 | let compositor = match compositor::handle() { 103 | Some(handle) => handle, 104 | None => return 105 | }; 106 | 107 | handler.on_up(compositor, 108 | touch.weak_reference(), 109 | &event); 110 | }; 111 | motion_listener => motion_notify: |this: &mut TouchWrapper, data: *mut libc::c_void,| unsafe { 112 | let (ref touch, ref mut handler) = this.data; 113 | let event = touch::event::Motion::from_ptr(data as *mut _); 114 | let compositor = match compositor::handle() { 115 | Some(handle) => handle, 116 | None => return 117 | }; 118 | 119 | handler.on_motion(compositor, 120 | touch.weak_reference(), 121 | &event); 122 | }; 123 | cancel_listener => cancel_notify: |this: &mut TouchWrapper, data: *mut libc::c_void,| unsafe { 124 | let (ref touch, ref mut handler) = this.data; 125 | let event = touch::event::Cancel::from_ptr(data as *mut _); 126 | let compositor = match compositor::handle() { 127 | Some(handle) => handle, 128 | None => return 129 | }; 130 | 131 | handler.on_cancel(compositor, 132 | touch.weak_reference(), 133 | &event); 134 | }; 135 | ]); 136 | -------------------------------------------------------------------------------- /src/manager/xdg_shell_manager.rs: -------------------------------------------------------------------------------- 1 | //! Manager for stable XDG shell client. 2 | 3 | use std::ptr::NonNull; 4 | 5 | use crate::libc; 6 | use crate::wayland_sys::server::signal::wl_signal_add; 7 | use wlroots_sys::{wlr_xdg_surface, wlr_xdg_surface_role::*}; 8 | 9 | use super::xdg_shell_handler::XdgShell; 10 | use crate::{ 11 | compositor, 12 | shell::xdg_shell::{self, ShellState}, 13 | surface, 14 | utils::Handleable 15 | }; 16 | 17 | pub type NewSurfaceResult = (Option>, Option>); 18 | 19 | /// Callback that is triggered when a new stable XDG shell surface appears. 20 | pub type NewSurface = 21 | fn(compositor_handle: compositor::Handle, xdg_shell_handle: xdg_shell::Handle) -> NewSurfaceResult; 22 | 23 | wayland_listener_static! { 24 | static mut MANAGER; 25 | (Manager, Builder): [ 26 | (NewSurface, add_listener, surface_added) => (add_notify, surface_added): 27 | |manager: &mut Manager, data: *mut libc::c_void,| 28 | unsafe { 29 | let xdg_surface = NonNull::new(data as *mut wlr_xdg_surface) 30 | .expect("Xdg shell surface was null"); 31 | let xdg_surface_ptr = xdg_surface.as_ptr(); 32 | let compositor = match compositor::handle() { 33 | Some(handle) => handle, 34 | None => return 35 | }; 36 | wlr_log!(WLR_DEBUG, "New xdg_shell_surface request {:p}", xdg_surface_ptr); 37 | let state = unsafe { 38 | match (*xdg_surface_ptr).role { 39 | WLR_XDG_SURFACE_ROLE_NONE => None, 40 | WLR_XDG_SURFACE_ROLE_TOPLEVEL => { 41 | let toplevel = NonNull::new((*xdg_surface_ptr).__bindgen_anon_1.toplevel) 42 | .expect("XDG Toplevel pointer was null"); 43 | Some(ShellState::TopLevel(xdg_shell::TopLevel::from_shell(xdg_surface, toplevel))) 44 | } 45 | WLR_XDG_SURFACE_ROLE_POPUP => { 46 | let popup = NonNull::new((*xdg_surface_ptr).__bindgen_anon_1.popup) 47 | .expect("XDG Popup pointer was null"); 48 | Some(ShellState::Popup(xdg_shell::Popup::from_shell(xdg_surface, popup))) 49 | } 50 | } 51 | }; 52 | let shell_surface = xdg_shell::Surface::new(xdg_surface, state); 53 | 54 | let (shell_surface_manager, surface_handler) = 55 | match manager.surface_added { 56 | None => (None, None), 57 | Some(f) => f(compositor, shell_surface.weak_reference()) 58 | }; 59 | 60 | let mut shell_surface = XdgShell::new((shell_surface, shell_surface_manager)); 61 | let surface_state = (*(*xdg_surface_ptr).surface).data as *mut surface::InternalState; 62 | if let Some(surface_handler) = surface_handler { 63 | (*(*surface_state).surface.unwrap().as_ptr()).data().1 = surface_handler; 64 | } 65 | 66 | wl_signal_add(&mut (*xdg_surface_ptr).events.destroy as *mut _ as _, 67 | shell_surface.destroy_listener() as _); 68 | wl_signal_add(&mut (*(*xdg_surface_ptr).surface).events.commit as *mut _ as _, 69 | shell_surface.commit_listener() as _); 70 | wl_signal_add(&mut (*xdg_surface_ptr).events.ping_timeout as *mut _ as _, 71 | shell_surface.ping_timeout_listener() as _); 72 | wl_signal_add(&mut (*xdg_surface_ptr).events.new_popup as *mut _ as _, 73 | shell_surface.new_popup_listener() as _); 74 | wl_signal_add(&mut (*xdg_surface_ptr).events.map as *mut _ as _, 75 | shell_surface.map_listener() as _); 76 | wl_signal_add(&mut (*xdg_surface_ptr).events.unmap as *mut _ as _, 77 | shell_surface.unmap_listener() as _); 78 | let events = with_handles!([(shell_surface: {shell_surface.surface_mut()})] => { 79 | match shell_surface.state() { 80 | None | Some(&mut ShellState::Popup(_)) => None, 81 | Some(&mut ShellState::TopLevel(ref mut toplevel)) => Some((*toplevel.as_ptr()).events) 82 | } 83 | }).expect("Cannot borrow xdg shell surface"); 84 | if let Some(mut events) = events { 85 | wl_signal_add(&mut events.request_maximize as *mut _ as _, 86 | shell_surface.maximize_listener() as _); 87 | wl_signal_add(&mut events.request_fullscreen as *mut _ as _, 88 | shell_surface.fullscreen_listener() as _); 89 | wl_signal_add(&mut events.request_minimize as *mut _ as _, 90 | shell_surface.minimize_listener() as _); 91 | wl_signal_add(&mut events.request_move as *mut _ as _, 92 | shell_surface.move_listener() as _); 93 | wl_signal_add(&mut events.request_resize as *mut _ as _, 94 | shell_surface.resize_listener() as _); 95 | wl_signal_add(&mut events.request_show_window_menu as *mut _ as _, 96 | shell_surface.show_window_menu_listener() as _); 97 | } 98 | let shell_data = (*xdg_surface_ptr).data as *mut xdg_shell::SurfaceState; 99 | (*shell_data).shell = NonNull::new(Box::into_raw(shell_surface)); 100 | }; 101 | ] 102 | } 103 | -------------------------------------------------------------------------------- /src/render/image.rs: -------------------------------------------------------------------------------- 1 | use crate::cursor::xcursor; 2 | 3 | /// An image that can be attached to a `Cursor` or `OutputCursor`. 4 | #[derive(Debug, Default, PartialEq)] 5 | pub struct Image<'buffer> { 6 | pub pixels: &'buffer [u8], 7 | pub stride: i32, 8 | pub width: u32, 9 | pub height: u32, 10 | pub hotspot_x: i32, 11 | pub hotspot_y: i32, 12 | pub delay: u32, 13 | pub scale: f32 14 | } 15 | 16 | impl<'buffer> Image<'buffer> { 17 | #[allow(clippy::too_many_arguments)] 18 | pub fn new( 19 | pixels: &'buffer [u8], 20 | stride: i32, 21 | width: u32, 22 | height: u32, 23 | hotspot_x: i32, 24 | hotspot_y: i32, 25 | scale: f32, 26 | delay: u32 27 | ) -> Image<'buffer> { 28 | Image { 29 | pixels, 30 | stride, 31 | width, 32 | height, 33 | hotspot_x, 34 | hotspot_y, 35 | scale, 36 | delay 37 | } 38 | } 39 | } 40 | 41 | impl<'buffer> From> for Image<'buffer> { 42 | fn from(image: xcursor::Image<'buffer>) -> Self { 43 | let xcursor::Image { 44 | buffer, 45 | width, 46 | height, 47 | hotspot_x, 48 | hotspot_y, 49 | delay, 50 | .. 51 | } = image; 52 | Image { 53 | pixels: buffer, 54 | width, 55 | height, 56 | stride: width as i32 * 4, 57 | scale: 1.0, 58 | hotspot_x: hotspot_x as _, 59 | hotspot_y: hotspot_y as _, 60 | delay 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/render/matrix.rs: -------------------------------------------------------------------------------- 1 | //! Matrix math is used to render things on a computer screen. This is common 2 | //! throughout computer graphics, for examples and primers on using matrix 3 | //! math to render things to screens please read an OpengGL tutorial. 4 | //! 5 | //! In wlroots we primarily use a 3x3 matrix of 32 bit floating point values to 6 | //! represent a 2D screen. We also provide basic helper functions to assist in 7 | //! transforming the matrices. 8 | 9 | use wlroots_sys::{ 10 | wl_output_transform, wlr_matrix_multiply, wlr_matrix_project_box, wlr_matrix_projection, 11 | wlr_matrix_rotate, wlr_matrix_scale, wlr_matrix_transform, wlr_matrix_translate, wlr_matrix_transpose 12 | }; 13 | 14 | use crate::area::Area; 15 | 16 | pub const IDENTITY: [f32; 9] = [1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0]; 17 | 18 | /// Shortcut for the various matrix operations involved in projecting the 19 | /// specified wlr_box onto a given orthographic projection with a given 20 | /// rotation. The result can be applied to each coordinate of the box to 21 | /// get a new coordinate from [-1,1]. 22 | pub fn project_box( 23 | area: Area, 24 | transform: wl_output_transform, 25 | rotation: f32, 26 | projection: [f32; 9] 27 | ) -> [f32; 9] { 28 | unsafe { 29 | let mut output = [0.0; 9]; 30 | wlr_matrix_project_box( 31 | output.as_mut_ptr(), 32 | &area.into(), 33 | transform, 34 | rotation, 35 | projection.as_ptr() 36 | ); 37 | output 38 | } 39 | } 40 | 41 | /// Translate the 2D matrix to a magnitude of (x, y). 42 | pub fn translate(x: f32, y: f32) -> [f32; 9] { 43 | let mut output = [0.0; 9]; 44 | unsafe { 45 | wlr_matrix_translate(output.as_mut_ptr(), x, y); 46 | } 47 | output 48 | } 49 | 50 | /// Scales the 2D matrix to a magnitude of (x, y). 51 | pub fn scale(x: f32, y: f32) -> [f32; 9] { 52 | let mut output = [0.0; 9]; 53 | unsafe { 54 | wlr_matrix_scale(output.as_mut_ptr(), x, y); 55 | } 56 | output 57 | } 58 | 59 | /// Rotate the matrix by some amount of radians. 60 | pub fn rotate(mut matrix: [f32; 9], radians: f32) -> [f32; 9] { 61 | unsafe { 62 | wlr_matrix_rotate(matrix.as_mut_ptr(), radians); 63 | } 64 | matrix 65 | } 66 | 67 | /// Multiply two matrices together. 68 | pub fn multiply(x: [f32; 9], y: [f32; 9]) -> [f32; 9] { 69 | let mut output = [0.0; 9]; 70 | unsafe { 71 | wlr_matrix_multiply(output.as_mut_ptr(), x.as_ptr(), y.as_ptr()); 72 | } 73 | output 74 | } 75 | 76 | /// Transform the matrix based on the given Wayland output transform mode. 77 | pub fn transform(mut matrix: [f32; 9], transform: wl_output_transform) -> [f32; 9] { 78 | unsafe { 79 | wlr_matrix_transform(matrix.as_mut_ptr(), transform); 80 | } 81 | matrix 82 | } 83 | 84 | /// Create a 2D orthographic projection matrix of (width, height) with a 85 | /// specified `wl_output_transform` 86 | pub fn projection(mut matrix: [f32; 9], width: i32, height: i32, transform: wl_output_transform) -> [f32; 9] { 87 | unsafe { 88 | wlr_matrix_projection(matrix.as_mut_ptr(), width, height, transform); 89 | } 90 | matrix 91 | } 92 | 93 | /// Flip the values over the diagonal of a matrix 94 | pub fn transpose(matrix: [f32; 9]) -> [f32; 9] { 95 | let mut result = [0.0; 9]; 96 | unsafe { 97 | wlr_matrix_transpose(result.as_mut_ptr(), matrix.as_ptr()); 98 | } 99 | result 100 | } 101 | -------------------------------------------------------------------------------- /src/render/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "unstable")] 2 | mod image; 3 | #[cfg(feature = "unstable")] 4 | pub mod matrix; 5 | #[cfg(feature = "unstable")] 6 | mod pixman_region; 7 | #[cfg(feature = "unstable")] 8 | mod renderer; 9 | #[cfg(feature = "unstable")] 10 | mod texture; 11 | 12 | #[cfg(feature = "unstable")] 13 | pub use self::image::*; 14 | #[cfg(feature = "unstable")] 15 | pub use self::pixman_region::*; 16 | #[cfg(feature = "unstable")] 17 | pub use self::renderer::*; 18 | #[cfg(feature = "unstable")] 19 | pub use self::texture::*; 20 | -------------------------------------------------------------------------------- /src/render/pixman_region.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | 3 | use crate::libc::{c_int, c_uint}; 4 | use wlroots_sys::{ 5 | pixman_region32_fini, pixman_region32_init, pixman_region32_t, pixman_region32_union_rect 6 | }; 7 | 8 | /// A pixman region, used for damage tracking. 9 | #[derive(Debug, Default)] 10 | pub struct PixmanRegion { 11 | pub region: pixman_region32_t 12 | } 13 | 14 | impl PixmanRegion { 15 | /// Make a new pixman region. 16 | pub fn new() -> Self { 17 | unsafe { 18 | // NOTE Rational for uninitialized memory: 19 | // We are automatically filling it in with pixman_region32_init. 20 | let mut region = mem::uninitialized(); 21 | pixman_region32_init(&mut region); 22 | PixmanRegion { region } 23 | } 24 | } 25 | 26 | pub fn rectangle(&mut self, x: c_int, y: c_int, width: c_uint, height: c_uint) { 27 | unsafe { 28 | let region_ptr = &mut self.region as *mut _; 29 | pixman_region32_union_rect(region_ptr, region_ptr, x, y, width, height); 30 | } 31 | } 32 | } 33 | 34 | impl Drop for PixmanRegion { 35 | fn drop(&mut self) { 36 | unsafe { pixman_region32_fini(&mut self.region) } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/render/texture.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use crate::libc::c_int; 4 | use wlroots_sys::{wl_shm_format, wlr_texture, wlr_texture_get_size}; 5 | 6 | /// Wrapper around wl_shm_format, to make it easier and nicer to type. 7 | #[repr(u32)] 8 | pub enum TextureFormat { 9 | ARGB8888 = wl_shm_format::WL_SHM_FORMAT_ARGB8888 as u32, 10 | XRGB8888 = wl_shm_format::WL_SHM_FORMAT_XRGB8888 as u32, 11 | C8 = wl_shm_format::WL_SHM_FORMAT_C8 as u32, 12 | RGB332 = wl_shm_format::WL_SHM_FORMAT_RGB332 as u32, 13 | BGR233 = wl_shm_format::WL_SHM_FORMAT_BGR233 as u32, 14 | XRGB4444 = wl_shm_format::WL_SHM_FORMAT_XRGB4444 as u32, 15 | XBGR4444 = wl_shm_format::WL_SHM_FORMAT_XBGR4444 as u32, 16 | RGBX4444 = wl_shm_format::WL_SHM_FORMAT_RGBX4444 as u32, 17 | BGRX4444 = wl_shm_format::WL_SHM_FORMAT_BGRX4444 as u32, 18 | ARGB4444 = wl_shm_format::WL_SHM_FORMAT_ARGB4444 as u32, 19 | ABGR4444 = wl_shm_format::WL_SHM_FORMAT_ABGR4444 as u32, 20 | RGBA4444 = wl_shm_format::WL_SHM_FORMAT_RGBA4444 as u32, 21 | BGRA4444 = wl_shm_format::WL_SHM_FORMAT_BGRA4444 as u32, 22 | XRGB1555 = wl_shm_format::WL_SHM_FORMAT_XRGB1555 as u32, 23 | XBGR1555 = wl_shm_format::WL_SHM_FORMAT_XBGR1555 as u32, 24 | RGBX5551 = wl_shm_format::WL_SHM_FORMAT_RGBX5551 as u32, 25 | BGRX5551 = wl_shm_format::WL_SHM_FORMAT_BGRX5551 as u32, 26 | ARGB1555 = wl_shm_format::WL_SHM_FORMAT_ARGB1555 as u32, 27 | ABGR1555 = wl_shm_format::WL_SHM_FORMAT_ABGR1555 as u32, 28 | RGBA5551 = wl_shm_format::WL_SHM_FORMAT_RGBA5551 as u32, 29 | BGRA5551 = wl_shm_format::WL_SHM_FORMAT_BGRA5551 as u32, 30 | RGB565 = wl_shm_format::WL_SHM_FORMAT_RGB565 as u32, 31 | BGR565 = wl_shm_format::WL_SHM_FORMAT_BGR565 as u32, 32 | RGB888 = wl_shm_format::WL_SHM_FORMAT_RGB888 as u32, 33 | BGR888 = wl_shm_format::WL_SHM_FORMAT_BGR888 as u32, 34 | XBGR8888 = wl_shm_format::WL_SHM_FORMAT_XBGR8888 as u32, 35 | RGBX8888 = wl_shm_format::WL_SHM_FORMAT_RGBX8888 as u32, 36 | BGRX8888 = wl_shm_format::WL_SHM_FORMAT_BGRX8888 as u32, 37 | ABGR8888 = wl_shm_format::WL_SHM_FORMAT_ABGR8888 as u32, 38 | RGBA8888 = wl_shm_format::WL_SHM_FORMAT_RGBA8888 as u32, 39 | BGRA8888 = wl_shm_format::WL_SHM_FORMAT_BGRA8888 as u32, 40 | XRGB2101010 = wl_shm_format::WL_SHM_FORMAT_XRGB2101010 as u32, 41 | XBGR2101010 = wl_shm_format::WL_SHM_FORMAT_XBGR2101010 as u32, 42 | RGBX1010102 = wl_shm_format::WL_SHM_FORMAT_RGBX1010102 as u32, 43 | BGRX1010102 = wl_shm_format::WL_SHM_FORMAT_BGRX1010102 as u32, 44 | ARGB2101010 = wl_shm_format::WL_SHM_FORMAT_ARGB2101010 as u32, 45 | ABGR2101010 = wl_shm_format::WL_SHM_FORMAT_ABGR2101010 as u32, 46 | RGBA1010102 = wl_shm_format::WL_SHM_FORMAT_RGBA1010102 as u32, 47 | BGRA1010102 = wl_shm_format::WL_SHM_FORMAT_BGRA1010102 as u32, 48 | YUYV = wl_shm_format::WL_SHM_FORMAT_YUYV as u32, 49 | YVYU = wl_shm_format::WL_SHM_FORMAT_YVYU as u32, 50 | UYVY = wl_shm_format::WL_SHM_FORMAT_UYVY as u32, 51 | VYUY = wl_shm_format::WL_SHM_FORMAT_VYUY as u32, 52 | AYUV = wl_shm_format::WL_SHM_FORMAT_AYUV as u32, 53 | NV12 = wl_shm_format::WL_SHM_FORMAT_NV12 as u32, 54 | NV21 = wl_shm_format::WL_SHM_FORMAT_NV21 as u32, 55 | NV16 = wl_shm_format::WL_SHM_FORMAT_NV16 as u32, 56 | NV61 = wl_shm_format::WL_SHM_FORMAT_NV61 as u32, 57 | YUV410 = wl_shm_format::WL_SHM_FORMAT_YUV410 as u32, 58 | YVU410 = wl_shm_format::WL_SHM_FORMAT_YVU410 as u32, 59 | YUV411 = wl_shm_format::WL_SHM_FORMAT_YUV411 as u32, 60 | YVU411 = wl_shm_format::WL_SHM_FORMAT_YVU411 as u32, 61 | YUV420 = wl_shm_format::WL_SHM_FORMAT_YUV420 as u32, 62 | YVU420 = wl_shm_format::WL_SHM_FORMAT_YVU420 as u32, 63 | YUV422 = wl_shm_format::WL_SHM_FORMAT_YUV422 as u32, 64 | YVU422 = wl_shm_format::WL_SHM_FORMAT_YVU422 as u32, 65 | YUV444 = wl_shm_format::WL_SHM_FORMAT_YUV444 as u32, 66 | YVU444 = wl_shm_format::WL_SHM_FORMAT_YVU444 as u32 67 | } 68 | 69 | impl Into for TextureFormat { 70 | fn into(self) -> wl_shm_format { 71 | // NOTE Rationale for transmute: 72 | // * Easiest way to convert to the value type 73 | // * Is safe because of the definitions above linking them together. 74 | unsafe { ::std::mem::transmute(self as u32) } 75 | } 76 | } 77 | 78 | #[derive(Debug, Eq, PartialEq, Hash)] 79 | /// A wrapper for a wlr_texture. 80 | /// 81 | /// For textures created from `GenericRenderer::create_texture_from_pixels`, the 82 | /// lifetime will be `'static` because the memory will be owned by the user. 83 | pub struct Texture<'surface> { 84 | texture: *mut wlr_texture, 85 | phantom: PhantomData<&'surface ()> 86 | } 87 | 88 | impl<'surface> Texture<'surface> { 89 | pub(crate) unsafe fn from_ptr<'unbound>(texture: *mut wlr_texture) -> Texture<'unbound> { 90 | Texture { 91 | texture, 92 | phantom: PhantomData 93 | } 94 | } 95 | 96 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_texture { 97 | self.texture 98 | } 99 | 100 | /// Gets the size of the texture. 101 | /// 102 | /// Return value is in (width, height) format. 103 | pub fn size(&self) -> (c_int, c_int) { 104 | unsafe { 105 | let (mut width, mut height) = (0, 0); 106 | wlr_texture_get_size(self.texture, &mut width, &mut height); 107 | (width, height) 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/types/area.rs: -------------------------------------------------------------------------------- 1 | //! Wrapper for the `wlr_box` type. 2 | //! Note that we renamed it to `Area` to avoid conflicts with Rust's Box. 3 | 4 | use crate::libc::{c_double, c_float, c_int}; 5 | 6 | use wlroots_sys::{ 7 | wl_output_transform, wlr_box, wlr_box_closest_point, wlr_box_contains_point, wlr_box_empty, 8 | wlr_box_intersection, wlr_box_rotated_bounds, wlr_box_transform 9 | }; 10 | 11 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 12 | /// Result of applying an intersection of two `Area`s. 13 | pub enum IntersectionResult { 14 | /// This area is the intersection between the two points. 15 | Intersection(Area), 16 | /// There was not an intersection 17 | NoIntersection 18 | } 19 | 20 | #[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] 21 | pub struct Origin { 22 | pub x: c_int, 23 | pub y: c_int 24 | } 25 | 26 | impl Origin { 27 | pub fn new(x: c_int, y: c_int) -> Self { 28 | Origin { x, y } 29 | } 30 | } 31 | 32 | impl Into for Origin { 33 | fn into(self) -> Area { 34 | Area::new(self, Size::default()) 35 | } 36 | } 37 | 38 | #[derive(Default, Debug, Clone, Copy, Eq, PartialEq)] 39 | pub struct Size { 40 | pub width: c_int, 41 | pub height: c_int 42 | } 43 | 44 | impl Size { 45 | pub fn new(width: c_int, height: c_int) -> Self { 46 | Size { width, height } 47 | } 48 | } 49 | 50 | impl Into for Size { 51 | fn into(self) -> Area { 52 | Area::new(Origin::default(), self) 53 | } 54 | } 55 | 56 | #[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] 57 | /// Generic geometry-like struct. Container an origin (x, y) point and bounds 58 | /// (width, height). 59 | pub struct Area { 60 | pub origin: Origin, 61 | pub size: Size 62 | } 63 | 64 | impl Into for Area { 65 | fn into(self) -> wlr_box { 66 | wlr_box { 67 | x: self.origin.x, 68 | y: self.origin.y, 69 | width: self.size.width, 70 | height: self.size.height 71 | } 72 | } 73 | } 74 | 75 | impl Area { 76 | pub fn new(origin: Origin, size: Size) -> Self { 77 | Area { origin, size } 78 | } 79 | 80 | /// Construct an Area from a `wlr_box`. 81 | pub fn from_box(wlr_box: wlr_box) -> Self { 82 | Area { 83 | origin: Origin { 84 | x: wlr_box.x, 85 | y: wlr_box.y 86 | }, 87 | size: Size { 88 | width: wlr_box.width, 89 | height: wlr_box.height 90 | } 91 | } 92 | } 93 | 94 | /// Makes a new `Area` with width and height set to the values in the given 95 | /// `Size`. 96 | pub fn with_size(self, size: Size) -> Self { 97 | Area { size, ..self } 98 | } 99 | 100 | /// Makes a new `Area` with x and y set to the value in the given `Origin`. 101 | pub fn with_origin(self, origin: Origin) -> Self { 102 | Area { origin, ..self } 103 | } 104 | 105 | /// Finds the closest point within the box to the given point. 106 | /// If the (x, y) point lies outside of the box, then it finds the closest 107 | /// corner and returns that. 108 | /// 109 | /// Returned value is in form of (x, y). 110 | pub fn closest_point(self, x: c_double, y: c_double) -> (c_double, c_double) { 111 | unsafe { 112 | let (mut dest_x, mut dest_y) = (0.0, 0.0); 113 | wlr_box_closest_point(&self.into(), x, y, &mut dest_x, &mut dest_y); 114 | (dest_x, dest_y) 115 | } 116 | } 117 | 118 | /// Gets the intersection of the two areas. 119 | pub fn intersection(self, other_box: Area) -> IntersectionResult { 120 | unsafe { 121 | let res = Area::default(); 122 | let is_empty = wlr_box_intersection(&mut res.into(), &self.into(), &other_box.into()); 123 | if is_empty { 124 | IntersectionResult::NoIntersection 125 | } else { 126 | IntersectionResult::Intersection(res) 127 | } 128 | } 129 | } 130 | 131 | /// Determines if the box contains the given point. 132 | pub fn contains_point(self, x: c_double, y: c_double) -> bool { 133 | unsafe { wlr_box_contains_point(&self.into(), x, y) } 134 | } 135 | 136 | /// Determines if the box is empty (e.g if the bounds give it an area of 0). 137 | pub fn is_empty(self) -> bool { 138 | unsafe { wlr_box_empty(&self.into()) } 139 | } 140 | 141 | /// Transforms the box coordinates and bounds according to the 142 | /// output transformation. 143 | /// 144 | /// e.g: If it's `WL_OUTPUT_TRANSFORM_90` then it will flip the Area 90° 145 | /// clockwise. 146 | pub fn transform(self, transform: wl_output_transform, width: c_int, height: c_int) -> Area { 147 | unsafe { 148 | let res = Area::default(); 149 | wlr_box_transform(&mut res.into(), &self.into(), transform, width, height); 150 | res 151 | } 152 | } 153 | 154 | /// Creates the smallest box that contains the box rotated about its center. 155 | pub fn rotated_bounds(self, rotation: c_float) -> Area { 156 | unsafe { 157 | let dest = Area::default(); 158 | wlr_box_rotated_bounds(&mut dest.into(), &self.into(), rotation); 159 | dest 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/types/cursor/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "unstable")] 2 | #[allow(clippy::module_inception)] 3 | mod cursor; 4 | pub mod xcursor; 5 | #[cfg(feature = "unstable")] 6 | pub(crate) mod xcursor_manager; 7 | 8 | #[cfg(feature = "unstable")] 9 | pub use self::cursor::*; 10 | -------------------------------------------------------------------------------- /src/types/cursor/xcursor_manager.rs: -------------------------------------------------------------------------------- 1 | use std::{marker::PhantomData, ptr}; 2 | 3 | use wlroots_sys::{ 4 | wlr_xcursor_manager, wlr_xcursor_manager_create, wlr_xcursor_manager_destroy, 5 | wlr_xcursor_manager_get_xcursor, wlr_xcursor_manager_load, wlr_xcursor_manager_set_cursor_image, 6 | wlr_xcursor_manager_theme 7 | }; 8 | 9 | use crate::{ 10 | cursor::{ 11 | xcursor::{self, XCursor}, 12 | Cursor 13 | }, 14 | utils::{c_to_rust_string, safe_as_cstring} 15 | }; 16 | 17 | /// An `xcursor::Theme` at a particular scale factor of the base size. 18 | #[derive(Debug)] 19 | pub struct ManagerTheme<'manager> { 20 | theme: *mut wlr_xcursor_manager_theme, 21 | phantom: PhantomData<&'manager Manager> 22 | } 23 | 24 | /// xcursor::Manager dynamically loads xcursor themes at sizes necessary for use 25 | /// on outputs at arbitrary scale factors. You should call `load` for each 26 | /// output you will show your cursor on, with the scale factor parameter set to 27 | /// that output's scale factor. 28 | #[derive(Debug)] 29 | pub struct Manager { 30 | manager: *mut wlr_xcursor_manager 31 | } 32 | 33 | impl<'manager> ManagerTheme<'manager> { 34 | fn new(theme: *mut wlr_xcursor_manager_theme) -> Self { 35 | ManagerTheme { 36 | theme, 37 | phantom: PhantomData 38 | } 39 | } 40 | 41 | /// Get the scale factor of the theme. 42 | pub fn scale(&self) -> f32 { 43 | unsafe { (*self.theme).scale } 44 | } 45 | 46 | /// Get the underlying `xcursor::Theme` for this managed theme. 47 | pub fn theme(self) -> xcursor::Theme { 48 | unsafe { xcursor::Theme::from_ptr((*self.theme).theme) } 49 | } 50 | } 51 | 52 | impl Manager { 53 | /// Create a new `xcursor::Manager`. 54 | pub fn create>>(name: T, size: u32) -> Option { 55 | unsafe { 56 | let name_str = name.into().map(safe_as_cstring); 57 | let name_ptr = name_str.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()); 58 | let manager = wlr_xcursor_manager_create(name_ptr, size); 59 | if manager.is_null() { 60 | None 61 | } else { 62 | Some(Manager { manager }) 63 | } 64 | } 65 | } 66 | 67 | /// Get the name of the theme this `Manager` manages. 68 | pub fn name(&self) -> String { 69 | unsafe { c_to_rust_string((*self.manager).name).expect("Could not parse make as UTF-8") } 70 | } 71 | 72 | /// Get the base size (when scale = 1) in pixels for the theme. 73 | pub fn size(&self) -> u32 { 74 | unsafe { (*self.manager).size } 75 | } 76 | 77 | /// Retrieves a `XCursor` for the given cursor name at the given scale 78 | /// factor, or None if this `Manager` has not loaded a cursor theme at 79 | /// the requested scale. 80 | pub fn get_xcursor>>(&self, name: T, scale: f32) -> Option { 81 | let name_str = name.into().map(safe_as_cstring); 82 | let name_ptr = name_str.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()); 83 | unsafe { 84 | let xcursor = wlr_xcursor_manager_get_xcursor(self.manager, name_ptr, scale); 85 | if xcursor.is_null() { 86 | None 87 | } else { 88 | Some(XCursor::from_ptr(xcursor)) 89 | } 90 | } 91 | } 92 | 93 | /// Get a list of all the scaled `xcursor::ManagerTheme`s managed by this 94 | /// manager. 95 | pub fn scaled_themes<'manager>(&'manager self) -> Vec> { 96 | unsafe { 97 | let mut result = vec![]; 98 | 99 | wl_list_for_each!((*self.manager).scaled_themes, 100 | link, 101 | (theme: wlr_xcursor_manager_theme) => { 102 | result.push(ManagerTheme::new(theme)) 103 | }); 104 | 105 | result 106 | } 107 | } 108 | 109 | /// Ensures an xcursor theme at the given scale factor is loaded in the 110 | /// manager. 111 | /// 112 | /// Returns false if the scaled theme was successfully loaded and true 113 | /// otherwise 114 | pub fn load(&self, scale: f32) -> bool { 115 | unsafe { 116 | match wlr_xcursor_manager_load(self.manager, scale) { 117 | 0 => false, 118 | _ => true 119 | } 120 | } 121 | } 122 | 123 | /// Set a `Cursor`'s cursor image to the specified cursor name for all scale 124 | /// factors. The `Cursor` will take over from this point and ensure the 125 | /// correct cursor is used on each output, assuming an `OutputLayout` is 126 | /// attached to it. 127 | pub fn set_cursor_image(&mut self, name: String, cursor: &Cursor) { 128 | let name_str = safe_as_cstring(name); 129 | unsafe { 130 | wlr_xcursor_manager_set_cursor_image(self.manager, name_str.as_ptr(), cursor.as_ptr()); 131 | } 132 | } 133 | } 134 | 135 | impl Drop for Manager { 136 | fn drop(&mut self) { 137 | unsafe { wlr_xcursor_manager_destroy(self.manager) } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/types/data_device/data_source.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use std::marker::PhantomData; 4 | 5 | use wlroots_sys::{wl_data_device_manager_dnd_action, wlr_data_offer, wlr_data_source}; 6 | 7 | /// An offering of data 8 | #[derive(Debug)] 9 | pub struct Offer<'source> { 10 | offer: *mut wlr_data_offer, 11 | phantom: PhantomData<&'source Source> 12 | } 13 | 14 | impl<'source> Offer<'source> { 15 | pub fn actions(&self) -> u32 { 16 | unsafe { (*self.offer).actions } 17 | } 18 | 19 | pub fn preferred_action(&self) -> wl_data_device_manager_dnd_action { 20 | unsafe { (*self.offer).preferred_action } 21 | } 22 | 23 | pub fn in_ask(&self) -> bool { 24 | unsafe { (*self.offer).in_ask } 25 | } 26 | } 27 | 28 | #[derive(Debug)] 29 | pub struct Source { 30 | source: *mut wlr_data_source 31 | } 32 | 33 | // TODO Be able to set the function pointers? 34 | 35 | impl Source { 36 | // TODO Mime types 37 | 38 | pub fn action(&self) -> i32 { 39 | unsafe { (*self.source).actions } 40 | } 41 | 42 | pub fn accepted(&self) -> bool { 43 | unsafe { (*self.source).accepted } 44 | } 45 | 46 | // TODO Seat client 47 | 48 | pub fn current_dnd_action(&self) -> wl_data_device_manager_dnd_action { 49 | unsafe { (*self.source).current_dnd_action } 50 | } 51 | 52 | pub fn compositor_action(&self) -> u32 { 53 | unsafe { (*self.source).compositor_action } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/types/data_device/manager.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use wlroots_sys::{ 4 | wl_display, wlr_data_device_manager, wlr_data_device_manager_create, wlr_data_device_manager_destroy 5 | }; 6 | 7 | /// Global for the data device manager global for a certain display. 8 | #[derive(Debug)] 9 | pub struct Manager { 10 | manager: *mut wlr_data_device_manager 11 | } 12 | 13 | impl Manager { 14 | /// Create a wl data device manager global for this display. 15 | pub(crate) unsafe fn new(display: *mut wl_display) -> Option { 16 | let manager = wlr_data_device_manager_create(display); 17 | if manager.is_null() { 18 | None 19 | } else { 20 | Some(Manager { manager }) 21 | } 22 | } 23 | } 24 | 25 | impl Drop for Manager { 26 | fn drop(&mut self) { 27 | unsafe { wlr_data_device_manager_destroy(self.manager) } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/types/data_device/mod.rs: -------------------------------------------------------------------------------- 1 | mod data_source; 2 | mod manager; 3 | 4 | pub use self::data_source::*; 5 | pub use self::manager::*; 6 | -------------------------------------------------------------------------------- /src/types/dmabuf.rs: -------------------------------------------------------------------------------- 1 | //! Support for the DMABuf type 2 | 3 | use wlroots_sys::{wl_display, wlr_linux_dmabuf_v1, wlr_linux_dmabuf_v1_create, 4 | wlr_linux_dmabuf_v1_destroy}; 5 | use {crate::compositor::Compositor, 6 | crate::render::GenericRenderer}; 7 | 8 | 9 | #[derive(Debug)] 10 | pub struct Dmabuf { 11 | dmabuf: *mut wlr_linux_dmabuf_v1 12 | } 13 | 14 | impl Dmabuf { 15 | pub fn new(compositor: &Compositor) -> Option { 16 | unsafe { 17 | // Get the renderer from compositor 18 | let renderer: Option<&GenericRenderer> = compositor.renderer.as_ref(); 19 | match renderer { 20 | Some(ref renderer) => { 21 | let dmabuf_raw = wlr_linux_dmabuf_v1_create(compositor.display as *mut wl_display, renderer.as_ptr()); 22 | if !dmabuf_raw.is_null() { 23 | Some(Dmabuf { dmabuf: dmabuf_raw }) 24 | } else { 25 | None 26 | } 27 | } 28 | None => None 29 | } 30 | } 31 | } 32 | } 33 | 34 | impl Drop for Dmabuf { 35 | fn drop(&mut self) { 36 | unsafe { wlr_linux_dmabuf_v1_destroy(self.dmabuf) } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/types/input/input_device.rs: -------------------------------------------------------------------------------- 1 | use std::{cell::Cell, ptr::NonNull, rc::Weak}; 2 | 3 | use crate::libc::{c_double, c_uint}; 4 | use wlroots_sys::{ 5 | wlr_input_device, wlr_input_device_pointer, wlr_input_device_type, wlr_input_device_type::* 6 | }; 7 | 8 | pub(crate) use crate::manager::input_manager::Manager; 9 | use crate::{ 10 | input::{keyboard, pointer, switch, tablet_pad, tablet_tool, touch}, 11 | utils::c_to_rust_string 12 | }; 13 | 14 | /// A handle to an input device. 15 | pub enum Handle { 16 | Keyboard(keyboard::Handle), 17 | Pointer(pointer::Handle), 18 | Touch(touch::Handle), 19 | TabletPad(tablet_pad::Handle), 20 | TabletTool(tablet_tool::Handle), 21 | Switch(switch::Handle) 22 | } 23 | 24 | pub(crate) struct InputState { 25 | pub(crate) handle: Weak>, 26 | pub(crate) device: Device 27 | } 28 | 29 | /// Wrapper for wlr_input_device 30 | #[derive(Debug, Eq, PartialEq, Hash, Ord, PartialOrd)] 31 | pub struct Device { 32 | pub(crate) device: NonNull 33 | } 34 | 35 | impl Device { 36 | /// Just like `std::clone::Clone`, but unsafe. 37 | /// 38 | /// # Unsafety 39 | /// This is unsafe because the user should not be able to clone 40 | /// this type out because it isn't bound by anything but the underlying 41 | /// pointer could be removed at any time. 42 | /// 43 | /// This isn't exposed to the user, but still marked as `unsafe` to reduce 44 | /// possible bugs from using this. 45 | pub(crate) unsafe fn clone(&self) -> Self { 46 | Device { device: self.device } 47 | } 48 | 49 | pub fn vendor(&self) -> c_uint { 50 | unsafe { self.device.as_ref().vendor } 51 | } 52 | 53 | pub fn product(&self) -> c_uint { 54 | unsafe { self.device.as_ref().product } 55 | } 56 | 57 | pub fn name(&self) -> Option { 58 | unsafe { c_to_rust_string(self.device.as_ref().name) } 59 | } 60 | 61 | pub fn output_name(&self) -> Option { 62 | unsafe { c_to_rust_string(self.device.as_ref().output_name) } 63 | } 64 | 65 | /// Get the size in (width_mm, height_mm) format. 66 | /// 67 | /// These values will be 0 if it's not supported. 68 | pub fn size(&self) -> (c_double, c_double) { 69 | unsafe { (self.device.as_ref().width_mm, self.device.as_ref().height_mm) } 70 | } 71 | 72 | /// Get the type of the device 73 | pub fn dev_type(&self) -> wlr_input_device_type { 74 | unsafe { self.device.as_ref().type_ } 75 | } 76 | 77 | /// Get a handle to the backing input device. 78 | pub fn device(&self) -> Handle { 79 | unsafe { 80 | match self.dev_type() { 81 | WLR_INPUT_DEVICE_KEYBOARD => { 82 | let keyboard_ptr = self.device.as_ref().__bindgen_anon_1.keyboard; 83 | Handle::Keyboard(keyboard::Handle::from_ptr(keyboard_ptr)) 84 | }, 85 | WLR_INPUT_DEVICE_POINTER => { 86 | let pointer_ptr = self.device.as_ref().__bindgen_anon_1.pointer; 87 | Handle::Pointer(pointer::Handle::from_ptr(pointer_ptr)) 88 | }, 89 | WLR_INPUT_DEVICE_TOUCH => { 90 | let touch_ptr = self.device.as_ref().__bindgen_anon_1.touch; 91 | Handle::Touch(touch::Handle::from_ptr(touch_ptr)) 92 | }, 93 | WLR_INPUT_DEVICE_TABLET_TOOL => { 94 | let tablet_tool_ptr = self.device.as_ref().__bindgen_anon_1.tablet; 95 | Handle::TabletTool(tablet_tool::Handle::from_ptr(tablet_tool_ptr)) 96 | }, 97 | WLR_INPUT_DEVICE_TABLET_PAD => { 98 | let tablet_pad_ptr = self.device.as_ref().__bindgen_anon_1.tablet_pad; 99 | Handle::TabletPad(tablet_pad::Handle::from_ptr(tablet_pad_ptr)) 100 | }, 101 | WLR_INPUT_DEVICE_SWITCH => { 102 | let switch_ptr = self.device.as_ref().__bindgen_anon_1.lid_switch; 103 | Handle::Switch(switch::Handle::from_ptr(switch_ptr)) 104 | } 105 | } 106 | } 107 | } 108 | 109 | pub(crate) unsafe fn dev_union(&self) -> wlr_input_device_pointer { 110 | self.device.as_ref().__bindgen_anon_1 111 | } 112 | 113 | pub(crate) unsafe fn from_ptr(device: *mut wlr_input_device) -> Self { 114 | let device = NonNull::new(device).expect("Device was null"); 115 | Device { device } 116 | } 117 | 118 | pub(crate) unsafe fn as_non_null(&self) -> NonNull { 119 | self.device 120 | } 121 | 122 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_input_device { 123 | self.device.as_ptr() 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/types/input/mod.rs: -------------------------------------------------------------------------------- 1 | mod input_device; 2 | pub mod keyboard; 3 | pub mod pointer; 4 | pub mod switch; 5 | pub mod tablet_pad; 6 | pub mod tablet_tool; 7 | pub mod touch; 8 | 9 | pub use self::input_device::*; 10 | 11 | pub mod manager { 12 | //! Input resources are managed by the input resource manager. 13 | //! 14 | //! To manage a particular type of input resource implement a function 15 | //! with the signature of its corresponding name. For example, to manage 16 | //! keyboards implement [`KeyboardAdded`](./type.KeyboardAdded.html). 17 | //! 18 | //! Pass those functions to an [`input::Builder`](./struct.Builder.html) 19 | //! which is then given to a `compositor::Builder`. 20 | pub use crate::manager::input_manager::*; 21 | } 22 | -------------------------------------------------------------------------------- /src/types/input/pointer.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use std::{cell::Cell, ptr::NonNull, rc::Rc}; 4 | 5 | use wlroots_sys::{wlr_input_device, wlr_pointer}; 6 | 7 | pub use crate::events::pointer_events as event; 8 | pub use crate::manager::pointer_handler::*; 9 | use crate::{ 10 | input::{self, InputState}, 11 | utils::{self, HandleErr, HandleResult, Handleable} 12 | }; 13 | 14 | pub type Handle = utils::Handle, wlr_pointer, Pointer>; 15 | 16 | #[derive(Debug)] 17 | pub struct Pointer { 18 | /// The structure that ensures weak handles to this structure are still 19 | /// alive. 20 | /// 21 | /// They contain weak handles, and will safely not use dead memory when this 22 | /// is freed by wlroots. 23 | /// 24 | /// If this is `None`, then this is from an upgraded `pointer::Handle`, and 25 | /// the operations are **unchecked**. 26 | /// This is means safe operations might fail, but only if you use the unsafe 27 | /// marked function `upgrade` on a `pointer::Handle`. 28 | liveliness: Rc>, 29 | /// The device that refers to this pointer. 30 | device: input::Device, 31 | /// The underlying pointer data. 32 | pointer: NonNull 33 | } 34 | 35 | impl Pointer { 36 | /// Tries to convert an input device to a Pointer 37 | /// 38 | /// Returns none if it is of a different input variant. 39 | /// 40 | /// # Safety 41 | /// This creates a totally new Pointer (e.g with its own reference count) 42 | /// so only do this once per `wlr_input_device`! 43 | pub(crate) unsafe fn new_from_input_device(device: *mut wlr_input_device) -> Option { 44 | use wlroots_sys::wlr_input_device_type::*; 45 | match (*device).type_ { 46 | WLR_INPUT_DEVICE_POINTER => { 47 | let pointer = NonNull::new((*device).__bindgen_anon_1.pointer).expect( 48 | "Pointer pointer was \ 49 | null" 50 | ); 51 | let liveliness = Rc::new(Cell::new(false)); 52 | let handle = Rc::downgrade(&liveliness); 53 | let state = Box::new(InputState { 54 | handle, 55 | device: input::Device::from_ptr(device) 56 | }); 57 | (*pointer.as_ptr()).data = Box::into_raw(state) as *mut _; 58 | Some(Pointer { 59 | liveliness, 60 | device: input::Device::from_ptr(device), 61 | pointer 62 | }) 63 | }, 64 | _ => None 65 | } 66 | } 67 | 68 | /// Gets the wlr_input_device associated with this Pointer. 69 | pub fn input_device(&self) -> &input::Device { 70 | &self.device 71 | } 72 | 73 | /// Gets the wlr_pointer associated with this Pointer. 74 | #[allow(dead_code)] 75 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_pointer { 76 | self.pointer.as_ptr() 77 | } 78 | } 79 | 80 | impl Drop for Pointer { 81 | fn drop(&mut self) { 82 | if Rc::strong_count(&self.liveliness) == 1 { 83 | wlr_log!(WLR_DEBUG, "Dropped Pointer {:p}", self.pointer); 84 | unsafe { 85 | let _ = Box::from_raw((*self.pointer.as_ptr()).data as *mut InputState); 86 | } 87 | let weak_count = Rc::weak_count(&self.liveliness); 88 | if weak_count > 0 { 89 | wlr_log!( 90 | WLR_DEBUG, 91 | "Still {} weak pointers to Pointer {:p}", 92 | weak_count, 93 | self.pointer 94 | ); 95 | } 96 | } 97 | } 98 | } 99 | 100 | impl Handleable, wlr_pointer> for Pointer { 101 | #[doc(hidden)] 102 | unsafe fn from_ptr(pointer: *mut wlr_pointer) -> Option { 103 | let pointer = NonNull::new(pointer)?; 104 | let data = Box::from_raw((*pointer.as_ptr()).data as *mut InputState); 105 | let handle = data.handle.clone(); 106 | let device = data.device.clone(); 107 | (*pointer.as_ptr()).data = Box::into_raw(data) as *mut _; 108 | Some(Pointer { 109 | liveliness: handle.upgrade().unwrap(), 110 | device, 111 | pointer 112 | }) 113 | } 114 | 115 | #[doc(hidden)] 116 | unsafe fn as_ptr(&self) -> *mut wlr_pointer { 117 | self.pointer.as_ptr() 118 | } 119 | 120 | #[doc(hidden)] 121 | unsafe fn from_handle(handle: &Handle) -> HandleResult { 122 | let liveliness = handle.handle.upgrade().ok_or(HandleErr::AlreadyDropped)?; 123 | let device = handle.data.ok_or(HandleErr::AlreadyDropped)?; 124 | Ok(Pointer { 125 | liveliness, 126 | // NOTE Rationale for cloning: 127 | // If we already dropped we don't reach this point. 128 | device: input::Device { device }, 129 | pointer: handle.as_non_null() 130 | }) 131 | } 132 | 133 | fn weak_reference(&self) -> Handle { 134 | Handle { 135 | ptr: self.pointer, 136 | handle: Rc::downgrade(&self.liveliness), 137 | // NOTE Rationale for cloning: 138 | // Since we have a strong reference already, 139 | // the input must still be alive. 140 | data: unsafe { Some(self.device.as_non_null()) }, 141 | _marker: std::marker::PhantomData 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/types/input/switch.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use std::{cell::Cell, ptr::NonNull, rc::Rc}; 4 | 5 | pub use crate::events::switch_events as event; 6 | pub use crate::manager::switch_handler::*; 7 | use wlroots_sys::{wlr_input_device, wlr_switch}; 8 | use crate::{ 9 | input::{self, InputState}, 10 | utils::{self, HandleErr, HandleResult, Handleable} 11 | }; 12 | 13 | pub type Handle = utils::Handle, wlr_switch, Switch>; 14 | 15 | #[derive(Debug)] 16 | pub struct Switch { 17 | /// The structure that ensures weak handles to this structure are still 18 | /// alive. 19 | /// 20 | /// They contain weak handles, and will safely not use dead memory when this 21 | /// is freed by wlroots. 22 | /// 23 | /// If this is `None`, then this is from an upgraded `pointer::Handle`, and 24 | /// the operations are **unchecked**. 25 | /// This is means safe operations might fail, but only if you use the unsafe 26 | /// marked function `upgrade` on a `pointer::Handle`. 27 | liveliness: Rc>, 28 | /// The device that refers to this pointer. 29 | device: input::Device, 30 | /// The underlying switch data. 31 | switch: NonNull 32 | } 33 | 34 | impl Switch { 35 | /// Tries to convert an input device to a Switch 36 | /// 37 | /// Returns none if it is of a different input variant. 38 | /// 39 | /// # Safety 40 | /// This creates a totally new Switch (e.g with its own reference count) 41 | /// so only do this once per `wlr_input_device`! 42 | pub(crate) unsafe fn new_from_input_device(device: *mut wlr_input_device) -> Option { 43 | use wlroots_sys::wlr_input_device_type::*; 44 | match (*device).type_ { 45 | WLR_INPUT_DEVICE_SWITCH => { 46 | let switch = NonNull::new((*device).__bindgen_anon_1.lid_switch).expect( 47 | "Switch pointer \ 48 | was null" 49 | ); 50 | let liveliness = Rc::new(Cell::new(false)); 51 | let handle = Rc::downgrade(&liveliness); 52 | let state = Box::new(InputState { 53 | handle, 54 | device: input::Device::from_ptr(device) 55 | }); 56 | (*switch.as_ptr()).data = Box::into_raw(state) as *mut _; 57 | Some(Switch { 58 | liveliness, 59 | device: input::Device::from_ptr(device), 60 | switch 61 | }) 62 | }, 63 | _ => None 64 | } 65 | } 66 | 67 | /// Gets the wlr_input_device associated with this switch. 68 | pub fn input_device(&self) -> &input::Device { 69 | &self.device 70 | } 71 | } 72 | 73 | impl Drop for Switch { 74 | fn drop(&mut self) { 75 | if Rc::strong_count(&self.liveliness) == 1 { 76 | wlr_log!(WLR_DEBUG, "Dropped Switch {:p}", self.switch.as_ptr()); 77 | unsafe { 78 | let _ = Box::from_raw((*self.switch.as_ptr()).data as *mut InputState); 79 | } 80 | let weak_count = Rc::weak_count(&self.liveliness); 81 | if weak_count > 0 { 82 | wlr_log!( 83 | WLR_DEBUG, 84 | "Still {} weak pointers to Switch {:p}", 85 | weak_count, 86 | self.switch.as_ptr() 87 | ); 88 | } 89 | } 90 | } 91 | } 92 | 93 | impl Handleable, wlr_switch> for Switch { 94 | #[doc(hidden)] 95 | unsafe fn from_ptr(switch: *mut wlr_switch) -> Option { 96 | let switch = NonNull::new(switch)?; 97 | let data = Box::from_raw((*switch.as_ptr()).data as *mut InputState); 98 | let handle = data.handle.clone(); 99 | let device = data.device.clone(); 100 | (*switch.as_ptr()).data = Box::into_raw(data) as *mut _; 101 | Some(Switch { 102 | liveliness: handle.upgrade().unwrap(), 103 | device, 104 | switch 105 | }) 106 | } 107 | 108 | #[doc(hidden)] 109 | unsafe fn as_ptr(&self) -> *mut wlr_switch { 110 | self.switch.as_ptr() 111 | } 112 | 113 | #[doc(hidden)] 114 | unsafe fn from_handle(handle: &Handle) -> HandleResult { 115 | let liveliness = handle.handle.upgrade().ok_or(HandleErr::AlreadyDropped)?; 116 | let device = handle.data.ok_or(HandleErr::AlreadyDropped)?; 117 | Ok(Switch { 118 | liveliness, 119 | // NOTE Rationale for cloning: 120 | // If we already dropped we don't reach this point. 121 | device: input::Device { device }, 122 | switch: handle.as_non_null() 123 | }) 124 | } 125 | 126 | fn weak_reference(&self) -> Handle { 127 | Handle { 128 | ptr: self.switch, 129 | handle: Rc::downgrade(&self.liveliness), 130 | // NOTE Rationale for cloning: 131 | // Since we have a strong reference already, 132 | // the input must still be alive. 133 | data: unsafe { Some(self.device.as_non_null()) }, 134 | _marker: std::marker::PhantomData 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/types/input/tablet_pad.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | use std::{cell::Cell, ptr::NonNull, rc::Rc}; 3 | 4 | use wlroots_sys::{wlr_input_device, wlr_tablet_pad}; 5 | 6 | pub use crate::events::tablet_pad_events as event; 7 | pub use crate::manager::tablet_pad_handler::*; 8 | use crate::{ 9 | input::{self, InputState}, 10 | utils::{self, HandleErr, HandleResult, Handleable} 11 | }; 12 | 13 | pub type Handle = utils::Handle, wlr_tablet_pad, TabletPad>; 14 | 15 | #[derive(Debug)] 16 | pub struct TabletPad { 17 | /// The structure that ensures weak handles to this structure are still 18 | /// alive. 19 | /// 20 | /// They contain weak handles, and will safely not use dead memory when this 21 | /// is freed by wlroots. 22 | /// 23 | /// If this is `None`, then this is from an upgraded `tablet_pad::Handle`, 24 | /// and the operations are **unchecked**. 25 | /// This is means safe operations might fail, but only if you use the unsafe 26 | /// marked function `upgrade` on a `tablet_pad::Handle`. 27 | liveliness: Rc>, 28 | /// The device that refers to this tablet pad. 29 | device: input::Device, 30 | /// Underlying tablet state 31 | pad: NonNull 32 | } 33 | 34 | impl TabletPad { 35 | /// Tries to convert an input device to a TabletPad 36 | /// 37 | /// Returns None if it is of a different type of input variant. 38 | /// 39 | /// # Safety 40 | /// This creates a totally new TabletPad (e.g with its own reference count) 41 | /// so only do this once per `wlr_input_device`! 42 | pub(crate) unsafe fn new_from_input_device(device: *mut wlr_input_device) -> Option { 43 | use wlroots_sys::wlr_input_device_type::*; 44 | match (*device).type_ { 45 | WLR_INPUT_DEVICE_TABLET_PAD => { 46 | let pad = NonNull::new((*device).__bindgen_anon_1.tablet_pad).expect( 47 | "Pad pointer was \ 48 | null" 49 | ); 50 | let liveliness = Rc::new(Cell::new(false)); 51 | let handle = Rc::downgrade(&liveliness); 52 | let state = Box::new(InputState { 53 | handle, 54 | device: input::Device::from_ptr(device) 55 | }); 56 | (*pad.as_ptr()).data = Box::into_raw(state) as *mut _; 57 | Some(TabletPad { 58 | liveliness, 59 | device: input::Device::from_ptr(device), 60 | pad 61 | }) 62 | }, 63 | _ => None 64 | } 65 | } 66 | 67 | /// Gets the wlr_input_device associated with this TabletPad. 68 | pub fn input_device(&self) -> &input::Device { 69 | &self.device 70 | } 71 | } 72 | 73 | impl Drop for TabletPad { 74 | fn drop(&mut self) { 75 | if Rc::strong_count(&self.liveliness) != 1 { 76 | return; 77 | } 78 | wlr_log!(WLR_DEBUG, "Dropped TabletPad {:p}", self.pad.as_ptr()); 79 | unsafe { 80 | let _ = Box::from_raw((*self.pad.as_ptr()).data as *mut InputState); 81 | } 82 | let weak_count = Rc::weak_count(&self.liveliness); 83 | if weak_count > 0 { 84 | wlr_log!( 85 | WLR_DEBUG, 86 | "Still {} weak pointers to TabletPad {:p}", 87 | weak_count, 88 | self.pad.as_ptr() 89 | ); 90 | } 91 | } 92 | } 93 | 94 | impl Handleable, wlr_tablet_pad> for TabletPad { 95 | #[doc(hidden)] 96 | unsafe fn from_ptr(pad: *mut wlr_tablet_pad) -> Option { 97 | let pad = NonNull::new(pad)?; 98 | let data = Box::from_raw((*pad.as_ptr()).data as *mut InputState); 99 | let handle = data.handle.clone(); 100 | let device = data.device.clone(); 101 | (*pad.as_ptr()).data = Box::into_raw(data) as *mut _; 102 | Some(TabletPad { 103 | liveliness: handle.upgrade().unwrap(), 104 | device, 105 | pad 106 | }) 107 | } 108 | 109 | #[doc(hidden)] 110 | unsafe fn as_ptr(&self) -> *mut wlr_tablet_pad { 111 | self.pad.as_ptr() 112 | } 113 | 114 | #[doc(hidden)] 115 | unsafe fn from_handle(handle: &Handle) -> HandleResult { 116 | let liveliness = handle.handle.upgrade().ok_or(HandleErr::AlreadyDropped)?; 117 | let device = handle.data.ok_or(HandleErr::AlreadyDropped)?; 118 | Ok(TabletPad { 119 | liveliness, 120 | // NOTE Rationale for cloning: 121 | // If we already dropped we don't reach this point. 122 | device: input::Device { device }, 123 | pad: handle.as_non_null() 124 | }) 125 | } 126 | 127 | fn weak_reference(&self) -> Handle { 128 | Handle { 129 | ptr: self.pad, 130 | handle: Rc::downgrade(&self.liveliness), 131 | // NOTE Rationale for cloning: 132 | // Since we have a strong reference already, 133 | // the input must still be alive. 134 | data: unsafe { Some(self.device.as_non_null()) }, 135 | _marker: std::marker::PhantomData 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/types/input/touch.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use std::{cell::Cell, ptr::NonNull, rc::Rc}; 4 | 5 | use wlroots_sys::{wlr_input_device, wlr_touch}; 6 | 7 | pub use crate::events::touch_events as event; 8 | pub use crate::manager::touch_handler::*; 9 | use crate::{ 10 | input::{self, InputState}, 11 | utils::{self, HandleErr, HandleResult, Handleable} 12 | }; 13 | 14 | pub type Handle = utils::Handle, wlr_touch, Touch>; 15 | 16 | #[derive(Debug)] 17 | pub struct Touch { 18 | /// The structure that ensures weak handles to this structure are still 19 | /// alive. 20 | /// 21 | /// They contain weak handles, and will safely not use dead memory when this 22 | /// is freed by wlroots. 23 | /// 24 | /// If this is `None`, then this is from an upgraded `touch::Handle`, and 25 | /// the operations are **unchecked**. 26 | /// This is means safe operations might fail, but only if you use the unsafe 27 | /// marked function `upgrade` on a `touch::Handle`. 28 | liveliness: Rc>, 29 | /// The device that refers to this touch. 30 | device: input::Device, 31 | /// The underlying touch data. 32 | touch: NonNull 33 | } 34 | 35 | impl Touch { 36 | /// Tries to convert an input device to a Touch. 37 | /// 38 | /// Returns none if it is of a different input variant. 39 | /// 40 | /// # Safety 41 | /// This creates a totally new Touch (e.g with its own reference count) 42 | /// so only do this once per `wlr_input_device`! 43 | pub(crate) unsafe fn new_from_input_device(device: *mut wlr_input_device) -> Option { 44 | use wlroots_sys::wlr_input_device_type::*; 45 | match (*device).type_ { 46 | WLR_INPUT_DEVICE_TOUCH => { 47 | let touch = NonNull::new((*device).__bindgen_anon_1.touch).expect("Touch pointer was null"); 48 | let liveliness = Rc::new(Cell::new(false)); 49 | let handle = Rc::downgrade(&liveliness); 50 | let state = Box::new(InputState { 51 | handle, 52 | device: input::Device::from_ptr(device) 53 | }); 54 | (*touch.as_ptr()).data = Box::into_raw(state) as *mut _; 55 | Some(Touch { 56 | liveliness, 57 | device: input::Device::from_ptr(device), 58 | touch 59 | }) 60 | }, 61 | _ => None 62 | } 63 | } 64 | 65 | /// Gets the wlr_input_device associated with this `Touch`. 66 | pub fn input_device(&self) -> &input::Device { 67 | &self.device 68 | } 69 | } 70 | impl Drop for Touch { 71 | fn drop(&mut self) { 72 | if Rc::strong_count(&self.liveliness) == 1 { 73 | wlr_log!(WLR_DEBUG, "Dropped Touch {:p}", self.touch.as_ptr()); 74 | unsafe { 75 | let _ = Box::from_raw((*self.touch.as_ptr()).data as *mut input::Device); 76 | } 77 | let weak_count = Rc::weak_count(&self.liveliness); 78 | if weak_count > 0 { 79 | wlr_log!( 80 | WLR_DEBUG, 81 | "Still {} weak pointers to Touch {:p}", 82 | weak_count, 83 | self.touch.as_ptr() 84 | ); 85 | } 86 | } 87 | } 88 | } 89 | 90 | impl Handleable, wlr_touch> for Touch { 91 | #[doc(hidden)] 92 | unsafe fn from_ptr(touch: *mut wlr_touch) -> Option { 93 | let touch = NonNull::new(touch)?; 94 | let data = Box::from_raw((*touch.as_ptr()).data as *mut InputState); 95 | let handle = data.handle.clone(); 96 | let device = data.device.clone(); 97 | (*touch.as_ptr()).data = Box::into_raw(data) as *mut _; 98 | Some(Touch { 99 | liveliness: handle.upgrade().unwrap(), 100 | device, 101 | touch 102 | }) 103 | } 104 | 105 | #[doc(hidden)] 106 | unsafe fn as_ptr(&self) -> *mut wlr_touch { 107 | self.touch.as_ptr() 108 | } 109 | 110 | #[doc(hidden)] 111 | unsafe fn from_handle(handle: &Handle) -> HandleResult { 112 | let liveliness = handle.handle.upgrade().ok_or(HandleErr::AlreadyDropped)?; 113 | let device = handle.data.ok_or(HandleErr::AlreadyDropped)?; 114 | Ok(Touch { 115 | liveliness, 116 | // NOTE Rationale for cloning: 117 | // If we already dropped we don't reach this point. 118 | device: input::Device { device }, 119 | touch: handle.as_non_null() 120 | }) 121 | } 122 | 123 | fn weak_reference(&self) -> Handle { 124 | Handle { 125 | ptr: self.touch, 126 | handle: Rc::downgrade(&self.liveliness), 127 | // NOTE Rationale for cloning: 128 | // Since we have a strong reference already, 129 | // the input must still be alive. 130 | data: unsafe { Some(self.device.as_non_null()) }, 131 | _marker: std::marker::PhantomData 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/types/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cursor; 2 | 3 | #[cfg(feature = "unstable")] 4 | pub mod area; 5 | #[cfg(feature = "unstable")] 6 | pub mod dmabuf; 7 | #[cfg(feature = "unstable")] 8 | pub mod data_device; 9 | #[cfg(feature = "unstable")] 10 | pub mod input; 11 | #[cfg(feature = "unstable")] 12 | pub mod output; 13 | #[cfg(feature = "unstable")] 14 | pub mod seat; 15 | #[cfg(feature = "unstable")] 16 | pub mod shell; 17 | #[cfg(feature = "unstable")] 18 | pub mod surface; 19 | -------------------------------------------------------------------------------- /src/types/output/damage.rs: -------------------------------------------------------------------------------- 1 | use std::{ptr, time::Duration}; 2 | 3 | use crate::libc::clock_t; 4 | use wlroots_sys::{ 5 | timespec, wlr_output, wlr_output_damage, wlr_output_damage_add, wlr_output_damage_add_box, 6 | wlr_output_damage_add_whole, wlr_output_damage_create, wlr_output_damage_destroy, 7 | wlr_output_damage_make_current, wlr_output_damage_swap_buffers 8 | }; 9 | 10 | use crate::{area::Area, render::PixmanRegion}; 11 | 12 | #[derive(Debug)] 13 | /// Tracks damage for an output. 14 | /// 15 | /// When a `frame` event is emitted, `make_current` should be 16 | /// called. If necessary, the output should be repainted and 17 | /// `swap_buffers` should be called. 18 | /// 19 | /// No rendering should happen outside a `frame` event handler. 20 | pub struct Damage { 21 | damage: *mut wlr_output_damage 22 | } 23 | 24 | impl Damage { 25 | /// Makes a new `Damage` bound to the given Output. 26 | /// 27 | /// # Safety 28 | /// This function is unsafe because the `Damage` should not outlive the 29 | /// past in `Output`. 30 | pub(crate) unsafe fn new(output: *mut wlr_output) -> Self { 31 | unsafe { 32 | let damage = wlr_output_damage_create(output); 33 | if damage.is_null() { 34 | panic!("Damage was none") 35 | } 36 | Damage { damage } 37 | } 38 | } 39 | 40 | pub(crate) unsafe fn from_ptr(damage: *mut wlr_output_damage) -> Self { 41 | Damage { damage } 42 | } 43 | 44 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_output_damage { 45 | self.damage 46 | } 47 | 48 | /// Just like `std::clone::Clone` but unsafe. 49 | /// 50 | /// # Unsafety 51 | /// You can create a reference leak using this method very easily, 52 | /// and it could make it so that weak handles to an output are dangling. 53 | /// 54 | /// This exists due to an issue in output_manager.rs that might be fixed 55 | /// with NLL, so if this is no longer necessary it should be removed asap. 56 | pub(crate) unsafe fn clone(&self) -> Self { 57 | Damage { damage: self.damage } 58 | } 59 | 60 | /// Makes the output rendering context current. 61 | /// Returns `true` if `wlr_output_damage_swap_buffers` needs to be called. 62 | /// 63 | /// The region of the output that needs to be repainted is added to 64 | /// `damage`. 65 | pub fn make_current<'a, T>(&mut self, damage: T) -> bool 66 | where 67 | T: Into> 68 | { 69 | unsafe { 70 | let mut res = false; 71 | let damage = match damage.into() { 72 | Some(region) => &mut region.region as *mut _, 73 | None => ptr::null_mut() 74 | }; 75 | wlr_output_damage_make_current(self.damage, &mut res, damage); 76 | res 77 | } 78 | } 79 | 80 | /// Swaps the output buffers. 81 | /// 82 | /// If the time of the frame isn't known, set `when` to `None`. 83 | /// 84 | /// Swapping buffers schedules a `frame` event. 85 | pub fn swap_buffers<'a, T, U>(&mut self, when: T, damage: U) -> bool 86 | where 87 | T: Into>, 88 | U: Into> 89 | { 90 | unsafe { 91 | let when = when.into().map(|duration| timespec { 92 | tv_sec: duration.as_secs() as clock_t, 93 | tv_nsec: clock_t::from(duration.subsec_nanos()) 94 | }); 95 | let when_ptr = when 96 | .map(|mut duration| &mut duration as *mut _) 97 | .unwrap_or_else(ptr::null_mut); 98 | let damage = match damage.into() { 99 | Some(region) => &mut region.region as *mut _, 100 | None => ptr::null_mut() 101 | }; 102 | wlr_output_damage_swap_buffers(self.damage, when_ptr, damage) 103 | } 104 | } 105 | 106 | /// Accumulates damage and schedules a `frame` event. 107 | pub fn add(&mut self, damage: &mut PixmanRegion) { 108 | unsafe { 109 | wlr_output_damage_add(self.damage, &mut damage.region); 110 | } 111 | } 112 | 113 | /// Damages the whole output and schedules a `frame` event. 114 | pub fn add_whole(&mut self) { 115 | unsafe { wlr_output_damage_add_whole(self.damage) } 116 | } 117 | 118 | /// Accumulates damage from an `Area` and schedules a `frame` event. 119 | pub fn add_area(&mut self, area: Area) { 120 | unsafe { wlr_output_damage_add_box(self.damage, &mut area.into()) } 121 | } 122 | } 123 | 124 | impl Drop for Damage { 125 | fn drop(&mut self) { 126 | wlr_log!(WLR_DEBUG, "Dropped Damage {:p}", self.damage); 127 | unsafe { 128 | wlr_output_damage_destroy(self.damage); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/types/output/mod.rs: -------------------------------------------------------------------------------- 1 | mod cursor; 2 | mod damage; 3 | pub mod layout; 4 | mod mode; 5 | #[allow(clippy::module_inception)] 6 | mod output; 7 | 8 | pub use self::cursor::*; 9 | pub use self::damage::*; 10 | pub use self::mode::*; 11 | pub use self::output::*; 12 | 13 | pub mod manager { 14 | //! Output resources are managed by the output resource manager. 15 | //! 16 | //! Using the [`OutputBuilder`](./struct.OutputBuilder.html) a 17 | //! [`BuilderResult`](./struct.BuilderResult.html) is constructed in a 18 | //! function conforming to the [`OutputAdded`](./type.OutputAdded.html) 19 | //! type signature. That function is passed to the [`output::Builder`](. 20 | //! /struct.Builder.html) which is then given to the `compositor::Builder`. 21 | pub use crate::manager::output_manager::*; 22 | } 23 | -------------------------------------------------------------------------------- /src/types/output/mode.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use std::marker::PhantomData; 4 | 5 | use wlroots_sys::wlr_output_mode; 6 | 7 | use crate::output::Output; 8 | 9 | #[derive(Debug, Eq, PartialEq)] 10 | pub struct Mode<'output> { 11 | output_mode: *mut wlr_output_mode, 12 | phantom: PhantomData<&'output Output> 13 | } 14 | 15 | impl<'output> Mode<'output> { 16 | /// NOTE This is a lifetime defined by the user of this function, but it 17 | /// must not outlive the `Output` that hosts this output mode. 18 | pub(crate) unsafe fn new<'unbound>(output_mode: *mut wlr_output_mode) -> Mode<'unbound> { 19 | Mode { 20 | output_mode, 21 | phantom: PhantomData 22 | } 23 | } 24 | 25 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_output_mode { 26 | self.output_mode 27 | } 28 | 29 | /// Gets the flags set on this Mode. 30 | pub fn flags(&self) -> u32 { 31 | unsafe { (*self.output_mode).flags } 32 | } 33 | 34 | /// Gets the dimensions of this Mode. 35 | /// 36 | /// Returned value is (width, height) 37 | pub fn dimensions(&self) -> (i32, i32) { 38 | unsafe { ((*self.output_mode).width, (*self.output_mode).height) } 39 | } 40 | 41 | /// Get the refresh value of the output. 42 | pub fn refresh(&self) -> i32 { 43 | unsafe { (*self.output_mode).refresh } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/types/seat/drag_icon.rs: -------------------------------------------------------------------------------- 1 | use std::{ 2 | cell::Cell, 3 | hash::{Hash, Hasher}, 4 | panic, 5 | rc::{Rc, Weak} 6 | }; 7 | 8 | use wlroots_sys::wlr_drag_icon; 9 | 10 | pub use crate::manager::drag_icon_handler::*; 11 | use crate::{ 12 | surface, 13 | utils::{HandleErr, HandleResult} 14 | }; 15 | 16 | #[derive(Debug)] 17 | pub struct DragIcon { 18 | liveliness: Rc>, 19 | drag_icon: *mut wlr_drag_icon 20 | } 21 | 22 | impl DragIcon { 23 | #[allow(dead_code)] 24 | pub(crate) unsafe fn new(drag_icon: *mut wlr_drag_icon) -> Self { 25 | let liveliness = Rc::new(Cell::new(false)); 26 | let state = Box::new(DragIconState { 27 | handle: Rc::downgrade(&liveliness) 28 | }); 29 | (*drag_icon).data = Box::into_raw(state) as *mut _; 30 | DragIcon { 31 | liveliness, 32 | drag_icon 33 | } 34 | } 35 | 36 | /// Get a handle for the surface associated with this drag icon 37 | pub fn surface(&mut self) -> surface::Handle { 38 | unsafe { 39 | let surface = (*self.drag_icon).surface; 40 | if surface.is_null() { 41 | panic!("drag icon had a null surface!"); 42 | } 43 | surface::Handle::from_ptr(surface) 44 | } 45 | } 46 | 47 | /// Whether or not to display the drag icon 48 | pub fn mapped(&mut self) -> bool { 49 | unsafe { (*self.drag_icon).mapped } 50 | } 51 | 52 | /// If this is a touch-driven dnd operation, the id of the touch point that 53 | /// started it 54 | pub fn touch_id(&mut self) -> i32 { 55 | unsafe { (*(*self.drag_icon).drag).touch_id } 56 | } 57 | 58 | /// Creates a weak reference to a `DragIcon`. 59 | pub fn weak_reference(&self) -> Handle { 60 | Handle { 61 | handle: Rc::downgrade(&self.liveliness), 62 | drag_icon: self.drag_icon 63 | } 64 | } 65 | 66 | unsafe fn from_handle(handle: &Handle) -> HandleResult { 67 | let liveliness = handle.handle.upgrade().ok_or_else(|| HandleErr::AlreadyDropped)?; 68 | Ok(DragIcon { 69 | liveliness, 70 | drag_icon: handle.as_ptr() 71 | }) 72 | } 73 | } 74 | 75 | pub(crate) struct DragIconState { 76 | handle: Weak> 77 | } 78 | 79 | #[derive(Debug, Clone)] 80 | pub struct Handle { 81 | handle: Weak>, 82 | drag_icon: *mut wlr_drag_icon 83 | } 84 | 85 | impl Eq for Handle {} 86 | 87 | impl PartialEq for Handle { 88 | fn eq(&self, rhs: &Self) -> bool { 89 | self.drag_icon == rhs.drag_icon 90 | } 91 | } 92 | 93 | impl Hash for Handle { 94 | fn hash(&self, state: &mut H) { 95 | self.drag_icon.hash(state); 96 | } 97 | } 98 | 99 | impl Handle { 100 | #[allow(unused)] 101 | pub(crate) unsafe fn from_ptr(drag_icon: *mut wlr_drag_icon) -> Self { 102 | if drag_icon.is_null() { 103 | panic!("drag icon was null"); 104 | } 105 | let data = (*drag_icon).data as *mut DragIconState; 106 | if data.is_null() { 107 | panic!("Cannot construct handle from drag icon that has not been set up!"); 108 | } 109 | 110 | let handle = (*data).handle.clone(); 111 | 112 | Handle { handle, drag_icon } 113 | } 114 | 115 | pub(crate) unsafe fn upgrade(&self) -> HandleResult { 116 | self.handle.upgrade() 117 | .ok_or(HandleErr::AlreadyDropped) 118 | // NOTE 119 | // We drop the Rc here because having two would allow a dangling 120 | // pointer to exist! 121 | .and_then(|check| { 122 | let drag_icon = DragIcon::from_handle(self)?; 123 | if check.get() { 124 | return Err(HandleErr::AlreadyBorrowed) 125 | } 126 | check.set(true); 127 | Ok(drag_icon) 128 | }) 129 | } 130 | 131 | pub fn run(&self, runner: F) -> HandleResult 132 | where 133 | F: FnOnce(&mut DragIcon) -> R 134 | { 135 | let mut drag_icon = unsafe { self.upgrade()? }; 136 | let res = panic::catch_unwind(panic::AssertUnwindSafe(|| runner(&mut drag_icon))); 137 | if let Some(check) = self.handle.upgrade() { 138 | // Sanity check that it hasn't been tampered with. 139 | if !check.get() { 140 | wlr_log!( 141 | WLR_ERROR, 142 | "After running DragIcon callback, mutable lock was \ 143 | false for: {:?}", 144 | drag_icon 145 | ); 146 | panic!("Lock in incorrect state!"); 147 | } 148 | check.set(false); 149 | }; 150 | match res { 151 | Ok(res) => Ok(res), 152 | Err(err) => panic::resume_unwind(err) 153 | } 154 | } 155 | 156 | unsafe fn as_ptr(&self) -> *mut wlr_drag_icon { 157 | self.drag_icon 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/types/seat/grab.rs: -------------------------------------------------------------------------------- 1 | use wlroots_sys::{wlr_seat_keyboard_grab, wlr_seat_pointer_grab, wlr_seat_touch_grab}; 2 | 3 | pub struct Pointer { 4 | grab: *mut wlr_seat_pointer_grab 5 | } 6 | 7 | pub struct Keyboard { 8 | grab: *mut wlr_seat_keyboard_grab 9 | } 10 | 11 | pub struct Touch { 12 | grab: *mut wlr_seat_touch_grab 13 | } 14 | 15 | #[allow(dead_code)] 16 | impl Pointer { 17 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_seat_pointer_grab { 18 | self.grab 19 | } 20 | 21 | pub(crate) unsafe fn from_ptr(grab: *mut wlr_seat_pointer_grab) -> Self { 22 | Pointer { grab } 23 | } 24 | } 25 | 26 | #[allow(dead_code)] 27 | impl Keyboard { 28 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_seat_keyboard_grab { 29 | self.grab 30 | } 31 | 32 | pub(crate) unsafe fn from_ptr(grab: *mut wlr_seat_keyboard_grab) -> Self { 33 | Keyboard { grab } 34 | } 35 | } 36 | 37 | #[allow(dead_code)] 38 | impl Touch { 39 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_seat_touch_grab { 40 | self.grab 41 | } 42 | 43 | pub(crate) unsafe fn from_ptr(grab: *mut wlr_seat_touch_grab) -> Self { 44 | Touch { grab } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/types/seat/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod drag_icon; 2 | pub mod grab; 3 | #[allow(clippy::module_inception)] 4 | mod seat; 5 | mod seat_client; 6 | mod touch_point; 7 | 8 | pub use self::seat::*; 9 | pub use self::seat_client::*; 10 | pub use self::touch_point::*; 11 | -------------------------------------------------------------------------------- /src/types/seat/seat_client.rs: -------------------------------------------------------------------------------- 1 | //! Wrapper for wlr_seat_client, a manager for handling seats to an individual 2 | //! client. 3 | //! 4 | //! This struct is very unsafe, and probably will not be used directly by the 5 | //! compositor author. Instead, this is used internally by various wlr seat 6 | //! state structs (e.g `wlr_seat_keyboard_state`, `wlr_seat_pointer_state`) 7 | 8 | use std::marker::PhantomData; 9 | 10 | use super::seat::Seat; 11 | 12 | use wlroots_sys::{wl_client, wlr_seat_client, wlr_seat_client_for_wl_client}; 13 | 14 | /// Contains state for a single client's bound wl_seat resource. 15 | /// It can be used to issue input events to the client. 16 | /// 17 | /// The lifetime of this object is managed by `Seat`. 18 | pub struct Client<'wlr_seat> { 19 | client: *mut wlr_seat_client, 20 | _phantom: PhantomData<&'wlr_seat Seat> 21 | } 22 | 23 | #[allow(dead_code)] 24 | impl<'wlr_seat> Client<'wlr_seat> { 25 | /// Gets a seat::Client for the specified client, 26 | /// if there is one bound for that client. 27 | /// 28 | /// # Unsafety 29 | /// Since this just is a wrapper for checking if the wlr_seat pointer 30 | /// matches the provided wl_client pointer, this function is unsafe. 31 | /// 32 | /// Please only pass a valid pointer to a wl_client to this function. 33 | pub unsafe fn client_for_wl_client( 34 | seat: &'wlr_seat mut Seat, 35 | client: *mut wl_client 36 | ) -> Option> { 37 | let client = wlr_seat_client_for_wl_client(seat.as_ptr(), client); 38 | if client.is_null() { 39 | None 40 | } else { 41 | Some(Client { 42 | client, 43 | _phantom: PhantomData 44 | }) 45 | } 46 | } 47 | 48 | /// Recreates a `Client` from a raw `wlr_seat_client`. 49 | /// 50 | /// # Unsafety 51 | /// The pointer must point to a valid `wlr_seat_client`. 52 | /// 53 | /// Note also that the struct has an *boundless lifetime*. You _must_ ensure 54 | /// this struct does not live longer than the `Seat` that manages it. 55 | pub(crate) unsafe fn from_ptr<'unbound_seat>(client: *mut wlr_seat_client) -> Client<'unbound_seat> { 56 | Client { 57 | client, 58 | _phantom: PhantomData 59 | } 60 | } 61 | 62 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_seat_client { 63 | self.client 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/types/seat/touch_point.rs: -------------------------------------------------------------------------------- 1 | use wlroots_sys::wlr_touch_point; 2 | 3 | #[derive(Clone)] 4 | pub struct TouchPoint { 5 | touch_point: *mut wlr_touch_point 6 | } 7 | 8 | /// Wrapper around a touch id. It is valid, as it is only returned from wlroots. 9 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 10 | pub struct TouchId(i32); 11 | 12 | // Note that we implement `Into` here because we _don't_ want to be able to 13 | // convert from any i32 into a `TouchId` 14 | impl Into for TouchId { 15 | fn into(self) -> i32 { 16 | self.0 17 | } 18 | } 19 | 20 | impl TouchPoint { 21 | /// Get the touch id associated for this point. 22 | pub fn touch_id(&self) -> TouchId { 23 | unsafe { TouchId((*self.touch_point).touch_id) } 24 | } 25 | 26 | #[allow(dead_code)] 27 | pub(crate) unsafe fn as_ptr(&self) -> *mut wlr_touch_point { 28 | self.touch_point 29 | } 30 | 31 | pub(crate) unsafe fn from_ptr(touch_point: *mut wlr_touch_point) -> Self { 32 | TouchPoint { touch_point } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/types/shell/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod xdg_shell; 2 | pub mod xdg_shell_v6; 3 | -------------------------------------------------------------------------------- /src/types/surface/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod subsurface; 2 | pub(crate) mod subsurface_manager; 3 | #[allow(clippy::module_inception)] 4 | mod surface; 5 | mod surface_state; 6 | 7 | pub use self::surface::*; 8 | pub use self::surface_state::*; 9 | -------------------------------------------------------------------------------- /src/types/surface/subsurface.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use std::{cell::Cell, ptr::NonNull, rc::Rc}; 4 | 5 | use crate::libc; 6 | use crate::wayland_sys::server::WAYLAND_SERVER_HANDLE; 7 | use wlroots_sys::wlr_subsurface; 8 | 9 | use crate::{ 10 | compositor, surface, 11 | utils::{self, HandleErr, HandleResult, Handleable} 12 | }; 13 | 14 | pub type Handle = utils::Handle<(), wlr_subsurface, Subsurface>; 15 | 16 | #[allow(unused_variables)] 17 | pub trait Handler { 18 | fn on_destroy( 19 | &mut self, 20 | compositor_handle: compositor::Handle, 21 | subsurface_handle: Handle, 22 | surface_handle: surface::Handle 23 | ) { 24 | } 25 | } 26 | 27 | wayland_listener!(pub(crate) InternalSubsurface, (Subsurface, Box), [ 28 | on_destroy_listener => on_destroy_notify: |this: &mut InternalSubsurface, 29 | data: *mut libc::c_void,| 30 | unsafe { 31 | let (ref mut subsurface, ref mut manager) = this.data; 32 | let subsurface_ptr = data as *mut wlr_subsurface; 33 | let surface = surface::Handle::from_ptr((*subsurface_ptr).surface); 34 | let compositor = match compositor::handle() { 35 | Some(handle) => handle, 36 | None => return 37 | }; 38 | manager.on_destroy(compositor, subsurface.weak_reference(), surface); 39 | Box::from_raw((*subsurface_ptr).data as *mut InternalSubsurface); 40 | }; 41 | ]); 42 | 43 | #[derive(Debug)] 44 | pub struct Subsurface { 45 | /// The structe that ensures weak handles to this structure are still alive. 46 | /// 47 | /// They contain weak handles, and will safely not use dead memory when this 48 | /// is freed by wlroots. 49 | /// 50 | /// If this is `None`, then this is from an upgraded `surface::Handle`, and 51 | /// the operations are **unchecked**. 52 | /// This is means safe operations might fail, but only if you use the unsafe 53 | /// marked function `upgrade` on a `surface::Handle`. 54 | liveliness: Rc>, 55 | /// The pointer to the wlroots object that wraps a wl_surface. 56 | subsurface: NonNull 57 | } 58 | 59 | impl Subsurface { 60 | pub(crate) unsafe fn new(subsurface: *mut wlr_subsurface) -> Self { 61 | let subsurface = NonNull::new(subsurface).expect("Subsurface pointer was null"); 62 | let liveliness = Rc::new(Cell::new(false)); 63 | Subsurface { 64 | subsurface, 65 | liveliness 66 | } 67 | } 68 | 69 | /// Get a handle to the surface for this sub surface. 70 | pub fn surface(&self) -> surface::Handle { 71 | unsafe { surface::Handle::from_ptr((*self.subsurface.as_ptr()).surface) } 72 | } 73 | 74 | /// Get a handle to the parent surface for this sub surface. 75 | pub fn parent_surface(&self) -> surface::Handle { 76 | unsafe { surface::Handle::from_ptr((*self.subsurface.as_ptr()).parent) } 77 | } 78 | 79 | /// Get the cached state of the sub surface. 80 | pub fn cached_state(&self) -> Option { 81 | unsafe { 82 | if (*self.subsurface.as_ptr()).has_cache { 83 | None 84 | } else { 85 | Some(surface::State::new((*self.subsurface.as_ptr()).cached)) 86 | } 87 | } 88 | } 89 | 90 | /// Determine if the sub surface has a cached state. 91 | pub fn has_cache(&self) -> bool { 92 | unsafe { (*self.subsurface.as_ptr()).has_cache } 93 | } 94 | 95 | pub fn synchronized(&self) -> bool { 96 | unsafe { (*self.subsurface.as_ptr()).synchronized } 97 | } 98 | 99 | pub fn reordered(&self) -> bool { 100 | unsafe { (*self.subsurface.as_ptr()).reordered } 101 | } 102 | } 103 | 104 | impl Handleable<(), wlr_subsurface> for Subsurface { 105 | #[doc(hidden)] 106 | unsafe fn from_ptr(subsurface: *mut wlr_subsurface) -> Option { 107 | let subsurface = NonNull::new(subsurface)?; 108 | let data = (*subsurface.as_ptr()).data as *mut InternalSubsurface; 109 | Some(Subsurface { 110 | liveliness: (*data).data.0.liveliness.clone(), 111 | subsurface 112 | }) 113 | } 114 | 115 | #[doc(hidden)] 116 | unsafe fn as_ptr(&self) -> *mut wlr_subsurface { 117 | self.subsurface.as_ptr() 118 | } 119 | 120 | #[doc(hidden)] 121 | unsafe fn from_handle(handle: &Handle) -> HandleResult { 122 | let liveliness = handle.handle.upgrade().ok_or_else(|| HandleErr::AlreadyDropped)?; 123 | Ok(Subsurface { 124 | liveliness, 125 | subsurface: handle.ptr 126 | }) 127 | } 128 | 129 | fn weak_reference(&self) -> Handle { 130 | Handle { 131 | ptr: self.subsurface, 132 | handle: Rc::downgrade(&self.liveliness), 133 | data: Some(()), 134 | _marker: std::marker::PhantomData 135 | } 136 | } 137 | } 138 | 139 | impl Drop for InternalSubsurface { 140 | fn drop(&mut self) { 141 | unsafe { 142 | ffi_dispatch!( 143 | WAYLAND_SERVER_HANDLE, 144 | wl_list_remove, 145 | &mut (*self.on_destroy_listener()).link as *mut _ as _ 146 | ); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/types/surface/subsurface_manager.rs: -------------------------------------------------------------------------------- 1 | //! Handles the subsurface list for surfaces. 2 | //! 3 | //! This handler will live in the Surface struct, behind a box 4 | //! and is not exposed to the compositor writer. 5 | //! 6 | //! It ensures the list of subsurfaces is kept up to date and invalidates 7 | //! the subsurface handles when they are destroyed. 8 | 9 | use std::fmt; 10 | 11 | use crate::libc; 12 | use wlroots_sys::wlr_subsurface; 13 | 14 | use crate::{ 15 | surface::subsurface::{self, Subsurface}, 16 | utils::Handleable 17 | }; 18 | 19 | wayland_listener!(pub SubsurfaceManager, Vec, [ 20 | subsurface_created_listener => subsurface_created_notify: 21 | |this: &mut SubsurfaceManager, data: *mut libc::c_void,| 22 | unsafe { 23 | let subsurfaces = &mut this.data; 24 | let subsurface = Subsurface::new(data as *mut wlr_subsurface); 25 | subsurfaces.push(subsurface) 26 | }; 27 | ]); 28 | 29 | impl SubsurfaceManager { 30 | pub(crate) fn subsurfaces(&self) -> Vec { 31 | self.data.iter().map(|surface| surface.weak_reference()).collect() 32 | } 33 | } 34 | 35 | impl fmt::Debug for SubsurfaceManager { 36 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 37 | write!(f, "{:?}", self.data) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/types/surface/surface_state.rs: -------------------------------------------------------------------------------- 1 | //! TODO Documentation 2 | 3 | use std::marker::PhantomData; 4 | 5 | use crate::libc::c_int; 6 | use wlroots_sys::{wl_output_transform, wl_resource, wlr_surface_state}; 7 | 8 | use crate::{render::PixmanRegion, surface::Surface}; 9 | 10 | #[derive(Debug)] 11 | #[repr(u32)] 12 | /// Represents a change in the pending state. 13 | /// 14 | /// When a particular bit is set, it means the field corresponding to it 15 | /// will be updated for the current state on the next commit. 16 | /// 17 | /// # Pending vs Current state 18 | /// When this is set on the pending state, it means this field will be updated 19 | /// on the next commit. 20 | /// 21 | /// When it is set on the current state, it indicates what fields have changed 22 | /// since the last commit. 23 | pub enum InvalidState { 24 | Buffer = 1, 25 | SurfaceDamage = 2, 26 | BufferDamage = 4, 27 | OpaqueRegion = 8, 28 | InputRegion = 16, 29 | Transform = 32, 30 | Scale = 64, 31 | SubsurfacePosition = 128, 32 | FrameCallbackList = 256 33 | } 34 | 35 | /// Surface state as reported by wlroots. 36 | #[derive(Debug)] 37 | pub struct State<'surface> { 38 | state: wlr_surface_state, 39 | phantom: PhantomData<&'surface Surface> 40 | } 41 | 42 | impl<'surface> State<'surface> { 43 | /// Create a new subsurface from the given surface. 44 | /// 45 | /// # Safety 46 | /// Since we rely on the surface providing a valid surface state, 47 | /// this function is marked unsafe. 48 | pub(crate) unsafe fn new(state: wlr_surface_state) -> State<'surface> { 49 | State { 50 | state, 51 | phantom: PhantomData 52 | } 53 | } 54 | 55 | /// Gets the state of the sub surface. 56 | /// 57 | /// # Panics 58 | /// If the invalid state is in an undefined state, this will panic. 59 | pub fn committed(&self) -> InvalidState { 60 | use self::InvalidState::*; 61 | unsafe { 62 | match self.state.committed { 63 | 1 => Buffer, 64 | 2 => SurfaceDamage, 65 | 4 => BufferDamage, 66 | 8 => OpaqueRegion, 67 | 16 => InputRegion, 68 | 32 => Transform, 69 | 64 => Scale, 70 | 128 => SubsurfacePosition, 71 | 256 => FrameCallbackList, 72 | invalid => { 73 | wlr_log!(WLR_ERROR, "Invalid invalid state {}", invalid); 74 | panic!("Invalid invalid state in wlr_surface_state") 75 | } 76 | } 77 | } 78 | } 79 | 80 | /// Get the position of the surface relative to the previous position. 81 | /// 82 | /// Return value is in (dx, dy) format. 83 | pub fn position(&self) -> (i32, i32) { 84 | unsafe { (self.state.dx, self.state.dy) } 85 | } 86 | 87 | /// Get the size of the sub surface. 88 | /// 89 | /// Return value is in (width, height) format. 90 | pub fn size(&self) -> (c_int, c_int) { 91 | unsafe { (self.state.width, self.state.height) } 92 | } 93 | 94 | /// Get the size of the buffer. 95 | /// 96 | /// Return value is iw (width, height) format. 97 | pub fn buffer_size(&self) -> (c_int, c_int) { 98 | unsafe { (self.state.buffer_width, self.state.buffer_height) } 99 | } 100 | 101 | /// Get the scale applied to the surface. 102 | pub fn scale(&self) -> i32 { 103 | unsafe { self.state.scale } 104 | } 105 | 106 | /// Get the output transform applied to the surface. 107 | pub fn transform(&self) -> wl_output_transform { 108 | unsafe { self.state.transform } 109 | } 110 | 111 | /// Gets the buffer of the surface. 112 | pub unsafe fn buffer(&self) -> *mut wl_resource { 113 | self.state.buffer_resource 114 | } 115 | 116 | pub unsafe fn surface_damage(&self) -> PixmanRegion { 117 | PixmanRegion { 118 | region: self.state.surface_damage 119 | } 120 | } 121 | 122 | pub unsafe fn buffer_damage(&self) -> PixmanRegion { 123 | PixmanRegion { 124 | region: self.state.buffer_damage 125 | } 126 | } 127 | 128 | pub unsafe fn opaque(&self) -> PixmanRegion { 129 | PixmanRegion { 130 | region: self.state.opaque 131 | } 132 | } 133 | 134 | pub unsafe fn input(&self) -> PixmanRegion { 135 | PixmanRegion { 136 | region: self.state.input 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/utils/edges.rs: -------------------------------------------------------------------------------- 1 | //! Some events refer to actions that occurred on certain "edges" of windows. 2 | //! This is represented as a bit flag since multiple edges (including none) 3 | //! could be affected. 4 | 5 | use wlroots_sys::wlr_edges; 6 | 7 | bitflags! { 8 | /// A bit flag representing which edge was affected by an event. 9 | pub struct Edges: u32 { 10 | const WLR_EDGE_NONE = wlr_edges::WLR_EDGE_NONE as u32; 11 | const WLR_EDGE_TOP = wlr_edges::WLR_EDGE_TOP as u32; 12 | const WLR_EDGE_BOTTOM = wlr_edges::WLR_EDGE_BOTTOM as u32; 13 | const WLR_EDGE_LEFT = wlr_edges::WLR_EDGE_LEFT as u32; 14 | const WLR_EDGE_RIGHT = wlr_edges::WLR_EDGE_RIGHT as u32; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/utils/log.rs: -------------------------------------------------------------------------------- 1 | //! Hooks into the wlroots logging functionality. Internally many events are 2 | //! logged and are reported on standard error. The verbosity of the logs is 3 | //! determined by [the verbosity level](type.LogVerbosity.html) when 4 | //! [initializing the logs](fn.init_logging.html). 5 | //! 6 | //! To log using this system please utilize the 7 | //! [`wlr_log!`](../../macro.wlr_log.html) macro. 8 | 9 | use crate::libc::c_char; 10 | use vsprintf::vsprintf; 11 | use wlroots_sys::{__va_list_tag, _wlr_log, wlr_log_importance, wlr_log_init}; 12 | 13 | use crate::utils::c_to_rust_string; 14 | 15 | use std::ffi::CString; 16 | 17 | // Export these so it can be used in `wlr_log!`. 18 | pub use self::wlr_log_importance::{WLR_DEBUG, WLR_ERROR, WLR_INFO, WLR_SILENT}; 19 | 20 | /// How verbose you want the logging. Lower levels prints more. 21 | pub type LogVerbosity = wlr_log_importance; 22 | 23 | /// The signature for the callback function you can hook into the logging 24 | /// functionality of wlroots. 25 | /// 26 | /// `message` is the formatted string ready to be displayed on the screen. 27 | pub type LogCallback = fn(verbosity: LogVerbosity, message: String); 28 | 29 | static mut RUST_LOGGING_FN: LogCallback = dummy_callback; 30 | 31 | /// Initialize wlroots logging at a certain level of verbosity with 32 | /// an optional callback that will be called for every log. 33 | /// 34 | /// To log using this system, use the 35 | /// [`wlr_log!`](../../macro.wlr_log.html) macro. 36 | pub fn init_logging(verbosity: LogVerbosity, callback: F) 37 | where 38 | F: Into> 39 | { 40 | unsafe { 41 | match callback.into() { 42 | None => wlr_log_init(verbosity, None), 43 | Some(callback) => { 44 | RUST_LOGGING_FN = callback; 45 | wlr_log_init(verbosity, Some(log_callback)); 46 | } 47 | } 48 | } 49 | } 50 | 51 | /// Dummy callback to fill in RUST_LOGGING_FN when it's not in use. 52 | fn dummy_callback(_: LogVerbosity, _: String) {} 53 | 54 | /// Real hook into the logging callback, calls the real user-supplied callback 55 | /// with nice Rust inputs. 56 | unsafe extern "C" fn log_callback( 57 | importance: wlr_log_importance, 58 | fmt: *const c_char, 59 | va_list: *mut __va_list_tag 60 | ) { 61 | let message = 62 | vsprintf(fmt, va_list).unwrap_or_else(|_| c_to_rust_string(fmt).unwrap_or_else(|| "".into())); 63 | RUST_LOGGING_FN(importance, message); 64 | } 65 | 66 | pub struct Logger; 67 | 68 | static LOGGER: Logger = Logger; 69 | 70 | impl Logger { 71 | /// Attempts to initialize the global logger with a Logger around _wlr_log. 72 | /// 73 | /// This should be called early in the execution of the program, as all log 74 | /// events that occur before initialization with be ignored. 75 | /// 76 | /// # Errors 77 | /// 78 | /// This function will fail if it is called more than once, or if another 79 | /// library has already initialized a global logger. 80 | pub fn init(level: log::LevelFilter, callback: F) 81 | where 82 | F: Into> 83 | { 84 | init_logging( 85 | match level { 86 | log::LevelFilter::Off => WLR_SILENT, 87 | log::LevelFilter::Warn | log::LevelFilter::Error => WLR_ERROR, 88 | log::LevelFilter::Info => WLR_INFO, 89 | log::LevelFilter::Debug | log::LevelFilter::Trace => WLR_DEBUG 90 | }, 91 | callback 92 | ); 93 | 94 | log::set_logger(&LOGGER).expect( 95 | "Attempted to set a logger after the logging system was \ 96 | already initialized" 97 | ); 98 | log::set_max_level(level); 99 | } 100 | } 101 | 102 | impl log::Log for Logger { 103 | fn enabled(&self, metadata: &log::Metadata) -> bool { 104 | metadata.level() <= log::max_level() 105 | } 106 | 107 | fn log(&self, record: &log::Record) { 108 | if self.enabled(record.metadata()) { 109 | let wlr_level = match record.level() { 110 | log::Level::Warn | log::Level::Error => WLR_ERROR, 111 | log::Level::Info => WLR_INFO, 112 | log::Level::Debug | log::Level::Trace => WLR_DEBUG 113 | }; 114 | 115 | let formatted_msg = match (record.file(), record.line()) { 116 | (Some(file), Some(line)) => format!("[{}:{}] {}", file, line, record.args()), 117 | (Some(file), None) => format!("[{}] {}", file, record.args()), 118 | (None, _) => format!("{}", record.args()) 119 | }; 120 | let msg = CString::new(formatted_msg).expect("Could not convert log message to CString"); 121 | 122 | unsafe { 123 | _wlr_log(wlr_level, msg.as_ptr()); 124 | } 125 | } 126 | } 127 | 128 | fn flush(&self) {} 129 | } 130 | -------------------------------------------------------------------------------- /src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | //! Utilities for use within wlroots-rs that are not directly related to Wayland 2 | //! or compositors. 3 | 4 | pub mod edges; 5 | pub mod log; 6 | pub mod region; 7 | 8 | // Rust specific utilities that don't wrap a wlroots utility. 9 | mod handle; 10 | mod string; 11 | mod time; 12 | 13 | pub use self::handle::*; 14 | pub(crate) use self::string::{c_to_rust_string, safe_as_cstring}; 15 | pub use self::time::{current_time, ToMs}; 16 | 17 | /// Handle unwinding from a panic, used in conjunction with 18 | /// `::std::panic::catch_unwind`. 19 | /// 20 | /// When a panic occurs, we terminate the compositor and let the rest 21 | /// of the code run. 22 | #[cfg(feature = "unstable")] 23 | pub(crate) unsafe fn handle_unwind(res: ::std::thread::Result) { 24 | match res { 25 | Ok(_) => {}, 26 | Err(err) => { 27 | if crate::compositor::COMPOSITOR_PTR == 0 as *mut _ { 28 | ::std::process::abort(); 29 | } 30 | (&mut *crate::compositor::COMPOSITOR_PTR).save_panic_error(err); 31 | crate::compositor::terminate() 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/utils/region.rs: -------------------------------------------------------------------------------- 1 | //! Helper functions for manipulating Pixman regions from the Pixman library. 2 | //! 3 | //! [The Pixman library](http://www.pixman.org/) is a library for pixel 4 | //! manipulation. 5 | 6 | use std::mem; 7 | 8 | use crate::libc::{c_double, c_float, c_int}; 9 | use wlroots_sys::{ 10 | pixman_region32_init, pixman_region32_t, wl_output_transform, wlr_region_confine, wlr_region_expand, 11 | wlr_region_rotated_bounds, wlr_region_scale, wlr_region_transform 12 | }; 13 | 14 | /// A thin wrapper around a 32 bit Pixman region. 15 | #[derive(Default)] 16 | pub struct PixmanRegion32 { 17 | pub region: pixman_region32_t 18 | } 19 | 20 | impl PixmanRegion32 { 21 | /// Construct a new Pixman region. 22 | pub fn new() -> Self { 23 | unsafe { 24 | // NOTE This is safe because the init function properly 25 | // sets up the fields. 26 | let mut region: pixman_region32_t = mem::uninitialized(); 27 | pixman_region32_init(&mut region); 28 | PixmanRegion32 { region } 29 | } 30 | } 31 | 32 | /// Scales a region, ie. multiplies all its coordinates by `scale` 33 | /// and write out the result to `dest`. 34 | /// 35 | /// The resulting coordinates are rounded up or down so that the new region 36 | /// is at least as big as the original one. 37 | pub fn scale(&self, dest: &mut PixmanRegion32, scale: c_float) { 38 | unsafe { 39 | let region_ptr = &self.region as *const _ as *mut _; 40 | wlr_region_scale(&mut dest.region, region_ptr, scale); 41 | } 42 | } 43 | 44 | /// Applies a transform to a region inside a box of size `width` x `height`. 45 | /// Writes the result to `dest`. 46 | pub fn transform( 47 | &self, 48 | dest: &mut PixmanRegion32, 49 | transform: wl_output_transform, 50 | width: c_int, 51 | height: c_int 52 | ) { 53 | unsafe { 54 | let region_ptr = &self.region as *const _ as *mut _; 55 | wlr_region_transform(&mut dest.region, region_ptr, transform, width, height); 56 | } 57 | } 58 | 59 | /// Expands the region of `distance`. If `distance` is negative, it shrinks 60 | /// the region. Writes the result to the `dest`. 61 | pub fn expand(&self, dest: &mut PixmanRegion32, distance: c_int) { 62 | unsafe { 63 | let region_ptr = &self.region as *const _ as *mut _; 64 | wlr_region_expand(&mut dest.region, region_ptr, distance); 65 | } 66 | } 67 | 68 | /// Builds the smallest possible region that contains the region rotated 69 | /// about the point in output space (ox, oy). 70 | /// Writes the result to the `dest`. 71 | pub fn rotated_bounds(&self, dest: &mut PixmanRegion32, rotation: c_float, ox: c_int, oy: c_int) { 72 | unsafe { 73 | let region_ptr = &self.region as *const _ as *mut _; 74 | wlr_region_rotated_bounds(&mut dest.region, region_ptr, rotation, ox, oy); 75 | } 76 | } 77 | 78 | /// Confines a region to the box formed by the points. 79 | /// 80 | /// If it could not be confined by the points it will return an error. 81 | pub fn confine( 82 | &mut self, 83 | x1: c_double, 84 | y1: c_double, 85 | x2: c_double, 86 | y2: c_double 87 | ) -> Result<(c_double, c_double), ()> { 88 | unsafe { 89 | let (mut x_out, mut y_out) = (0.0, 0.0); 90 | let res = wlr_region_confine(&mut self.region, x1, y1, x2, y2, &mut x_out, &mut y_out); 91 | if res { 92 | Ok((x_out, y_out)) 93 | } else { 94 | Err(()) 95 | } 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/utils/string.rs: -------------------------------------------------------------------------------- 1 | //! As a wrapper for a C library wlroots needs to do a lot of conversion between 2 | //! Rust strings (e.g UTF-8 strings) and C strings (e.g. NULL terminated bytes). 3 | 4 | use std::{ 5 | ffi::{CStr, CString}, 6 | os::raw::c_char, 7 | process::exit 8 | }; 9 | 10 | /// Converts a C string into a Rust string without error handling. 11 | /// The pointer passed to this function _must_ be valid. 12 | pub unsafe fn c_to_rust_string(c_str: *const c_char) -> Option { 13 | if c_str.is_null() { 14 | None 15 | } else { 16 | Some(CStr::from_ptr(c_str).to_string_lossy().into_owned()) 17 | } 18 | } 19 | 20 | /// Converts a Rust string into C string without error handling. 21 | /// If any error occurs, it is logged and then the program is immediantly 22 | /// aborted. 23 | pub fn safe_as_cstring(string: S) -> CString 24 | where 25 | S: Into> 26 | { 27 | match CString::new(string) { 28 | Ok(string) => string, 29 | Err(err) => { 30 | wlr_log!( 31 | WLR_ERROR, 32 | "Error occured while trying to convert a Rust string to a C string {:?}", 33 | err 34 | ); 35 | exit(1) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/utils/time.rs: -------------------------------------------------------------------------------- 1 | //! Timing is important for compositors and clients to know when to render 2 | //! frames. Most of these functions will be used for that purpose. 3 | 4 | use std::time::Duration; 5 | 6 | use crate::libc::{clock_gettime, timespec, CLOCK_MONOTONIC}; 7 | 8 | /// Trait to convert something to milliseconds. 9 | /// 10 | /// Used primarily to convert a `std::time::Duration` into 11 | /// something usable by wlroots 12 | pub trait ToMs { 13 | /// Convert the time to a millisecond representation. 14 | /// 15 | /// This conversion should be lossless. 16 | fn to_ms(self) -> u32; 17 | } 18 | 19 | impl ToMs for Duration { 20 | fn to_ms(self) -> u32 { 21 | let seconds_delta = self.as_secs() as u32; 22 | let mili_delta = self.subsec_millis(); 23 | (seconds_delta * 1000) + mili_delta 24 | } 25 | } 26 | 27 | /// Get the current time as a duration suitable for functions such as 28 | /// `surface.send_frame_done()`. 29 | pub fn current_time() -> Duration { 30 | unsafe { 31 | let mut ts = timespec { 32 | tv_sec: 0, 33 | tv_nsec: 0 34 | }; 35 | clock_gettime(CLOCK_MONOTONIC, &mut ts); 36 | Duration::new(ts.tv_sec as u64, ts.tv_nsec as u32) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/xwayland/hints.rs: -------------------------------------------------------------------------------- 1 | use std::marker::PhantomData; 2 | 3 | use crate::libc::{int32_t, uint32_t}; 4 | use wlroots_sys::{wlr_xwayland_surface_hints, wlr_xwayland_surface_size_hints}; 5 | 6 | use crate::xwayland; 7 | 8 | /// Hints provided by the XWayland client to aid in compositing. 9 | pub struct Hints<'surface> { 10 | hints: *mut wlr_xwayland_surface_hints, 11 | phantom: PhantomData<&'surface xwayland::surface::Surface> 12 | } 13 | 14 | /// Hints provided by the XWayland client to aid in compositing specifically 15 | /// for placement. 16 | pub struct SizeHints<'surface> { 17 | hints: *mut wlr_xwayland_surface_size_hints, 18 | phantom: PhantomData<&'surface xwayland::surface::Surface> 19 | } 20 | 21 | impl<'surface> Hints<'surface> { 22 | pub(crate) unsafe fn from_ptr(hints: *mut wlr_xwayland_surface_hints) -> Self { 23 | Hints { 24 | hints, 25 | phantom: PhantomData 26 | } 27 | } 28 | 29 | pub fn flags(&self) -> uint32_t { 30 | unsafe { (*self.hints).flags } 31 | } 32 | 33 | pub fn input(&self) -> uint32_t { 34 | unsafe { (*self.hints).input } 35 | } 36 | 37 | pub fn initial_state(&self) -> int32_t { 38 | unsafe { (*self.hints).initial_state } 39 | } 40 | 41 | pub unsafe fn icon_pixmap(&self) -> u32 { 42 | (*self.hints).icon_pixmap 43 | } 44 | 45 | pub unsafe fn icon_window(&self) -> u32 { 46 | (*self.hints).icon_window 47 | } 48 | 49 | /// Get the coordinates of the icon. 50 | /// 51 | /// Return format is (x, y). 52 | pub fn icon_coords(&self) -> (int32_t, int32_t) { 53 | unsafe { ((*self.hints).icon_x, (*self.hints).icon_y) } 54 | } 55 | 56 | pub unsafe fn icon_mask(&self) -> u32 { 57 | (*self.hints).icon_mask 58 | } 59 | 60 | pub unsafe fn window_group(&self) -> u32 { 61 | (*self.hints).window_group 62 | } 63 | } 64 | 65 | impl<'surface> SizeHints<'surface> { 66 | pub(crate) unsafe fn from_ptr(hints: *mut wlr_xwayland_surface_size_hints) -> Self { 67 | SizeHints { 68 | hints, 69 | phantom: PhantomData 70 | } 71 | } 72 | 73 | /// Get the flags associated with the surface size. 74 | pub fn flags(&self) -> uint32_t { 75 | unsafe { (*self.hints).flags } 76 | } 77 | 78 | /// Get the coordinates of the surface. 79 | /// 80 | /// Return format is (x, y). 81 | pub fn coords(&self) -> (int32_t, int32_t) { 82 | unsafe { ((*self.hints).x, (*self.hints).y) } 83 | } 84 | 85 | /// Get the dimensions of the surface. 86 | /// 87 | /// Return format is (width, height). 88 | pub fn dimensions(&self) -> (int32_t, int32_t) { 89 | unsafe { ((*self.hints).width, (*self.hints).height) } 90 | } 91 | 92 | /// Get the minimal allowed dimensions of the surface. 93 | /// 94 | /// Return format is (width, height). 95 | pub fn min_dimensions(&self) -> (int32_t, int32_t) { 96 | unsafe { ((*self.hints).min_width, (*self.hints).min_height) } 97 | } 98 | 99 | /// Get the maximal allowed dimensions of the surface. 100 | /// 101 | /// Return format is (width, height). 102 | pub fn max_dimensions(&self) -> (int32_t, int32_t) { 103 | unsafe { ((*self.hints).max_width, (*self.hints).max_height) } 104 | } 105 | 106 | /// TODO What is this 107 | /// 108 | /// Return format is (width, height). 109 | pub fn inc_dimensions(&self) -> (int32_t, int32_t) { 110 | unsafe { ((*self.hints).width_inc, (*self.hints).height_inc) } 111 | } 112 | 113 | /// TODO What is this 114 | /// 115 | /// Return format is (width, height). 116 | pub fn base_dimensions(&self) -> (int32_t, int32_t) { 117 | unsafe { ((*self.hints).base_width, (*self.hints).base_height) } 118 | } 119 | 120 | pub fn min_aspect_num(&self) -> int32_t { 121 | unsafe { (*self.hints).min_aspect_num } 122 | } 123 | 124 | pub fn min_aspect_den(&self) -> int32_t { 125 | unsafe { (*self.hints).min_aspect_den } 126 | } 127 | 128 | pub fn max_aspect_num(&self) -> int32_t { 129 | unsafe { (*self.hints).max_aspect_num } 130 | } 131 | 132 | pub fn max_aspect_den(&self) -> int32_t { 133 | unsafe { (*self.hints).max_aspect_den } 134 | } 135 | 136 | pub fn win_gravity(&self) -> uint32_t { 137 | unsafe { (*self.hints).win_gravity } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/xwayland/manager.rs: -------------------------------------------------------------------------------- 1 | //! XWayland client resources are managed by the XWayland resource manager 2 | //! and server. 3 | //! 4 | //! To manage XWayland clients (and run an XServer) implement a function 5 | //! with [`NewSurface`](./type.NewSurface.html) as the signature. 6 | //! 7 | //! Pass that function to the [`xwayland::Builder`](./struct.Builder.html) 8 | //! which is then passed to the `compositor::Builder`. 9 | 10 | use std::ptr::NonNull; 11 | 12 | use crate::libc; 13 | use crate::wayland_sys::server::signal::wl_signal_add; 14 | use wlroots_sys::wlr_xwayland_surface; 15 | 16 | use crate::{compositor, utils::Handleable, xwayland}; 17 | 18 | /// Callback that's triggered when the XWayland library is ready. 19 | pub type OnReady = fn(compositor::Handle); 20 | 21 | /// Callback that's triggered when a new surface is presented to the X 22 | /// server. 23 | pub type NewSurface = fn( 24 | compositor_handle: compositor::Handle, 25 | xwayland_surface: xwayland::surface::Handle 26 | ) -> Option>; 27 | 28 | wayland_listener_static! { 29 | static mut MANAGER; 30 | (Manager, Builder): [ 31 | (OnReady, on_ready_listener, xwayland_ready) => (ready_notify, xwayland_ready): 32 | |manager: &mut Manager, _data: *mut libc::c_void,| 33 | unsafe { 34 | let compositor = match compositor::handle() { 35 | Some(handle) => handle, 36 | None => return 37 | }; 38 | 39 | if let Some(xwayland_ready) = manager.xwayland_ready { 40 | xwayland_ready(compositor) 41 | } 42 | }; 43 | 44 | (NewSurface, new_surface_listener, surface_added) => (add_notify, surface_added): 45 | |manager: &mut Manager, data: *mut libc::c_void,| 46 | unsafe { 47 | let surface_ptr = data as *mut wlr_xwayland_surface; 48 | let compositor = match compositor::handle() { 49 | Some(handle) => handle, 50 | None => return 51 | }; 52 | let shell_surface = xwayland::surface::Surface::new(surface_ptr); 53 | let xwayland_handler = manager.surface_added 54 | .and_then(|f| f(compositor, shell_surface.weak_reference())); 55 | let mut shell = xwayland::surface::Shell::new((shell_surface, xwayland_handler)); 56 | 57 | wl_signal_add(&mut (*surface_ptr).events.destroy as *mut _ as _, 58 | shell.destroy_listener() as *mut _ as _); 59 | wl_signal_add(&mut (*surface_ptr).events.request_configure as *mut _ as _, 60 | shell.request_configure_listener() as *mut _ as _); 61 | wl_signal_add(&mut (*surface_ptr).events.request_move as *mut _ as _, 62 | shell.request_move_listener() as *mut _ as _); 63 | wl_signal_add(&mut (*surface_ptr).events.request_resize as *mut _ as _, 64 | shell.request_resize_listener() as *mut _ as _); 65 | wl_signal_add(&mut (*surface_ptr).events.request_maximize as *mut _ as _, 66 | shell.request_maximize_listener() as *mut _ as _); 67 | wl_signal_add(&mut (*surface_ptr).events.request_fullscreen as *mut _ as _, 68 | shell.request_fullscreen_listener() as *mut _ as _); 69 | wl_signal_add(&mut (*surface_ptr).events.map as *mut _ as _, 70 | shell.map_listener() as *mut _ as _); 71 | wl_signal_add(&mut (*surface_ptr).events.unmap as *mut _ as _, 72 | shell.unmap_listener() as *mut _ as _); 73 | wl_signal_add(&mut (*surface_ptr).events.set_title as *mut _ as _, 74 | shell.set_title_listener() as *mut _ as _); 75 | wl_signal_add(&mut (*surface_ptr).events.set_class as *mut _ as _, 76 | shell.set_class_listener() as *mut _ as _); 77 | wl_signal_add(&mut (*surface_ptr).events.set_parent as *mut _ as _, 78 | shell.set_parent_listener() as *mut _ as _); 79 | wl_signal_add(&mut (*surface_ptr).events.set_pid as *mut _ as _, 80 | shell.set_pid_listener() as *mut _ as _); 81 | wl_signal_add(&mut (*surface_ptr).events.set_window_type as *mut _ as _, 82 | shell.set_window_type_listener() as *mut _ as _); 83 | wl_signal_add(&mut (*surface_ptr).events.ping_timeout as *mut _ as _, 84 | shell.ping_timeout_listener() as *mut _ as _); 85 | let shell_data = (*surface_ptr).data as *mut xwayland::surface::State; 86 | (*shell_data).shell = NonNull::new(Box::into_raw(shell)); 87 | // TODO Pass in the new surface from the data 88 | }; 89 | ] 90 | } 91 | -------------------------------------------------------------------------------- /src/xwayland/mod.rs: -------------------------------------------------------------------------------- 1 | pub(crate) mod hints; 2 | pub mod manager; 3 | mod server; 4 | pub mod surface; 5 | 6 | pub use self::server::*; 7 | pub use crate::events::xwayland_events as event; 8 | -------------------------------------------------------------------------------- /src/xwayland/server.rs: -------------------------------------------------------------------------------- 1 | use crate::libc::c_int; 2 | use crate::wayland_sys::server::signal::wl_signal_add; 3 | use wlroots_sys::{ 4 | pid_t, wl_client, wl_display, wlr_compositor, wlr_xwayland, wlr_xwayland_create, wlr_xwayland_destroy, 5 | wlr_xwayland_set_cursor 6 | }; 7 | 8 | use crate::xwayland; 9 | 10 | #[allow(dead_code)] 11 | pub struct Server { 12 | xwayland: *mut wlr_xwayland, 13 | manager: &'static mut xwayland::manager::Manager 14 | } 15 | 16 | impl Server { 17 | pub(crate) unsafe fn new( 18 | display: *mut wl_display, 19 | compositor: *mut wlr_compositor, 20 | builder: xwayland::manager::Builder, 21 | lazy: bool 22 | ) -> Self { 23 | let xwayland = wlr_xwayland_create(display, compositor, lazy); 24 | if xwayland.is_null() { 25 | panic!("Could not start XWayland server") 26 | } 27 | let manager = xwayland::manager::Manager::build(builder); 28 | wl_signal_add( 29 | &mut (*xwayland).events.ready as *mut _ as _, 30 | (&mut manager.on_ready_listener) as *mut _ as _ 31 | ); 32 | wl_signal_add( 33 | &mut (*xwayland).events.new_surface as *mut _ as _, 34 | (&mut manager.new_surface_listener) as *mut _ as _ 35 | ); 36 | Server { xwayland, manager } 37 | } 38 | 39 | /// Get the PID of the XWayland server. 40 | pub fn pid(&self) -> pid_t { 41 | unsafe { (*self.xwayland).pid } 42 | } 43 | 44 | pub fn display(&self) -> c_int { 45 | unsafe { (*self.xwayland).display } 46 | } 47 | 48 | pub fn x_fd(&self) -> [c_int; 2] { 49 | unsafe { (*self.xwayland).x_fd } 50 | } 51 | 52 | pub fn wl_fd(&self) -> [c_int; 2] { 53 | unsafe { (*self.xwayland).wl_fd } 54 | } 55 | 56 | pub fn wm_fd(&self) -> [c_int; 2] { 57 | unsafe { (*self.xwayland).wm_fd } 58 | } 59 | 60 | pub fn wl_client(&self) -> *mut wl_client { 61 | unsafe { (*self.xwayland).client } 62 | } 63 | 64 | pub fn set_cursor( 65 | &mut self, 66 | bytes: &mut [u8], 67 | stride: u32, 68 | width: u32, 69 | height: u32, 70 | hotspot_x: i32, 71 | hotspot_y: i32 72 | ) { 73 | unsafe { 74 | wlr_xwayland_set_cursor( 75 | self.xwayland, 76 | bytes.as_mut_ptr(), 77 | stride, 78 | width, 79 | height, 80 | hotspot_x, 81 | hotspot_y 82 | ) 83 | } 84 | } 85 | } 86 | 87 | impl Drop for Server { 88 | fn drop(&mut self) { 89 | unsafe { wlr_xwayland_destroy(self.xwayland) } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /wlroots-dehandle/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wlroots-dehandle" 3 | version = "2.0.0" 4 | authors = ["Timidger "] 5 | description = "Procedural macro to upgrade wlroots handles without callback hell" 6 | license = "MIT" 7 | 8 | [lib] 9 | proc-macro = true 10 | 11 | [dependencies] 12 | syn = { version = "0.15", features = ["full", "fold"] } 13 | quote = "0.6" 14 | proc-macro2 = "0.4" 15 | -------------------------------------------------------------------------------- /wlroots-sys/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wlroots-sys" 3 | version = "0.4.0" 4 | authors = ["Timidger "] 5 | description = "Bindgen generated low-level wlroots wrapper" 6 | keywords = ["wayland", "compositor", "bindings"] 7 | categories = ["external-ffi-bindings"] 8 | license = "MIT" 9 | exclude = ["wlroots/.travis.yml"] 10 | 11 | build = "build.rs" 12 | 13 | [build-dependencies] 14 | bindgen = "0.30.*" 15 | meson = { version = "1.0", optional = true } 16 | wayland-scanner = "0.21.*" 17 | # For building optional dependencies 18 | pkg-config = "0.3.*" 19 | 20 | [dependencies] 21 | libc = "^0.2.*" 22 | wayland-commons = { version = "0.21.*", features = ["native_lib"] } 23 | wayland-server = { version = "0.21.*", features = ["native_lib"] } 24 | wayland-sys = { version = "0.21.*", features = ["dlopen", "server"] } 25 | 26 | [features] 27 | default = ["libcap", "systemd", "elogind", "xwayland", "x11_backend"] 28 | static = ["meson"] 29 | libcap = [] 30 | systemd = [] 31 | elogind = [] 32 | x11_backend = [] 33 | xwayland = [] 34 | xcb_errors = [] 35 | xcb_icccm = [] 36 | unstable = [] 37 | -------------------------------------------------------------------------------- /wlroots-sys/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_camel_case_types, non_upper_case_globals)] 2 | #![allow(clippy::all)] 3 | 4 | pub extern crate libc; 5 | pub extern crate wayland_commons; 6 | pub extern crate wayland_server; 7 | #[macro_use] 8 | pub extern crate wayland_sys; 9 | 10 | pub use wayland_sys::{ 11 | gid_t, pid_t, 12 | server::{self, WAYLAND_SERVER_HANDLE}, 13 | uid_t, * 14 | }; 15 | 16 | #[allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] 17 | mod generated { 18 | use libc; 19 | include!("gen.rs"); 20 | 21 | // XXX: If you add another protocols, take a look at wayland_protocol! macro 22 | // from `wayland-rs/wayland-protocols/src/protocol_macro.rs`. 23 | pub mod protocols { 24 | pub mod server_decoration { 25 | #![allow(unused_imports)] 26 | #![allow(unused_variables)] 27 | mod c_interfaces { 28 | use wayland_server::sys::protocol_interfaces::wl_surface_interface; 29 | include!(concat!(env!("OUT_DIR"), "/server_decoration_interfaces.rs")); 30 | } 31 | 32 | pub mod server { 33 | pub(crate) use wayland_commons::{ 34 | map::{Object, ObjectMetadata}, 35 | wire::{Argument, ArgumentType, Message, MessageDesc}, 36 | AnonymousObject, Interface, MessageGroup 37 | }; 38 | use wayland_server::{protocol::wl_surface, *}; 39 | pub(crate) use wayland_server::{NewResource, Resource}; 40 | pub(crate) use wayland_sys as sys; 41 | use wayland_sys::common::{wl_argument, wl_interface}; 42 | include!(concat!(env!("OUT_DIR"), "/server_decoration_server_api.rs")); 43 | } 44 | } 45 | pub mod idle { 46 | #![allow(unused_imports)] 47 | #![allow(unused_variables)] 48 | mod c_interfaces { 49 | use wayland_server::sys::protocol_interfaces::wl_seat_interface; 50 | include!(concat!(env!("OUT_DIR"), "/idle_interfaces.rs")); 51 | } 52 | 53 | pub mod server { 54 | pub(crate) use wayland_commons::{ 55 | map::{Object, ObjectMetadata}, 56 | wire::{Argument, ArgumentType, Message, MessageDesc}, 57 | AnonymousObject, Interface, MessageGroup 58 | }; 59 | use wayland_server::{protocol::wl_seat, *}; 60 | pub(crate) use wayland_server::{NewResource, Resource}; 61 | pub(crate) use wayland_sys as sys; 62 | use wayland_sys::common::{wl_argument, wl_interface}; 63 | include!(concat!(env!("OUT_DIR"), "/idle_server_api.rs")); 64 | } 65 | } 66 | 67 | } 68 | } 69 | pub use self::generated::*; 70 | 71 | #[cfg(feature = "unstable")] 72 | pub type wlr_output_events = self::generated::wlr_output__bindgen_ty_1; 73 | #[cfg(feature = "unstable")] 74 | pub type wlr_input_device_pointer = self::generated::wlr_input_device__bindgen_ty_1; 75 | 76 | #[cfg(feature = "unstable")] 77 | impl wl_output_transform { 78 | /// Returns the transform that, when composed with `self`, gives 79 | /// `WL_OUTPUT_TRANSFORM_NORMAL`. 80 | pub fn invert(self) -> Self { 81 | unsafe { wlr_output_transform_invert(self) } 82 | } 83 | 84 | /// Returns a transform that, when applied, has the same effect as applying 85 | /// sequentially `self` and `other`. 86 | pub fn compose(self, other: Self) -> Self { 87 | unsafe { wlr_output_transform_compose(self, other) } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /wlroots-sys/src/wlroots.h: -------------------------------------------------------------------------------- 1 | // Stable interfaces 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | 11 | #ifdef WLR_USE_UNSTABLE 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | // NOTE this is stable, but it relies on wlr_box.h which isn't 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | 64 | #include 65 | #include 66 | #include 67 | 68 | #endif 69 | --------------------------------------------------------------------------------