├── .gitignore ├── .travis.yml ├── Cargo.toml ├── README.md ├── build.rs ├── examples └── simple.rs └── src ├── callback.rs ├── dummy_callback.rs ├── dummy_handle.rs ├── dummy_input.rs ├── dummy_wayland.rs ├── handle.rs ├── input.rs ├── lib.rs ├── render.rs ├── types.rs ├── wayland.rs └── xkb ├── convert.lua ├── keysyms.rs ├── mod.rs └── tests.rs /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | /target/ 3 | /example/target/ 4 | *.bk -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | matrix: 7 | allow_failures: 8 | - rust: nightly 9 | notifications: 10 | email: false 11 | slack: way-cooler:bf5hNqMVmTgFpHo3a3vgZ4Lu 12 | script: cargo build --verbose 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustwlc" 3 | description = "wlc Wayland library bindings for Rust" 4 | version = "0.7.0" 5 | repository = "https://github.com/Immington-Industries/rust-wlc/" 6 | keywords = ["wlc", "Wayland", "compositor", "bindings"] 7 | readme = "README.md" 8 | license = "MIT" 9 | authors = ["Snirk Immington ", "Timidger "] 10 | build = "build.rs" 11 | 12 | [features] 13 | wlc-wayland = ["wayland-sys"] 14 | static-wlc = [] 15 | dummy = [] 16 | 17 | [dependencies] 18 | libc = "0.2" 19 | bitflags = "0.7" 20 | wayland-sys = { version = "^0.6.0", optional = true, features = ["server"] } 21 | 22 | [dev-dependencies] 23 | lazy_static = "0.2" 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-wlc 2 | 3 | [![Join the chat at https://gitter.im/Immington-Industries/rust-wlc](https://badges.gitter.im/Immington-Industries/rust-wlc.svg)](https://gitter.im/Immington-Industries/rust-wlc?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | [![Crates.io](https://img.shields.io/crates/v/rustwlc.svg)](https://crates.io/crate/rustwlc) 5 | [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Immington-Industries/rust-wlc/) 6 | 7 | Rust bindings for [wlc](https://github.com/Cloudef/wlc), the Wayland compositor library. 8 | 9 | **It is suggested you use the much better designed [wlc.rs](https://github.com/Drakulix/wlc.rs), this is used primarily for Way Cooler development** 10 | 11 | Bindings are compatable with [wlc](https://github.com/Cloudef/wlc) v0.0.9 12 | 13 | ### Rust Example 14 | 15 | ```rust 16 | // For more functional example see example/src/main.rs 17 | 18 | extern crate rustwlc; 19 | use rustwlc::types::*; 20 | use rustwlc::callback; 21 | use rustwlc::WlcView; 22 | 23 | // Callbacks must be labeled extern as they will be called from C 24 | extern "C" fn view_created(view: WlcView) -> bool { 25 | view.bring_to_front(); 26 | view.focus(); 27 | return true; 28 | } 29 | 30 | extern "C" fn view_focus(view: WlcView, focused: bool) { 31 | view.set_state(VIEW_ACTIVATED, focused); 32 | } 33 | 34 | fn main() { 35 | callback::view_created(view_created); 36 | callback::view_focus(view_focus); 37 | 38 | // The default log handler will print wlc logs to stdout 39 | rustwlc::log_set_default_handler(); 40 | let run_fn = rustwlc::init().expect("Unable to initialize!"); 41 | run_fn(); 42 | } 43 | ``` 44 | 45 | ### Usage 46 | We're on [crates.io](https://crates.io/crates/rustwlc), so to use the library simply add: 47 | 48 | ```toml 49 | [dependencies] 50 | rustwlc = "0.5" 51 | ``` 52 | to your Cargo.toml. 53 | 54 | You also need to setup the wlc library so that rust-wlc can see it. If you simply install the library, that will be sufficient. 55 | 56 | Note that wlc is prone to backwards-incompatable changes. Whenever this happens we bump a minor version, so make sure to specify the exact minor version in your `Cargo.toml`. We expect our version numbers to keep drifing away from each other until wlc stabilizes. Please be careful as updating wlc could break rustwlc. We will try to stay as close to upstream as possible. 57 | 58 | If you are looking to use a custom version of wlc (to ensure compatiblity by building against a specific version or to build the library with debug symbols for example), then you simply need to set the `LD_LIBRARY_PATH` environment variable to the full path of the share library object file (.so). To verify that the correct shared library is seen by rust-wlc, use the `ldd` utility to view the full paths of shared libraries, the entry that starts with "libwlc.so" should point to your custom path. 59 | 60 | So if you wlc install is at `/opt/wlc`, then the full path will probably be `/opt/wlc/target/src`. Notice that we only include the directory that containts the .so, not the .so itself. For more information on using DLLs in Linux, see [this link](http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN77). 61 | 62 | ### Documentation 63 | At the moment, we have Cargo documentation hosted at [doc.rs](https://docs.rs/rustwlc/0.5.6/rustwlc). 64 | You can also generate it with cargo doc: 65 | ```shell 66 | $ git clone "https://github.com/ImmingtonIndustries/rust-wlc.git" 67 | $ cd rust-wlc 68 | $ cargo doc 69 | ``` 70 | If the documentation isn't clear enough or in the wrong places, please let us know. 71 | 72 | ### Safety 73 | `rust-wlc` is written to be a clean Rust wrapper around wlc. While we've taken the liberty to make the code more Rust-friendly (such as creating instance methods for `WlcView` and `WlcOutput`), but we do not try to extend wlc itself. 74 | 75 | The callbacks registered in `callbacks` must be labeled `extern` (or `extern "C"`) because they are called from C code. In addition, as per the Rust spec, panicking from C is undefined behavior (although it's worked for us). 76 | 77 | Compositors using rustwlc can do so without any `unsafe` code. We have provided the option to use a Rust callback to handle logging (instead of a method taking in a `*const c_char`). There is also `println!`-powered default enabled with `rustwlc::log_set_default_handler()`. In addition, the methods `get_user_data` and `set_user_data` in `WlcView` and `WlcOutput` are unsafe because they use C raw types (`void*`) underneath, and proper usage requires a deeper understanding of wlc itself. 78 | 79 | We have some (WIP) Wayland bindings using the `wayland-sys` crate which can be enabled with the `wlc-wayland` feature. This allows access to Wayland from wlc using the Rust crate `wayland-sys`. This is not a requirement for a basic compositor, however, for some complex features (we used it to directly draw backgrounds onto a view in way-cooler) it may be needed. 80 | 81 | ## Contributing 82 | We accept pull requests! If you find a bug or would like to contribute (wlc isn't versioned, we may be a few commits behind their API) please submit an issue/pull request. 83 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | 3 | fn main() { 4 | if env::var("CARGO_FEATURE_STATIC_WLC").is_ok() { 5 | println!("cargo:rustc-link-search=/usr/local/lib"); 6 | println!("cargo:rustc-link-search=/usr/local/lib64"); 7 | println!("cargo:rustc-link-search=/lib64"); 8 | println!("cargo:rustc-link-search=native=/lib64"); 9 | println!("cargo:rustc-link-lib=dylib=wayland-client"); 10 | println!("cargo:rustc-link-lib=dylib=wayland-server"); 11 | println!("cargo:rustc-link-lib=dylib=systemd"); 12 | println!("cargo:rustc-link-lib=dylib=input"); 13 | println!("cargo:rustc-link-lib=dylib=udev"); 14 | println!("cargo:rustc-link-lib=dylib=GLESv2"); 15 | println!("cargo:rustc-link-lib=dylib=drm"); 16 | println!("cargo:rustc-link-lib=dylib=gbm"); 17 | println!("cargo:rustc-link-lib=dylib=xcb"); 18 | println!("cargo:rustc-link-lib=dylib=xcb-composite"); 19 | println!("cargo:rustc-link-lib=dylib=xcb-ewmh"); 20 | println!("cargo:rustc-link-lib=dylib=xcb-xkb"); 21 | println!("cargo:rustc-link-lib=dylib=xcb-image"); 22 | println!("cargo:rustc-link-lib=dylib=xcb-xfixes"); 23 | println!("cargo:rustc-link-lib=dylib=pixman-1"); 24 | println!("cargo:rustc-link-lib=dylib=X11"); 25 | println!("cargo:rustc-link-lib=dylib=X11-xcb"); 26 | println!("cargo:rustc-link-lib=dylib=EGL"); 27 | println!("cargo:rustc-link-search=native=/usr/include"); 28 | println!("cargo:rustc-link-lib=static=chck-atlas"); 29 | println!("cargo:rustc-link-lib=static=chck-pool"); 30 | println!("cargo:rustc-link-lib=static=chck-buffer"); 31 | println!("cargo:rustc-link-lib=static=chck-buffer"); 32 | println!("cargo:rustc-link-lib=static=chck-dl"); 33 | println!("cargo:rustc-link-lib=static=chck-fs"); 34 | println!("cargo:rustc-link-lib=static=chck-lut"); 35 | println!("cargo:rustc-link-lib=static=chck-pool"); 36 | println!("cargo:rustc-link-lib=static=chck-sjis" ); 37 | println!("cargo:rustc-link-lib=static=chck-string"); 38 | println!("cargo:rustc-link-lib=static=chck-tqueue"); 39 | println!("cargo:rustc-link-lib=static=chck-unicode"); 40 | println!("cargo:rustc-link-lib=static=chck-xdg"); 41 | println!("cargo:rustc-link-lib=static=wlc-protos"); 42 | println!("cargo:rustc-link-lib=static=wlc"); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /examples/simple.rs: -------------------------------------------------------------------------------- 1 | use std::sync::RwLock; 2 | 3 | #[macro_use] 4 | extern crate lazy_static; 5 | 6 | extern crate rustwlc; 7 | 8 | use rustwlc::*; 9 | use rustwlc::xkb::keysyms; 10 | 11 | use std::cmp; 12 | 13 | struct Compositor { 14 | pub view: Option, 15 | pub grab: Point, 16 | pub edges: ResizeEdge 17 | } 18 | 19 | lazy_static! { 20 | static ref COMPOSITOR: RwLock = 21 | RwLock::new(Compositor { view: None, 22 | grab: Point { x: 0, y: 0 }, 23 | edges: ResizeEdge::empty() }); 24 | } 25 | 26 | fn start_interactive_action(view: WlcView, origin: Point) -> bool { 27 | let mut comp = COMPOSITOR.write().unwrap(); 28 | if comp.view != None { 29 | return false 30 | } 31 | comp.grab = origin; 32 | comp.view = Some(view); 33 | 34 | view.bring_to_front(); 35 | return true 36 | } 37 | 38 | fn start_interactive_move(view: WlcView, origin: Point) { 39 | start_interactive_action(view, origin); 40 | } 41 | 42 | fn start_interactive_resize(view: WlcView, edges: ResizeEdge, origin: Point) { 43 | let geometry = match view.get_geometry() { 44 | None => { return; } 45 | Some(g) => g, 46 | }; 47 | 48 | if !start_interactive_action(view, origin) { 49 | return; 50 | } 51 | let halfw = geometry.origin.x + geometry.size.w as i32 / 2; 52 | let halfh = geometry.origin.y + geometry.size.h as i32 / 2; 53 | 54 | { 55 | let mut comp = COMPOSITOR.write().unwrap(); 56 | comp.edges = edges; 57 | if comp.edges.bits() == 0 { 58 | let flag_x = if origin.x < halfw { 59 | RESIZE_LEFT 60 | } else if origin.x > halfw { 61 | RESIZE_RIGHT 62 | } else { 63 | ResizeEdge::empty() 64 | }; 65 | 66 | let flag_y = if origin.y < halfh { 67 | RESIZE_TOP 68 | } else if origin.y > halfh { 69 | RESIZE_BOTTOM 70 | } else { 71 | ResizeEdge::empty() 72 | }; 73 | 74 | comp.edges = flag_x | flag_y; 75 | } 76 | } 77 | view.set_state(VIEW_RESIZING, true); 78 | } 79 | 80 | fn stop_interactive_action() { 81 | let mut comp = COMPOSITOR.write().unwrap(); 82 | 83 | match comp.view { 84 | None => return, 85 | Some(ref view) => 86 | view.set_state(VIEW_RESIZING, false) 87 | } 88 | 89 | comp.view = None; 90 | comp.edges = ResizeEdge::empty(); 91 | } 92 | 93 | fn get_topmost_view(output: WlcOutput, offset: usize) -> Option { 94 | let views = output.get_views(); 95 | if views.is_empty() { None } 96 | else { 97 | Some(views[(views.len() - 1 + offset) % views.len()]) 98 | } 99 | } 100 | 101 | fn render_output(output: WlcOutput) { 102 | let resolution = output.get_resolution().unwrap(); 103 | let views = output.get_views(); 104 | if views.is_empty() { return; } 105 | 106 | let mut toggle = false; 107 | let mut y = 0; 108 | let w = resolution.w / 2; 109 | let h = resolution.h / cmp::max((views.len() + 1) / 2, 1) as u32; 110 | for (i, view) in views.iter().enumerate() { 111 | view.set_geometry(ResizeEdge::empty(), Geometry { 112 | origin: Point { x: if toggle { w as i32 } else { 0 }, y: y }, 113 | size: Size { w: if !toggle && i == views.len() - 1 { resolution.w } else { w }, h: h } 114 | }); 115 | y += if toggle { h as i32 } else { 0 }; 116 | toggle ^= true; 117 | } 118 | } 119 | 120 | // Handles 121 | 122 | extern fn on_output_resolution(output: WlcOutput, _from: &Size, _to: &Size) { 123 | render_output(output); 124 | } 125 | 126 | extern fn on_view_created(view: WlcView) -> bool { 127 | view.set_mask(view.get_output().get_mask()); 128 | view.bring_to_front(); 129 | view.focus(); 130 | render_output(view.get_output()); 131 | true 132 | } 133 | 134 | extern fn on_view_destroyed(view: WlcView) { 135 | if let Some(top_view) = get_topmost_view(view.get_output(), 0) { 136 | top_view.focus(); 137 | } 138 | render_output(view.get_output()); 139 | } 140 | 141 | extern fn on_view_focus(view: WlcView, focused: bool) { 142 | view.set_state(VIEW_ACTIVATED, focused); 143 | } 144 | 145 | extern fn on_view_request_move(view: WlcView, origin: &Point) { 146 | start_interactive_move(view, *origin); 147 | } 148 | 149 | extern fn on_view_request_resize(view: WlcView, edges: ResizeEdge, origin: &Point) { 150 | start_interactive_resize(view, edges, *origin); 151 | } 152 | 153 | extern fn on_keyboard_key(view: WlcView, _time: u32, mods: &KeyboardModifiers, key: u32, state: KeyState) -> bool { 154 | use std::process::Command; 155 | let sym = input::keyboard::get_keysym_for_key(key, *mods); 156 | if state == KeyState::Pressed { 157 | if mods.mods == MOD_CTRL { 158 | // Key Q 159 | if sym == keysyms::KEY_q { 160 | if !view.is_root() { 161 | view.close(); 162 | } 163 | return true; 164 | // Down key 165 | } else if sym == keysyms::KEY_Down { 166 | view.send_to_back(); 167 | get_topmost_view(view.get_output(), 0).unwrap().focus(); 168 | return true; 169 | // Esc Key 170 | } else if sym == keysyms::KEY_Escape { 171 | terminate(); 172 | return true; 173 | // Return key 174 | } else if sym == keysyms::KEY_Return { 175 | let _ = Command::new("sh") 176 | .arg("-c") 177 | .arg("/usr/bin/weston-terminal || echo a").spawn() 178 | .unwrap_or_else(|e| { 179 | println!("Error spawning child: {}", e); panic!("spawning child")}); 180 | return true; 181 | } else if sym.raw() >= keysyms::KEY_1.raw() && sym.raw() <= keysyms::KEY_9.raw() { 182 | let outputs = WlcOutput::list(); 183 | let scale = (sym.raw() - keysyms::KEY_1.raw()) + 1; 184 | for output in outputs { 185 | output.set_resolution(output.get_resolution() 186 | .expect("No resolution"), scale); 187 | } 188 | println!("scale: {}", scale); 189 | return true; 190 | } 191 | } 192 | } 193 | return false; 194 | } 195 | 196 | extern fn on_pointer_button(view: WlcView, _time: u32, mods: &KeyboardModifiers, 197 | button: u32, state: ButtonState, point: &Point) -> bool { 198 | if state == ButtonState::Pressed { 199 | if !view.is_root() && mods.mods.contains(MOD_CTRL) { 200 | view.focus(); 201 | if mods.mods.contains(MOD_CTRL) { 202 | // Button left, we need to include linux/input.h somehow 203 | if button == 0x110 { 204 | start_interactive_move(view, *point); 205 | } 206 | if button == 0x111 { 207 | start_interactive_resize(view, ResizeEdge::empty(), *point); 208 | } 209 | } 210 | } 211 | } 212 | else { 213 | stop_interactive_action(); 214 | } 215 | 216 | { 217 | let comp = COMPOSITOR.read().unwrap(); 218 | return comp.view.is_some(); 219 | } 220 | } 221 | extern fn on_pointer_motion(_in_view: WlcView, _time: u32, point: &Point) -> bool { 222 | rustwlc::input::pointer::set_position(*point); 223 | { 224 | let comp = COMPOSITOR.read().unwrap(); 225 | if let Some(ref view) = comp.view { 226 | let dx = point.x - comp.grab.x; 227 | let dy = point.y - comp.grab.y; 228 | let mut geo = view.get_geometry().unwrap(); 229 | if comp.edges.bits() != 0 { 230 | let min = Size { w: 80u32, h: 40u32}; 231 | let mut new_geo = geo; 232 | 233 | if comp.edges.contains(RESIZE_LEFT) { 234 | if dx < 0 { 235 | new_geo.size.w += dx.abs() as u32; 236 | } else { 237 | new_geo.size.w -= dx.abs() as u32; 238 | } 239 | new_geo.origin.x += dx; 240 | } 241 | else if comp.edges.contains(RESIZE_RIGHT) { 242 | if dx < 0 { 243 | new_geo.size.w -= dx.abs() as u32; 244 | } else { 245 | new_geo.size.w += dx.abs() as u32; 246 | } 247 | } 248 | 249 | if comp.edges.contains(RESIZE_TOP) { 250 | if dy < 0 { 251 | new_geo.size.h += dy.abs() as u32; 252 | } else { 253 | new_geo.size.h -= dy.abs() as u32; 254 | } 255 | new_geo.origin.y += dy; 256 | } 257 | else if comp.edges.contains(RESIZE_BOTTOM) { 258 | if dy < 0 { 259 | new_geo.size.h -= dy.abs() as u32; 260 | } else { 261 | new_geo.size.h += dy.abs() as u32; 262 | } 263 | } 264 | 265 | if new_geo.size.w >= min.w { 266 | geo.origin.x = new_geo.origin.x; 267 | geo.size.w = new_geo.size.w; 268 | } 269 | 270 | if new_geo.size.h >= min.h { 271 | geo.origin.y = new_geo.origin.y; 272 | geo.size.h = new_geo.size.h; 273 | } 274 | 275 | view.set_geometry(comp.edges, geo); 276 | } 277 | else { 278 | geo.origin.x += dx; 279 | geo.origin.y += dy; 280 | view.set_geometry(ResizeEdge::empty(), geo); 281 | } 282 | } 283 | } 284 | 285 | { 286 | let mut comp = COMPOSITOR.write().unwrap(); 287 | comp.grab = *point; 288 | return comp.view.is_some(); 289 | } 290 | } 291 | 292 | fn main() { 293 | callback::output_resolution(on_output_resolution); 294 | callback::view_created(on_view_created); 295 | callback::view_destroyed(on_view_destroyed); 296 | callback::view_focus(on_view_focus); 297 | callback::view_request_move(on_view_request_move); 298 | callback::view_request_resize(on_view_request_resize); 299 | callback::keyboard_key(on_keyboard_key); 300 | callback::pointer_button(on_pointer_button); 301 | callback::pointer_motion(on_pointer_motion); 302 | 303 | rustwlc::log_set_default_handler(); 304 | let run_fn = rustwlc::init().expect("Unable to initialize wlc!"); 305 | run_fn(); 306 | } 307 | 308 | -------------------------------------------------------------------------------- /src/callback.rs: -------------------------------------------------------------------------------- 1 | //! Register wlc callbacks to events. 2 | //! 3 | //! See individual methods for callback details. 4 | //! 5 | //! # wlc Example 6 | //! ```no_run 7 | //! use rustwlc; 8 | //! use rustwlc::callback; 9 | //! use rustwlc::WlcView; 10 | //! 11 | //! // An example callback function 12 | //! // See the various functions in this module for more information 13 | //! extern "C" fn view_focus_callback(view: WlcView, focused: bool) { 14 | //! println!("A view came into focus!"); 15 | //! } 16 | //! 17 | //! // Set a default log callback 18 | //! rustwlc::log_set_default_handler(); 19 | //! 20 | //! // Register some callbacks 21 | //! callback::view_focus(view_focus_callback); 22 | //! // ... and additional callbacks 23 | //! 24 | //! // The only thing your code should do before init2 is register callbacks 25 | //! // and log handlers. 26 | //! let run_wlc = rustwlc::init2() 27 | //! .expect("Unable to initialize wlc!"); 28 | //! 29 | //! run_wlc(); 30 | //! ``` 31 | 32 | use super::types::*; 33 | use ::{WlcOutput, WlcView}; 34 | 35 | #[cfg_attr(feature = "static-wlc", link(name = "wlc", kind = "static"))] 36 | #[cfg_attr(not(feature = "static-wlc"), link(name = "wlc"))] 37 | extern "C" { 38 | // Output was created. Return false if you want to destroy the output. 39 | // (e.g. failed to allocate data related to view) 40 | fn wlc_set_output_created_cb(cb: extern "C" fn(WlcOutput) -> bool); 41 | 42 | // Output was destroyed. 43 | fn wlc_set_output_destroyed_cb(cb: extern "C" fn(WlcOutput)); 44 | 45 | // Output got or lost focus. 46 | fn wlc_set_output_focus_cb(cb: extern "C" fn(WlcOutput, bool)); 47 | 48 | // Output resolution changed. 49 | fn wlc_set_output_resolution_cb(cb: extern "C" fn(WlcOutput, &Size, &Size)); 50 | 51 | // Output context callbacks 52 | fn wlc_set_output_context_created_cb(cb: extern "C" fn(WlcOutput)); 53 | 54 | fn wlc_set_output_context_destroyed_cb(cb: extern "C" fn(WlcOutput)); 55 | 56 | // Output pre render hook. 57 | fn wlc_set_output_render_pre_cb(cb: extern "C" fn(WlcOutput)); 58 | 59 | // Output post render hook. 60 | fn wlc_set_output_render_post_cb(cb: extern "C" fn(WlcOutput)); 61 | 62 | // View was created. Return false if you want to destroy the view. 63 | // (e.g. failed to allocate data related to view) 64 | fn wlc_set_view_created_cb(cb: extern "C" fn(WlcView) -> bool); 65 | 66 | // View was destroyed. 67 | fn wlc_set_view_destroyed_cb(cb: extern "C" fn(handle: WlcView)); 68 | 69 | // View got or lost focus. 70 | fn wlc_set_view_focus_cb(cb: extern "C" fn(WlcView, bool)); 71 | 72 | // View was moved to output. 73 | fn wlc_set_view_move_to_output_cb(cb: extern "C" fn(WlcView, WlcOutput, 74 | WlcOutput)); 75 | 76 | // Request to set given geometry for view. 77 | // Apply using wlc_view_set_geometry to agree. 78 | fn wlc_set_view_request_geometry_cb(cb: extern "C" fn(WlcView, 79 | &Geometry)); 80 | 81 | // Request to disable or enable the given state for view. 82 | // Apply using wlc_view_set_state to agree. 83 | fn wlc_set_view_request_state_cb(cb: extern "C" fn(WlcView, 84 | ViewState, bool)); 85 | 86 | // Request to move itself. Start a interactive move to agree. 87 | fn wlc_set_view_request_move_cb(cb: extern "C" fn(WlcView, &Point)); 88 | 89 | // Request to resize itself with the given edges. 90 | // Start a interactive resize to agree. 91 | fn wlc_set_view_request_resize_cb(cb: extern "C" fn(WlcView, ResizeEdge, 92 | &Point)); 93 | 94 | // View pre render hook. 95 | fn wlc_set_view_render_pre_cb(cb: extern "C" fn(WlcView)); 96 | 97 | // View post render hook. 98 | fn wlc_set_view_render_post_cb(cb: extern "C" fn(WlcView)); 99 | 100 | // Key event was triggered, view handle will be zero if there was no focus. 101 | // Return true to prevent sending the event to clients. 102 | fn wlc_set_keyboard_key_cb(cb: extern "C" fn(WlcView, u32, 103 | &KeyboardModifiers, 104 | u32, KeyState) -> bool); 105 | 106 | // Button event was triggered, view handle will be zero if there 107 | // was no focus. Return true to prevent sending the event to clients. 108 | fn wlc_set_pointer_button_cb(cb: extern "C" fn(WlcView, u32, 109 | &KeyboardModifiers, u32, 110 | ButtonState, &Point) -> bool); 111 | 112 | // Scroll event was triggered, view handle will be zero if there was no 113 | // focus. Return true to prevent sending the event to clients. 114 | fn wlc_set_pointer_scroll_cb(cb: extern "C" fn(WlcView, u32, 115 | &KeyboardModifiers, 116 | ScrollAxis, [f64; 2]) -> bool); 117 | 118 | // Motion event was triggered, view handle will be zero if there was no 119 | // focus. Apply with wlc_pointer_set_position to agree. Return true to 120 | // prevent sending the event to clients. 121 | #[deprecated(since="0.7.0", note="Use wlc_set_pointer_motion_cb_v2 instead")] 122 | fn wlc_set_pointer_motion_cb(cb: extern "C" fn(WlcView, u32, 123 | &Point) -> bool); 124 | 125 | fn wlc_set_pointer_motion_cb_v2(cb: extern "C" fn(WlcView, u32, 126 | f64, f64) -> bool); 127 | 128 | // Touch event was triggered, view handle will be zero if there was no 129 | // focus. Return true to prevent sending the event to clients. 130 | fn wlc_set_touch_cb(cb: extern "C" fn(WlcView, u32, &KeyboardModifiers, 131 | TouchType, i32, &Point) -> bool); 132 | 133 | // Compositor is ready to accept clients. 134 | fn wlc_set_compositor_ready_cb(cb: extern "C" fn()); 135 | 136 | // Compositor is about to terminate. 137 | fn wlc_set_compositor_terminate_cb(cb: extern "C" fn()); 138 | 139 | // We're not supporting libinput experimental callbacks 140 | 141 | // Input device was created. Return value does nothing. (Experimental) 142 | //fn wlc_set_input_created_cb(cb: extern "C" fn(&LibinputDevice) -> bool); 143 | 144 | // Input device was destroyed. (Experimental) 145 | //fn wlc_set_input_destroyed_cb(cb: extern "C" fn(&LibinputDevice)); 146 | 147 | // View properties were updated 148 | fn wlc_set_view_properties_updated_cb(cb: extern "C" fn(handle: WlcView, 149 | mask: ViewPropertyType)); 150 | 151 | /// Get anchor rectangle requested by positioner, as defined in xdg-shell v6. 152 | /// Returns NULL if view has no valid positioner. 153 | fn wlc_view_positioner_get_anchor_rect(view: WlcView) -> *const Geometry; 154 | 155 | /// Get size requested by positioner, as defined in xdg-shell v6. 156 | /// Returns NULL if view has no valid positioner 157 | fn wlc_view_positioner_get_size(view: WlcView) -> *const Size; 158 | 159 | /// Get anchor requested by positioner, as defined in xdg-shell v6. 160 | /// Returns default value WLC_BIT_ANCHOR_NONE if view has no valid positioner 161 | /// or if positioner has no anchor set. 162 | fn wlc_view_positioner_get_anchor(view: WlcView) -> PositionerAnchorBit; 163 | 164 | /// Get anchor requested by positioner, as defined in xdg-shell v6. 165 | /// Returns default value WLC_BIT_GRAVITY_NONE if view has no valid positioner 166 | /// or if positioner has no gravity set. 167 | fn wlc_view_positioner_get_gravity(view: WlcView) -> PositionerGravityBit; 168 | 169 | /// Get constraint adjustment requested by positioner, as defined in xdg-shell v6. 170 | /// Returns default value WLC_BIT_CONSTRAINT_ADJUSTMENT_NONE if view has no 171 | /// valid positioner or if positioner has no constraint adjustment set. 172 | fn wlc_view_positioner_get_constraint_adjustment(view: WlcView) 173 | -> PositionerConstraintAdjustmentBits; 174 | } 175 | 176 | /// Callback invoked when an output is created. 177 | /// Return `true` to allow the output to exist. 178 | /// 179 | /// # Example 180 | /// ```rust 181 | /// use rustwlc::WlcOutput; 182 | /// 183 | /// extern fn on_output_created(output: WlcOutput) -> bool { 184 | /// println!("Output {} ({:?}) was created", output.get_name(), output); 185 | /// return true; 186 | /// } 187 | /// # fn main() { } 188 | /// ``` 189 | pub fn output_created(callback: extern "C" fn(output: WlcOutput) -> bool) { 190 | unsafe { 191 | wlc_set_output_created_cb(callback); 192 | } 193 | } 194 | 195 | /// Callback invoked when an output is destroyed. 196 | /// 197 | /// # Example 198 | /// ```rust 199 | /// use rustwlc::WlcOutput; 200 | /// 201 | /// extern fn output_destroyed(output: WlcOutput) { 202 | /// println!("Goodbye, {:?}", output); 203 | /// } 204 | /// # fn main() { } 205 | /// ``` 206 | pub fn output_destroyed(callback: extern "C" fn(output: WlcOutput)) { 207 | unsafe { 208 | wlc_set_output_destroyed_cb(callback); 209 | } 210 | } 211 | 212 | /// Callback invoked when an output gains focus. 213 | /// 214 | /// # Example 215 | /// ```rust 216 | /// use rustwlc::WlcOutput; 217 | /// 218 | /// extern fn output_focus(output: WlcOutput, focused: bool) { 219 | /// println!("Output {} {} focus", output.get_name(), 220 | /// if focused { "gained" } else { "lost" }); 221 | /// } 222 | /// # fn main() { } 223 | /// ``` 224 | pub fn output_focus(callback: extern "C" fn(output: WlcOutput, focused: bool)) { 225 | unsafe { 226 | wlc_set_output_focus_cb(callback); 227 | } 228 | } 229 | 230 | /// Callback invoked when an output's resolution changes. 231 | /// 232 | /// # Example 233 | /// ```rust 234 | /// use rustwlc::WlcOutput; 235 | /// use rustwlc::Size; 236 | /// 237 | /// extern fn output_resolution(output: WlcOutput, 238 | /// old_size: &Size, new_size: &Size) { 239 | /// println!("Output {} went from {} to {}", 240 | /// output.get_name(), old_size, new_size); 241 | /// } 242 | /// # fn main() { } 243 | /// ``` 244 | pub fn output_resolution(callback: extern "C" fn(output: WlcOutput, 245 | old_size: &Size, 246 | new_size: &Size)) { 247 | unsafe { 248 | wlc_set_output_resolution_cb(callback); 249 | } 250 | } 251 | 252 | /// Output context created. This generally happens on a tty switch. 253 | pub fn output_context_destroyed(cb: extern "C" fn(output: WlcOutput)) { 254 | unsafe { 255 | wlc_set_output_context_destroyed_cb(cb); 256 | } 257 | } 258 | 259 | /// Output context destroyed 260 | pub fn output_context_created(cb: extern "C" fn(output: WlcOutput)) { 261 | unsafe { 262 | wlc_set_output_context_created_cb(cb); 263 | } 264 | } 265 | 266 | /// Callback invoked pre-render for an output. 267 | pub fn output_render_pre(callback: extern "C" fn(output: WlcOutput)) { 268 | unsafe { 269 | wlc_set_output_render_pre_cb(callback); 270 | } 271 | } 272 | 273 | /// Callback invoked post-render for an output. 274 | pub fn output_render_post(callback: extern "C" fn(output: WlcOutput)) { 275 | unsafe { 276 | wlc_set_output_render_post_cb(callback); 277 | } 278 | } 279 | 280 | /// Callback invoked when a view is created. 281 | /// Return `true` to allow the view to be created. 282 | /// 283 | /// When a new view is created, the following should probably be applied: 284 | /// * Set the view's mask to the output's mask 285 | /// * Focus the view 286 | /// * Bring the view to the front 287 | /// 288 | /// # Example 289 | /// ```rust 290 | /// use rustwlc::WlcView; 291 | /// 292 | /// extern fn view_created(view: WlcView) -> bool { 293 | /// println!("View \"{}\" was created ({:?})", view.get_class(), view); 294 | /// view.set_mask(view.get_output().get_mask()); 295 | /// view.bring_to_front(); 296 | /// view.focus(); 297 | /// return true; 298 | /// } 299 | /// # fn main() { } 300 | /// ``` 301 | pub fn view_created(callback: extern "C" fn(view: WlcView) -> bool) { 302 | unsafe { 303 | wlc_set_view_created_cb(callback); 304 | } 305 | } 306 | 307 | /// Callback invoked when a view is destroyed. 308 | /// 309 | /// When a view is destroyed, it's a good idea to shift focus to 310 | /// some other view, i.e. the last one used. 311 | /// 312 | /// # Example 313 | /// ```rust 314 | /// use rustwlc::WlcView; 315 | /// 316 | /// extern fn view_destroyed(view: WlcView) { 317 | /// println!("Goodbye, {:?}", view); 318 | /// } 319 | /// # fn main() { } 320 | /// ``` 321 | pub fn view_destroyed(callback: extern "C" fn(view: WlcView)) { 322 | unsafe { 323 | wlc_set_view_destroyed_cb(callback); 324 | } 325 | } 326 | 327 | /// Callback invoked when a view is focused. 328 | /// 329 | /// The view's `ViewState::VIEW_ACTIVATED` bit should be set to true here. 330 | /// 331 | /// # Example 332 | /// ```rust 333 | /// use rustwlc::WlcView; 334 | /// // The bitflags constants need to be imported manually. 335 | /// use rustwlc::VIEW_ACTIVATED; 336 | /// 337 | /// extern fn view_focus(view: WlcView, focused: bool) { 338 | /// println!("View {:?} is {} focus, updating...", 339 | /// view, if focused { "in" } else { "out of" }); 340 | /// view.set_state(VIEW_ACTIVATED, focused); 341 | /// } 342 | /// ``` 343 | pub fn view_focus(callback: extern "C" fn(handle: WlcView, focused: bool)) { 344 | unsafe { 345 | wlc_set_view_focus_cb(callback); 346 | } 347 | } 348 | 349 | /// Callback invoked when a view switches outputs. 350 | /// 351 | /// Moving views between outputs is unsupported in wlc at the time of writing. 352 | /// Wayland mandates each output have its own memory buffer so it may take wlc 353 | /// some time before this is implemented. 354 | pub fn view_move_to_output(callback: extern "C" fn(view: WlcView, 355 | old_output: WlcOutput, 356 | new_output: WlcOutput)) { 357 | unsafe { 358 | wlc_set_view_move_to_output_cb(callback); 359 | } 360 | } 361 | 362 | /// Callback invoked when a view requests geometry. 363 | pub fn view_request_geometry(callback: extern "C" fn(handle: WlcView, 364 | geometry: &Geometry)) { 365 | unsafe { 366 | wlc_set_view_request_geometry_cb(callback); 367 | } 368 | } 369 | 370 | /// Callback invoked when a view requests a `ViewState`. 371 | pub fn view_request_state(callback: extern "C" fn(current: WlcView, 372 | state: ViewState, 373 | handled: bool)) { 374 | unsafe { 375 | wlc_set_view_request_state_cb(callback); 376 | } 377 | } 378 | 379 | /// Callback invoked when a view requests a move. 380 | pub fn view_request_move(callback: extern "C" fn(handle: WlcView, 381 | destination: &Point)) { 382 | unsafe { 383 | wlc_set_view_request_move_cb(callback); 384 | } 385 | } 386 | 387 | /// Callback invoked when a view requests a resize. 388 | pub fn view_request_resize(callback: extern "C" fn(handle: WlcView, 389 | edge: ResizeEdge, 390 | location: &Point)) { 391 | unsafe { 392 | wlc_set_view_request_resize_cb(callback); 393 | } 394 | } 395 | 396 | /// Callback invoked pre-view-render. 397 | pub fn view_render_pre(callback: extern "C" fn(view: WlcView)) { 398 | unsafe { 399 | wlc_set_view_render_pre_cb(callback); 400 | } 401 | } 402 | 403 | /// Callback invoked post-view-render. 404 | pub fn view_render_post(callback: extern "C" fn(view: WlcView)) { 405 | unsafe { 406 | wlc_set_view_render_post_cb(callback); 407 | } 408 | } 409 | 410 | /// Callback invoked on keypresses. 411 | /// Return `true` to block the press from the view. 412 | /// 413 | /// # Arguments 414 | /// The first `u32` is a timestamp, the second is the key code. The view may be 415 | /// the root window. 416 | /// 417 | /// Proper values for `key` can be found in `input.h` or a similar library/crate 418 | /// - see wlc documentation on the subject, it may not support your keyboard 419 | /// layout at the moment. 420 | /// 421 | /// # Example 422 | /// ```rust 423 | /// use rustwlc::WlcView; 424 | /// use rustwlc::{KeyboardModifiers, KeyState}; 425 | /// 426 | /// extern fn keyboard_key(view: WlcView, time: u32, mods: &KeyboardModifiers, 427 | /// key: u32, state: KeyState) -> bool { 428 | /// println!("Key {} {:?} on {:?} at {} with modifiers {:?}", 429 | /// key, view, state, time, mods); 430 | /// return false; 431 | /// } 432 | /// # fn main() { } 433 | /// ``` 434 | pub fn keyboard_key(callback: extern "C" fn(view: WlcView, time: u32, 435 | mods: &KeyboardModifiers, key: u32, 436 | state: KeyState) -> bool) { 437 | unsafe { 438 | wlc_set_keyboard_key_cb(callback); 439 | } 440 | } 441 | 442 | /// Callback invoked on mouse clicks. 443 | /// Return `true` to block the click from the view. 444 | /// 445 | /// # Arguments 446 | /// The first u32 is a timestamp, the second is the button code. 447 | /// The view may be the root window. Proper values for `button` 448 | /// can be found in `input.h` or a similar library/crate. 449 | /// 450 | /// # Example 451 | /// ```rust 452 | /// use rustwlc::WlcView; 453 | /// use rustwlc::{KeyboardModifiers, ButtonState, Point}; 454 | /// 455 | /// extern fn pointer_button(view: WlcView, time: u32, 456 | /// mods: &KeyboardModifiers, button: u32, 457 | /// state: ButtonState, point: &Point) -> bool { 458 | /// println!("Button {} {:?} at {} at {} in {:?}, keyboard mods: {:?}", 459 | /// button, state, time, point, view, mods); 460 | /// return false; 461 | /// } 462 | /// # fn main() { } 463 | /// ``` 464 | pub fn pointer_button(callback: extern "C" fn(view: WlcView, time: u32, 465 | mods: &KeyboardModifiers, 466 | button: u32, state: ButtonState, 467 | point: &Point) -> bool) { 468 | unsafe { 469 | wlc_set_pointer_button_cb(callback); 470 | } 471 | } 472 | 473 | /// Callback invoked on mouse scroll. 474 | /// Return `true` to block the scroll from the view. 475 | /// 476 | /// # Arguments 477 | /// * view: The WlcView (or output root) that was scrolled in 478 | /// * time: Timestamp 479 | /// * mods: Current pressed keyboard modifiers 480 | /// * axis: Which direction the scroll was in 481 | /// * amount: The first argument seems to be either 10 or -10 depending on 482 | /// up/down (or right/left if `axis == ScrollAxis::Horizontal`). 483 | /// The second one, when tested on a standard laptop trackpad, seems to be 484 | /// a double slightly above zero. 485 | pub fn pointer_scroll(callback: extern "C" fn(view: WlcView, time: u32, 486 | mods: &KeyboardModifiers, 487 | axis: ScrollAxis, 488 | amount: [f64; 2]) -> bool) { 489 | unsafe { 490 | wlc_set_pointer_scroll_cb(callback); 491 | } 492 | } 493 | 494 | /// Callback invoked on pointer motion. 495 | /// Return `true` to block the motion from the view. 496 | /// 497 | /// `rustwlc::input::pointer::set_position` 498 | /// must be invoked to actually move the cursor! 499 | /// 500 | /// # Example 501 | /// ```rust 502 | /// use rustwlc::WlcView; 503 | /// use rustwlc::Point; 504 | /// use rustwlc::input::pointer; 505 | /// 506 | /// extern fn pointer_motion(view: WlcView, time: u32, point: Point) -> bool { 507 | /// println!("Pointer was moved to {} in {:?} at {}", point, view, time); 508 | /// // This is very important. 509 | /// pointer::set_position(point); 510 | /// return false; 511 | /// } 512 | /// # fn main() { } 513 | /// ``` 514 | #[deprecated(since="0.7.0", note="Use pointer_motion_v2 instead")] 515 | #[allow(deprecated)] 516 | pub fn pointer_motion(callback: extern "C" fn(view: WlcView, time: u32, 517 | point: &Point) -> bool) { 518 | unsafe { 519 | wlc_set_pointer_motion_cb(callback); 520 | } 521 | } 522 | 523 | /// Callback invoked on pointer motion. 524 | /// Return `true` to block the motion from the view. 525 | /// 526 | /// `rustwlc::input::pointer::set_position_v2` 527 | /// must be invoked to actually move the cursor! 528 | /// 529 | /// # Example 530 | /// ```rust 531 | /// use rustwlc::WlcView; 532 | /// use rustwlc::Point; 533 | /// use rustwlc::input::pointer; 534 | /// 535 | /// extern fn pointer_motion(view: WlcView, time: u32, x: f64, y: f64) -> bool { 536 | /// println!("Pointer was moved to {} {} in {:?} at {}", x, y, view, time); 537 | /// // This is very important. 538 | /// pointer::set_position_v2(x, y); 539 | /// return false; 540 | /// } 541 | /// # fn main() { } 542 | /// ``` 543 | pub fn pointer_motion_v2(callback: extern "C" fn(view: WlcView, time: u32, 544 | x: f64, y: f64) -> bool) { 545 | unsafe { 546 | wlc_set_pointer_motion_cb_v2(callback); 547 | } 548 | } 549 | 550 | 551 | /// Callback invoked on touchscreen touch. 552 | /// Return `true` to block the touch from the view. 553 | /// 554 | /// # Arguments 555 | /// * `mods`: Which keyboard modifiers are being pressed during the event 556 | /// * `touch`: What kind of event it is (a touch down, a frame being made, 557 | /// a touch release). In the case of `TouchType::Frame`, `slot` and `point` 558 | /// will both be zero. 559 | /// * `slot`: Which finger - in cases of multiple touches down - is causing 560 | /// the event 561 | /// * `point`: Where the touch event happened 562 | pub fn touch(callback: extern "C" fn(handle: WlcView, time: u32, 563 | mods: &KeyboardModifiers, touch: TouchType, 564 | slot: i32, point: &Point) -> bool) { 565 | unsafe { 566 | wlc_set_touch_cb(callback); 567 | } 568 | } 569 | 570 | /// Callback invoked by wlc after `rustwlc::init` is called. 571 | pub fn compositor_ready(callback: extern "C" fn()) { 572 | unsafe { 573 | wlc_set_compositor_ready_cb(callback); 574 | } 575 | } 576 | 577 | /// Callback invoked by wlc when a compositor is terminating 578 | pub fn compositor_terminate(callback: extern "C" fn()) { 579 | unsafe { 580 | wlc_set_compositor_terminate_cb(callback); 581 | } 582 | } 583 | 584 | /// Callback invoked when a WlcView has its properties updated. 585 | /// 586 | /// # Arguments 587 | /// * `view`: View handle that is changing its properties 588 | /// * `mask`: Bitflag of which property is being updated 589 | pub fn view_properties_changed(callback: extern "C" fn(handle: WlcView, mask: ViewPropertyType)) { 590 | unsafe { 591 | wlc_set_view_properties_updated_cb(callback); 592 | } 593 | } 594 | 595 | /// Get anchor requested by positioner, as defined in xdg-shell v6. 596 | /// Returns default value WLC_BIT_ANCHOR_NONE if view has no valid positioner 597 | /// or if positioner has no anchor set. 598 | pub fn positioner_get_anchor_rect(view: WlcView) -> Option { 599 | unsafe { 600 | let out = wlc_view_positioner_get_anchor_rect(view); 601 | if out.is_null() { 602 | None 603 | } else { 604 | Some(*out) 605 | } 606 | } 607 | } 608 | 609 | /// Get size requested by positioner, as defined in xdg-shell v6. 610 | pub fn positioner_get_size(view: WlcView) -> Option { 611 | unsafe { 612 | let out = wlc_view_positioner_get_size(view); 613 | if out.is_null() { 614 | None 615 | } else { 616 | Some(*out) 617 | } 618 | } 619 | } 620 | 621 | /// Get anchor requested by positioner, as defined in xdg-shell v6. 622 | /// Returns default value WLC_BIT_GRAVITY_NONE if view has no valid positioner 623 | /// or if positioner has no gravity set. 624 | pub fn positioner_get_anchor(view: WlcView) -> PositionerAnchorBit { 625 | unsafe { 626 | wlc_view_positioner_get_anchor(view) 627 | } 628 | } 629 | 630 | pub fn positioner_get_gravity(view: WlcView) -> PositionerGravityBit { 631 | unsafe { 632 | wlc_view_positioner_get_gravity(view) 633 | } 634 | } 635 | 636 | pub fn positioner_get_constraint_adjustment(view: WlcView) 637 | -> PositionerConstraintAdjustmentBits { 638 | unsafe { 639 | wlc_view_positioner_get_constraint_adjustment(view) 640 | } 641 | } 642 | -------------------------------------------------------------------------------- /src/dummy_callback.rs: -------------------------------------------------------------------------------- 1 | //! Dummy wlc callbacks for events. 2 | #![allow(missing_docs)] 3 | 4 | use super::types::*; 5 | use ::{WlcOutput, WlcView}; 6 | 7 | 8 | pub fn output_created(_callback: extern "C" fn(output: WlcOutput) -> bool) { 9 | 10 | } 11 | 12 | pub fn output_destroyed(_callback: extern "C" fn(output: WlcOutput)) { 13 | 14 | } 15 | 16 | pub fn output_focus(_callback: extern "C" fn(output: WlcOutput, focused: bool)) { 17 | 18 | } 19 | 20 | pub fn output_resolution(_callback: extern "C" fn(output: WlcOutput, 21 | old_size: &Size, 22 | new_size: &Size)) { 23 | 24 | } 25 | 26 | pub fn output_context_destroyed(_cb: extern "C" fn(output: WlcOutput)) { 27 | 28 | } 29 | 30 | pub fn output_context_created(_cb: extern "C" fn(output: WlcOutput)) { 31 | 32 | } 33 | 34 | pub fn output_render_pre(_callback: extern "C" fn(output: WlcOutput)) { 35 | 36 | } 37 | 38 | pub fn output_render_post(_callback: extern "C" fn(output: WlcOutput)) { 39 | 40 | } 41 | 42 | pub fn view_created(_callback: extern "C" fn(view: WlcView) -> bool) { 43 | 44 | } 45 | 46 | pub fn view_destroyed(_callback: extern "C" fn(view: WlcView)) { 47 | 48 | } 49 | 50 | pub fn view_focus(_callback: extern "C" fn(handle: WlcView, focused: bool)) { 51 | 52 | } 53 | 54 | pub fn view_move_to_output(_callback: extern "C" fn(view: WlcView, 55 | old_output: WlcOutput, 56 | new_output: WlcOutput)) { 57 | 58 | } 59 | 60 | pub fn view_request_geometry(_callback: extern "C" fn(handle: WlcView, 61 | geometry: &Geometry)) { 62 | 63 | } 64 | 65 | pub fn view_request_state(_callback: extern "C" fn(current: WlcView, 66 | state: ViewState, 67 | handled: bool)) { 68 | 69 | } 70 | 71 | pub fn view_request_move(_callback: extern "C" fn(handle: WlcView, 72 | destination: &Point)) { 73 | 74 | } 75 | 76 | pub fn view_request_resize(_callback: extern "C" fn(handle: WlcView, 77 | edge: ResizeEdge, 78 | location: &Point)) { 79 | 80 | } 81 | 82 | pub fn view_render_pre(_callback: extern "C" fn(view: WlcView)) { 83 | 84 | } 85 | 86 | pub fn view_render_post(_callback: extern "C" fn(view: WlcView)) { 87 | 88 | } 89 | 90 | pub fn keyboard_key(_callback: extern "C" fn(view: WlcView, time: u32, 91 | mods: &KeyboardModifiers, key: u32, 92 | state: KeyState) -> bool) { 93 | 94 | } 95 | 96 | pub fn pointer_button(_callback: extern "C" fn(view: WlcView, time: u32, 97 | mods: &KeyboardModifiers, 98 | button: u32, state: ButtonState, 99 | point: &Point) -> bool) { 100 | 101 | } 102 | 103 | pub fn pointer_scroll(_callback: extern "C" fn(view: WlcView, time: u32, 104 | mods: &KeyboardModifiers, 105 | axis: ScrollAxis, 106 | amount: [f64; 2]) -> bool) { 107 | 108 | } 109 | 110 | pub fn pointer_motion(_callback: extern "C" fn(view: WlcView, time: u32, 111 | point: &Point) -> bool) { 112 | 113 | } 114 | 115 | pub fn touch(_callback: extern "C" fn(handle: WlcView, time: u32, 116 | mods: &KeyboardModifiers, touch: TouchType, 117 | slot: i32, point: &Point) -> bool) { 118 | 119 | } 120 | 121 | pub fn compositor_ready(_callback: extern "C" fn()) { 122 | 123 | } 124 | 125 | pub fn compositor_terminate(_callback: extern "C" fn()) { 126 | 127 | } 128 | 129 | pub fn view_properties_changed(_callback: extern "C" fn(handle: WlcView, mask: ViewPropertyType)) { 130 | 131 | } 132 | -------------------------------------------------------------------------------- /src/dummy_handle.rs: -------------------------------------------------------------------------------- 1 | //! Contains dummy definitions for wlc handle types. 2 | 3 | extern crate libc; 4 | use libc::{uint32_t, pid_t}; 5 | 6 | #[cfg(feature="wlc-wayland")] 7 | use libc::c_void; 8 | 9 | #[cfg(feature="wlc-wayland")] 10 | use wayland_sys::server::{wl_resource, wl_client}; 11 | 12 | #[cfg(feature="wlc-wayland")] 13 | use wayland_sys::common::wl_interface; 14 | 15 | #[cfg(feature="wlc-wayland")] 16 | use super::dummy_wayland::WlcResource; 17 | 18 | use super::types::{Geometry, ResizeEdge, Size, ViewType, ViewState}; 19 | 20 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 21 | /// Represents a handle to a wlc view. 22 | /// 23 | pub struct WlcView { 24 | handle: uint32_t, 25 | title: String, 26 | class: String, 27 | app_id: String, 28 | pid: pid_t, 29 | output: WlcOutput, 30 | geometry: Geometry, 31 | visible_geometry: Geometry, 32 | focus: bool, 33 | mask: u32, 34 | view_type: ViewType, 35 | view_state: ViewState, 36 | } 37 | 38 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] 39 | /// Represents a handle to a wlc output. 40 | pub struct WlcOutput { 41 | handle: uint32_t, 42 | name: String, 43 | sleep: bool, 44 | scaling: u32, 45 | mask: u32, 46 | resolution: Option, 47 | virtual_resolution: Option, 48 | views: Vec 49 | } 50 | 51 | impl From for WlcOutput { 52 | fn from(view: WlcView) -> Self { 53 | unsafe { WlcOutput::dummy(view.handle) } 54 | } 55 | } 56 | 57 | impl From for WlcView { 58 | fn from(output: WlcOutput) -> Self { 59 | unsafe { WlcView::dummy(output.handle) } 60 | } 61 | } 62 | 63 | // TODO Implement this 64 | /* 65 | #[cfg(feature = "wlc-wayland")] 66 | impl Into for wl_resource { 67 | fn into(self) -> WlcView { 68 | unsafe { WlcView(wlc_handle_from_wl_surface_resource(&self)) } 69 | } 70 | } 71 | */ 72 | 73 | 74 | // TODO Implement this 75 | /* 76 | #[cfg(feature="wlc-wayland")] 77 | impl Into for wl_resource { 78 | fn into(self) -> WlcOutput { 79 | unsafe { WlcOutput(wlc_handle_from_wl_output_resource(&self)) } 80 | } 81 | } 82 | */ 83 | 84 | impl WlcOutput { 85 | /// Compatability/debugging function. 86 | /// 87 | /// wlc internally stores views and outputs under the same type. 88 | /// If for some reason a conversion between the two was required, 89 | /// this function could be called. If this is the case please submit 90 | /// a bug report. 91 | pub fn as_view(self) -> WlcView { 92 | WlcView::from(self) 93 | } 94 | 95 | /// Create a dummy WlcOutput for testing purposes. 96 | /// 97 | /// # Unsafety 98 | /// The following operations on a dummy WlcOutput will cause crashes: 99 | /// 100 | /// - `WlcOutput::focused` when wlc is not running 101 | /// - `WlcOutput::list` when wlc is not running 102 | /// - `WlcOutput::set_resolution` on a dummy output 103 | /// 104 | /// In addition, `WlcOutput::set_views` will return an error. 105 | /// 106 | /// All other methods can be used on dummy outputs. 107 | /// 108 | /// # Example 109 | /// ```rust 110 | /// # use rustwlc::WlcOutput; 111 | /// unsafe { 112 | /// let output = WlcOutput::dummy(0u32); 113 | /// let output2 = WlcOutput::dummy(1u32); 114 | /// assert!(output < output2); 115 | /// assert!(output != output2); 116 | /// } 117 | /// ``` 118 | pub unsafe fn dummy(code: u32) -> WlcOutput { 119 | WlcOutput { 120 | handle: code, 121 | name: "".into(), 122 | sleep: false, 123 | scaling: 1, 124 | mask: 0, 125 | resolution: None, 126 | virtual_resolution: None, 127 | views: Vec::new() 128 | } 129 | } 130 | 131 | // TODO Implement mocks for user data 132 | 133 | /// Dummy gets user-specified data. 134 | /// 135 | /// Always returns None 136 | pub unsafe fn get_user_data(&self) -> Option<&mut T> { 137 | None 138 | } 139 | 140 | /// Dummy sets user-specified data. 141 | /// 142 | /// Always panics w/ `unimplemented!` 143 | pub unsafe fn set_user_data(&self, _data: &T) { 144 | unimplemented!() 145 | } 146 | 147 | /// Dummy scheduling for output for rendering next frame. 148 | /// 149 | /// If the output was already scheduled, this is 150 | /// a no-op; if output is currently rendering, 151 | /// it will render immediately after. 152 | pub fn schedule_render(self) { 153 | println!("Dummy call to wlc_output_schedule_render") 154 | } 155 | 156 | // TODO Mock this 157 | 158 | /// Dummy gets a list of the current outputs. 159 | /// 160 | /// Always returns an empty list. 161 | pub fn list() -> Vec { 162 | Vec::new() 163 | } 164 | 165 | /// Dummy gets the currently focused output. 166 | /// 167 | /// Always panics 168 | pub fn focused() -> WlcOutput { 169 | unimplemented!() 170 | } 171 | 172 | /// Dummy gets the name of the WlcOutput. 173 | pub fn get_name(self) -> String { 174 | self.name 175 | } 176 | 177 | /// Dummy gets the sleep status of the output. 178 | pub fn get_sleep(self) -> bool { 179 | self.sleep 180 | } 181 | 182 | /// Dummy sets the sleep status of the output. 183 | pub fn set_sleep(&mut self, sleep: bool) { 184 | self.sleep = sleep 185 | } 186 | 187 | /// Dummy gets the output's real resolution. Do not use for coordinate boundary. 188 | pub fn get_resolution(self) -> Option { 189 | self.resolution 190 | } 191 | 192 | /// Dummy get the virtual resolution. Helpful for getting resolution on high dpi displays. 193 | pub fn get_virtual_resolution(self) -> Option { 194 | self.virtual_resolution 195 | } 196 | 197 | /// Dummy sets the resolution of the output. 198 | pub fn set_resolution(&mut self, size: Size, scaling: u32) { 199 | self.scaling = scaling; 200 | self.resolution = Some(Size { 201 | w: size.w * scaling, 202 | h: size.h * scaling 203 | }) 204 | } 205 | 206 | /// Dummy gets the scaling for the output. 207 | pub fn get_scale(self) -> u32 { 208 | self.scaling 209 | } 210 | 211 | /// Dummy get views in stack order. 212 | pub fn get_views(self) -> Vec { 213 | self.views 214 | } 215 | 216 | /// Dummy gets the mask of this output 217 | pub fn get_mask(self) -> u32 { 218 | self.mask 219 | } 220 | 221 | /// Dummy sets the mask for this output 222 | pub fn set_mask(&mut self, mask: u32) { 223 | self.mask = mask 224 | } 225 | 226 | /// # Deprecated 227 | /// This function is equivalent to simply calling get_views 228 | #[deprecated(since = "0.5.3", note = "please use `get_views`")] 229 | pub fn get_mutable_views(self) -> Vec { 230 | self.get_views() 231 | } 232 | 233 | /// Dummy set the views of a given output. 234 | /// 235 | /// Always succeeds 236 | pub fn set_views(&mut self, views: &[WlcView]) -> Result<(), &'static str> { 237 | Ok(self.views = views.iter().map(|v| v.clone()).collect()) 238 | } 239 | 240 | /// Dummy focuses compositor on a specific output. 241 | /// 242 | /// Does nothing. 243 | pub fn focus(_output: Option) { 244 | println!("Dummy call to wlc_output_focus"); 245 | } 246 | } 247 | 248 | impl WlcView { 249 | /// Compatability/debugging function. 250 | /// 251 | /// wlc internally stores views and outputs under the same type. 252 | /// If for some reason a conversion between the two was required, 253 | /// this function could be called. If this is the case please submit 254 | /// a bug report. 255 | pub fn as_output(self) -> WlcOutput { 256 | WlcOutput::from(self) 257 | } 258 | 259 | /// Create a dummy WlcView for testing purposes. 260 | /// 261 | /// # Unsafety 262 | /// The following methods on views may crash the program: 263 | /// 264 | /// - `WlcView::focus` if wlc is not running 265 | /// - `WlcView::send_to_back` if wlc is not running 266 | /// - `WlcView::send_below` if wlc is not running 267 | /// - `WlcView::bring_above` if wlc is not running 268 | /// - `WlcView::bring_to_font` if wlc is not running 269 | /// 270 | /// All other methods can be used on dummy views. 271 | /// 272 | /// # Note 273 | /// `WlcView::root()` is equivalent to `WlcView::dummy(0)`. 274 | /// 275 | /// ```rust 276 | /// # use rustwlc::WlcView; 277 | /// assert!(WlcView::root() == unsafe { WlcView::dummy(0) }) 278 | /// ``` 279 | /// # Example 280 | /// ```rust 281 | /// # use rustwlc::WlcView; 282 | /// unsafe { 283 | /// let view = WlcView::dummy(0u32); 284 | /// let view2 = WlcView::dummy(1u32); 285 | /// assert!(view < view2); 286 | /// assert!(view != view2); 287 | /// } 288 | /// ``` 289 | pub unsafe fn dummy(code: u32) -> WlcView { 290 | WlcView { 291 | handle: code, 292 | title: "".into(), 293 | class: "".into(), 294 | app_id: "".into(), 295 | pid: 0 as pid_t, 296 | output: WlcOutput::dummy(0), 297 | geometry: Geometry::zero(), 298 | visible_geometry: Geometry::zero(), 299 | focus: false, 300 | mask: 0, 301 | view_type: ViewType::empty(), 302 | view_state: ViewState::empty(), 303 | } 304 | } 305 | 306 | /// Returns a reference to the root window (desktop background). 307 | /// 308 | /// # Example 309 | /// ``` 310 | /// # use rustwlc::WlcView; 311 | /// let view = WlcView::root(); 312 | /// assert!(view.is_root()); 313 | /// ``` 314 | pub fn root() -> WlcView { 315 | unsafe { 316 | WlcView::dummy(0) 317 | } 318 | } 319 | 320 | /// Whether this view is the root window (desktop background). 321 | /// 322 | /// # Example 323 | /// ```rust 324 | /// # use rustwlc::WlcView; 325 | /// # // This example can be run because WlcView::root() does not interact with wlc 326 | /// let view = WlcView::root(); 327 | /// assert!(view.is_root()); 328 | /// ``` 329 | #[inline] 330 | pub fn is_root(self) -> bool { 331 | self.handle == 0 332 | } 333 | 334 | /// Whether this view is not the root window (desktop background). 335 | /// 336 | /// # Usage 337 | /// A convenience method, the opposite of `view.is_root()`. 338 | /// 339 | /// # Example 340 | /// ```rust 341 | /// # use rustwlc::WlcView; 342 | /// let view = WlcView::root(); 343 | /// assert!(view.is_root()); 344 | /// assert!(!view.is_window()); 345 | /// ``` 346 | #[inline] 347 | pub fn is_window(self) -> bool { 348 | self.handle != 0 349 | } 350 | 351 | // TODO Mock user data 352 | 353 | /// Dummy gets user-specified data. 354 | /// 355 | /// Always returns `None` 356 | pub unsafe fn get_user_data(&self) -> Option<&mut T> { 357 | None 358 | } 359 | 360 | /// Dummy sets user-specified data. 361 | /// 362 | /// Always panics w/ `unimplemented!` 363 | pub unsafe fn set_user_data(&self, _data: &T) { 364 | unimplemented!() 365 | } 366 | 367 | /// Dummy closes this view. 368 | /// 369 | /// Does nothing 370 | pub fn close(self) { 371 | println!("Dummy call to wlc_view_close") 372 | } 373 | 374 | /// Dummy gets the WlcOutput this view is currently part of. 375 | pub fn get_output(self) -> WlcOutput { 376 | self.output 377 | } 378 | 379 | /// Dummy sets the output that the view renders on. 380 | pub fn set_output(&mut self, output: WlcOutput) { 381 | self.output = output 382 | } 383 | 384 | /// Dummy brings this view to focus. 385 | pub fn focus(&mut self) { 386 | self.focus = true 387 | } 388 | 389 | /// Dummy sends the view to the back of the compositor 390 | /// 391 | /// Does nothing 392 | pub fn send_to_back(self) { 393 | println!("Dummy call to wlc_view_send_to_back") 394 | } 395 | 396 | /// Dummy sends this view underneath another. 397 | /// 398 | /// Does nothing 399 | pub fn send_below(self, _other: WlcView) { 400 | println!("Dummy call to wlc_view_send_below") 401 | } 402 | 403 | /// Dummy brings this view above another. 404 | /// 405 | /// Does nothing 406 | pub fn bring_above(self, _other: WlcView) { 407 | println!("Dummy call to wlc_view_bring_above") 408 | } 409 | 410 | /// Dummy brings this view to the front of the stack 411 | /// within its WlcOutput. 412 | /// 413 | /// Does nothing 414 | pub fn bring_to_front(self) { 415 | println!("Dummy call to wlc_view_bring_to_front") 416 | } 417 | 418 | /// Dummy gets the current visibilty bitmask for the view. 419 | pub fn get_mask(self) -> u32 { 420 | self.mask 421 | } 422 | 423 | /// Dummy sets the visibilty bitmask for the view. 424 | pub fn set_mask(&mut self, mask: u32) { 425 | self.mask = mask 426 | } 427 | 428 | /// Dummy gets the geometry of the view. 429 | /// 430 | /// Always returns Some 431 | pub fn get_geometry(self) -> Option { 432 | Some(self.geometry) 433 | } 434 | 435 | /// Dummy gets the geometry of the view (that wlc displays). 436 | pub fn get_visible_geometry(self) -> Geometry { 437 | self.visible_geometry 438 | } 439 | 440 | /// Dummy sets the geometry of the view. 441 | /// 442 | /// Ignores `edges` 443 | pub fn set_geometry(&mut self, _edges: ResizeEdge, geometry: Geometry) { 444 | self.geometry = geometry; 445 | } 446 | 447 | /// Gets the type bitfield of the curent view 448 | pub fn get_type(self) -> ViewType { 449 | self.view_type 450 | } 451 | 452 | /// Dummy set flag in the type field. Toggle indicates whether it is set. 453 | pub fn set_type(&mut self, view_type: ViewType, toggle: bool) { 454 | if toggle { 455 | self.view_type.insert(view_type) 456 | } else { 457 | self.view_type.remove(view_type) 458 | } 459 | } 460 | 461 | /// Dummy get the current ViewState bitfield. 462 | pub fn get_state(self) -> ViewState { 463 | self.view_state 464 | } 465 | 466 | /// Dummy set ViewState bit. Toggle indicates whether it is set or not. 467 | pub fn set_state(&mut self, state: ViewState, toggle: bool) { 468 | if toggle { 469 | self.view_state.insert(state) 470 | } else { 471 | self.view_state.remove(state) 472 | } 473 | } 474 | 475 | /// Dummy gets parent view, returns `WlcView::root()` if this view has no parent. 476 | /// 477 | /// Will always panic 478 | pub fn get_parent(self) -> WlcView { 479 | unimplemented!() 480 | } 481 | 482 | /// Dummy set the parent of this view. 483 | /// 484 | /// Will always panic 485 | pub fn set_parent(self, _parent: &WlcView) { 486 | unimplemented!() 487 | } 488 | 489 | /// Dummy get the title of the view 490 | pub fn get_title(self) -> String { 491 | self.title 492 | } 493 | 494 | /// Dummy get class (shell surface only). 495 | pub fn get_class(self) -> String { 496 | self.class 497 | } 498 | 499 | /// Dummy get app id (xdg-surface only). 500 | pub fn get_app_id(self) -> String { 501 | self.app_id 502 | } 503 | 504 | /// Get the pid associated with this `WlcView`. 505 | pub fn get_pid(self) -> pid_t { 506 | self.pid 507 | } 508 | 509 | // TODO Mock these functions 510 | 511 | /// Dummy get the wl_client associated with this `WlcView`. 512 | /// 513 | /// Always return a null pointer 514 | #[cfg(feature="wlc-wayland")] 515 | pub fn get_client(self) -> *mut wl_client { 516 | ::std::ptr::null_mut() as *mut _ 517 | } 518 | 519 | /// Dummy get the wl_role associated with surface that this WLC view refers to. 520 | /// 521 | /// Always return a null pointer 522 | #[cfg(feature="wlc-wayland")] 523 | pub fn get_role(self) -> *mut wl_resource { 524 | ::std::ptr::null_mut() as *mut _ 525 | } 526 | 527 | #[cfg(feature="wlc-wayland")] 528 | /// Dummy turns a wl_surface into a wlc view. 529 | /// 530 | /// Always returns None 531 | pub fn view_from_surface(_surface: WlcResource, 532 | _client: *mut wl_client, 533 | _interface: *const wl_interface, 534 | _implementation: *const c_void, 535 | _version: uint32_t, 536 | _id: uint32_t, 537 | _userdata: *mut c_void ) 538 | -> Option { 539 | None 540 | } 541 | } 542 | -------------------------------------------------------------------------------- /src/dummy_input.rs: -------------------------------------------------------------------------------- 1 | //! Contains methods for interacting with the pointer 2 | //! and keyboard of wlc. 3 | 4 | #![allow(unused_variables)] 5 | #![allow(dead_code)] 6 | #![allow(deprecated)] 7 | 8 | pub mod pointer { 9 | //! Methods for interacting with the mouse 10 | use super::super::types::{Point}; 11 | 12 | /// Gets the current position of the mouse. 13 | pub fn get_position() -> Point { 14 | let point = Point { x: 0, y: 0 }; 15 | return point; 16 | } 17 | 18 | /// Sets the current mouse position. Required on mouse move callback. 19 | pub fn set_position(point: Point) { 20 | } 21 | } 22 | 23 | pub mod keyboard { 24 | //! Methods for interacting with the keyboard 25 | use super::super::types::{KeyboardModifiers}; 26 | use super::super::xkb::Keysym; 27 | 28 | /// Get currently held keys. 29 | /// # Panics 30 | /// All the time, this function hasn't been implemented yet 31 | pub fn get_current_keys<'a>() -> &'a[u32] { 32 | unimplemented!(); 33 | } 34 | 35 | /// Gets a keysym given a key and modifiers. 36 | pub fn get_keysym_for_key(key: u32, modifiers: KeyboardModifiers) -> Keysym { 37 | unimplemented!() 38 | } 39 | 40 | /// Gets a UTF32 value for a given key and modifiers. 41 | pub fn get_utf32_for_key(key: u32, modifiers: KeyboardModifiers) -> u32 { 42 | unimplemented!() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/dummy_wayland.rs: -------------------------------------------------------------------------------- 1 | //! Dummy code for wayland functions 2 | use wayland_sys::server::{wl_display}; 3 | 4 | use libc::uintptr_t; 5 | 6 | use types::{Size, Geometry}; 7 | 8 | 9 | /// ## Requires `wlc-wayland` feature 10 | /// 11 | /// A wlc resource for Wayland interop 12 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 13 | pub struct WlcResource { 14 | handle: uintptr_t, 15 | size: Size, 16 | subsurface_geometry: Geometry, 17 | subsurfaces: Vec 18 | } 19 | 20 | /// Get the wayland display for the current session. 21 | /// 22 | /// Always panics. 23 | pub fn get_display() -> *mut wl_display { 24 | unimplemented!() 25 | } 26 | 27 | 28 | impl WlcResource { 29 | /// # Requires `wlc-wayland` feature 30 | /// 31 | /// Gets the size of this surface 32 | pub fn get_surface_size(self) -> Size { 33 | self.size 34 | } 35 | 36 | /// Gets the inner uintptr_t value that resource uses. 37 | pub fn get_raw(self) -> uintptr_t { 38 | self.handle 39 | } 40 | 41 | /// ## Requires `wlc-wayland` feature 42 | /// 43 | /// Gets a list of subsurfaces from the given view 44 | pub fn get_subsurfaces(self) -> Vec { 45 | self.subsurfaces 46 | } 47 | 48 | /// # Requires `wlc-wayland` feature 49 | /// 50 | /// Gets the subsurface geometry of this WlcResource 51 | pub fn get_subsurface_geometry(self) -> Geometry { 52 | self.subsurface_geometry 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/handle.rs: -------------------------------------------------------------------------------- 1 | //! Contains definitions for wlc handle types. 2 | //! 3 | //! # Implementations 4 | //! - **Debug**: pointer-prints the underlying `uintptr_t` handle 5 | //! - **Eq, Ord**: compare the underlying `uintptr_t` handle 6 | //! - **Clone**: View handles can safely be cloned. 7 | use std::fmt::{self, Debug}; 8 | 9 | // TODO Remove all this dummy flag, this should basically not change 10 | 11 | extern crate libc; 12 | use libc::{uintptr_t, c_char, c_void, uint32_t, pid_t}; 13 | 14 | #[cfg(feature="wlc-wayland")] 15 | use wayland_sys::server::{wl_resource, wl_client}; 16 | 17 | #[cfg(feature="wlc-wayland")] 18 | use wayland_sys::common::wl_interface; 19 | 20 | #[cfg(feature="wlc-wayland")] 21 | use super::wayland::WlcResource; 22 | 23 | use super::pointer_to_string; 24 | use super::types::{Geometry, ResizeEdge, Point, Size, ViewType, ViewState}; 25 | use super::render::{wlc_output_get_renderer, wlc_output_schedule_render, wlc_renderer}; 26 | 27 | #[repr(C)] 28 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 29 | /// Represents a handle to a wlc view. 30 | /// 31 | pub struct WlcView(pub uintptr_t); 32 | 33 | impl fmt::Debug for WlcView { 34 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 35 | f.debug_struct("WlcView") 36 | .field("handle", &self.0 as &Debug) 37 | .field("title", &self.get_title() as &Debug) 38 | .field("class", &self.get_class() as &Debug) 39 | .finish() 40 | } 41 | } 42 | 43 | impl fmt::Display for WlcView { 44 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 45 | let mut name = self.get_title(); 46 | if name.is_empty() { 47 | name = self.get_class(); 48 | if name.is_empty() { 49 | name = format!("WlcView({handle})", handle=self.0); 50 | } 51 | } 52 | write!(f, "WlcOutput {{ name: {name} }}", name=name) 53 | } 54 | } 55 | 56 | #[repr(C)] 57 | #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 58 | /// Represents a handle to a wlc output. 59 | pub struct WlcOutput(pub uintptr_t); 60 | 61 | impl fmt::Debug for WlcOutput { 62 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 63 | f.debug_struct("WlcOutput") 64 | .field("handle", &self.0 as &Debug) 65 | .field("name", &self.get_name() as &Debug) 66 | .field("views", &self.get_views() as &Debug) 67 | .finish() 68 | } 69 | } 70 | 71 | impl fmt::Display for WlcOutput { 72 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 73 | let name = self.get_name(); 74 | write!(f, "WlcOutput {{ handle: {handle} name: {name} }}", handle=self.0, name=name) 75 | } 76 | } 77 | 78 | #[cfg_attr(feature = "static-wlc", link(name = "wlc", kind = "static"))] 79 | #[cfg_attr(not(feature = "static-wlc"), link(name = "wlc"))] 80 | extern "C" { 81 | fn wlc_get_outputs(memb: *mut libc::size_t) -> *const libc::uintptr_t; 82 | 83 | fn wlc_get_focused_output() -> uintptr_t; 84 | 85 | fn wlc_output_get_name(output: uintptr_t) -> *const c_char; 86 | 87 | fn wlc_handle_get_user_data(handle: uintptr_t) -> *mut c_void; 88 | 89 | fn wlc_handle_set_user_data(handle: uintptr_t, userdata: *const c_void); 90 | 91 | fn wlc_output_get_sleep(output: uintptr_t) -> bool; 92 | 93 | fn wlc_output_set_sleep(output: uintptr_t, sleep: bool); 94 | 95 | fn wlc_output_get_resolution(output: uintptr_t) -> *const Size; 96 | 97 | fn wlc_output_set_resolution(output: uintptr_t, resolution: *const Size, scale: uint32_t); 98 | 99 | fn wlc_output_get_scale(output: uintptr_t) -> uint32_t; 100 | 101 | fn wlc_output_get_virtual_resolution(output: uintptr_t) -> *const Size; 102 | 103 | fn wlc_output_get_mask(output: uintptr_t) -> u32; 104 | 105 | fn wlc_output_set_mask(output: uintptr_t, mask: u32); 106 | 107 | // TODO tricky definition here 108 | //fn wlc_output_get_pixels(output: WlcHandle) -> (); 109 | 110 | fn wlc_output_get_views(output: uintptr_t, 111 | out_memb: *mut libc::size_t) -> *const uintptr_t; 112 | 113 | fn wlc_output_set_views(output: uintptr_t, views: *const uintptr_t, memb: libc::size_t) -> bool; 114 | 115 | fn wlc_output_focus(output: uintptr_t); 116 | 117 | // View API 118 | 119 | fn wlc_view_focus(view: uintptr_t); 120 | 121 | fn wlc_view_close(view: uintptr_t); 122 | 123 | // View -> Output 124 | fn wlc_view_get_output(view: uintptr_t) -> uintptr_t; 125 | 126 | // "set output. Alternatively you can use wlc_output_set_views" 127 | fn wlc_view_set_output(view: uintptr_t, output: uintptr_t); 128 | 129 | fn wlc_view_send_to_back(view: uintptr_t); 130 | 131 | fn wlc_view_send_below(view: uintptr_t, other: uintptr_t); 132 | 133 | fn wlc_view_bring_above(view: uintptr_t, other: uintptr_t); 134 | 135 | fn wlc_view_bring_to_front(view: uintptr_t); 136 | 137 | fn wlc_view_get_mask(view: uintptr_t) -> u32; 138 | 139 | fn wlc_view_set_mask(view: uintptr_t, mask: u32); 140 | 141 | fn wlc_view_get_geometry(view: uintptr_t) -> *const Geometry; 142 | 143 | fn wlc_view_get_visible_geometry(view: uintptr_t, geo: *mut Geometry); 144 | 145 | fn wlc_view_set_geometry(view: uintptr_t, edges: u32, geo: *const Geometry); 146 | 147 | fn wlc_view_get_type(view: uintptr_t) -> u32; 148 | 149 | fn wlc_view_set_type(view: uintptr_t, view_type: u32, toggle: bool); 150 | 151 | fn wlc_view_get_state(view: uintptr_t) -> u32; 152 | 153 | fn wlc_view_set_state(view: uintptr_t, state: u32, toggle: bool); 154 | 155 | // Parent is Option 156 | fn wlc_view_get_parent(view: uintptr_t) -> uintptr_t; 157 | 158 | // Parent is Option 159 | fn wlc_view_set_parent(view: uintptr_t, parent: uintptr_t); 160 | 161 | fn wlc_view_get_title(view: uintptr_t) -> *const c_char; 162 | 163 | fn wlc_view_get_class(view: uintptr_t) -> *const c_char; 164 | 165 | fn wlc_view_get_app_id(view: uintptr_t) -> *const c_char; 166 | 167 | fn wlc_view_get_pid(view: uintptr_t)-> pid_t; 168 | 169 | #[cfg(feature="wlc-wayland")] 170 | fn wlc_handle_from_wl_surface_resource(resource: *const wl_resource) -> uintptr_t; 171 | 172 | #[cfg(feature="wlc-wayland")] 173 | pub fn wlc_handle_from_wl_output_resource(resource: *const wl_resource) -> uintptr_t; 174 | 175 | #[cfg(feature="wlc-wayland")] 176 | fn wlc_view_get_surface(view: uintptr_t) -> uintptr_t; 177 | 178 | #[cfg(feature="wlc-wayland")] 179 | fn wlc_view_get_wl_client(view: uintptr_t) -> *mut wl_client; 180 | 181 | #[cfg(feature="wlc-wayland")] 182 | fn wlc_view_get_role(view: uintptr_t) -> *mut wl_resource; 183 | 184 | #[cfg(feature="wlc-wayland")] 185 | fn wlc_view_from_surface(surface: uintptr_t, client: *const wl_client, interface: *const wl_interface, 186 | implementation: *const c_void, version: uint32_t, id: uint32_t, userdata: *mut c_void) 187 | -> uintptr_t; 188 | } 189 | 190 | #[cfg(feature="wlc-wayland")] 191 | impl Into for WlcView { 192 | fn into(self) -> WlcResource { 193 | WlcResource::from(unsafe { wlc_view_get_surface(self.0) } ) 194 | } 195 | } 196 | 197 | #[cfg(feature = "wlc-wayland")] 198 | impl Into for wl_resource { 199 | fn into(self) -> WlcView { 200 | unsafe { WlcView(wlc_handle_from_wl_surface_resource(&self)) } 201 | } 202 | } 203 | 204 | impl From for WlcOutput { 205 | fn from(view: WlcView) -> Self { 206 | WlcOutput(view.0) 207 | } 208 | } 209 | 210 | impl From for WlcView { 211 | fn from(output: WlcOutput) -> Self { 212 | WlcView(output.0) 213 | } 214 | } 215 | 216 | #[cfg(feature="wlc-wayland")] 217 | impl Into for wl_resource { 218 | fn into(self) -> WlcOutput { 219 | unsafe { WlcOutput(wlc_handle_from_wl_output_resource(&self)) } 220 | } 221 | } 222 | 223 | impl WlcOutput { 224 | /// Compatability/debugging function. 225 | /// 226 | /// wlc internally stores views and outputs under the same type. 227 | /// If for some reason a conversion between the two was required, 228 | /// this function could be called. If this is the case please submit 229 | /// a bug report. 230 | pub fn as_view(self) -> WlcView { 231 | WlcView::from(self) 232 | } 233 | 234 | /// Determines if this is a null a output (invalid). 235 | #[inline] 236 | pub fn is_null(self) -> bool { 237 | self.0 == 0 238 | } 239 | 240 | /// Create a dummy WlcOutput for testing purposes. 241 | /// 242 | /// # Unsafety 243 | /// The following operations on a dummy WlcOutput will cause crashes: 244 | /// 245 | /// - `WlcOutput::focused` when wlc is not running 246 | /// - `WlcOutput::list` when wlc is not running 247 | /// - `WlcOutput::set_resolution` on a dummy output 248 | /// 249 | /// In addition, `WlcOutput::set_views` will return an error. 250 | /// 251 | /// All other methods can be used on dummy outputs. 252 | /// 253 | /// # Example 254 | /// ```rust 255 | /// # use rustwlc::WlcOutput; 256 | /// unsafe { 257 | /// let output = WlcOutput::dummy(0u32); 258 | /// let output2 = WlcOutput::dummy(1u32); 259 | /// assert!(output < output2); 260 | /// assert!(output != output2); 261 | /// } 262 | /// ``` 263 | pub unsafe fn dummy(code: u32) -> WlcOutput { 264 | WlcOutput(code as libc::uintptr_t) 265 | } 266 | 267 | /// Gets user-specified data. 268 | /// 269 | /// # Unsafety 270 | /// The wlc implementation of this method uses `void*` pointers 271 | /// for raw C data. This function will internaly do a conversion 272 | /// between the input `T` and a `libc::c_void`. 273 | /// 274 | /// This is a highly unsafe conversion with no guarantees. As 275 | /// such, usage of these functions requires an understanding of 276 | /// what data they will have. Please review wlc's usage of these 277 | /// functions before attempting to use them yourself. 278 | pub unsafe fn get_user_data(&self) -> Option<&mut T> { 279 | let raw_data = wlc_handle_get_user_data(self.0); 280 | (raw_data as *mut T).as_mut() 281 | } 282 | 283 | /// Sets user-specified data. 284 | /// 285 | /// # Unsafety 286 | /// The wlc implementation of this method uses `void*` pointers 287 | /// for raw C data. This function will internaly do a conversion 288 | /// between the input `T` and a `libc::c_void`. 289 | /// 290 | /// This is a highly unsafe conversion with no guarantees. As 291 | /// such, usage of these functions requires an understanding of 292 | /// what data they will have. Please review wlc's usage of these 293 | /// functions before attempting to use them yourself. 294 | pub unsafe fn set_user_data(&self, data: &T) { 295 | let data_ptr: *const c_void = data as *const _ as *const c_void; 296 | wlc_handle_set_user_data(self.0, data_ptr); 297 | } 298 | 299 | /// Schedules output for rendering next frame. 300 | /// 301 | /// If the output was already scheduled, this is 302 | /// a no-op; if output is currently rendering, 303 | /// it will render immediately after. 304 | pub fn schedule_render(self) { 305 | unsafe { wlc_output_schedule_render(self.0) }; 306 | } 307 | 308 | /// Gets a list of the current outputs. 309 | /// 310 | /// # Safety 311 | /// This function will crash the program if run when wlc is not running. 312 | pub fn list() -> Vec { 313 | unsafe { 314 | let mut out_memb: libc::size_t = 0; 315 | let outputs = wlc_get_outputs(&mut out_memb); 316 | let mut result = Vec::with_capacity(out_memb); 317 | if !outputs.is_null() { 318 | for index in (0 as isize) .. (out_memb as isize) { 319 | result.push(WlcOutput(*outputs.offset(index))); 320 | } 321 | } 322 | result 323 | } 324 | } 325 | 326 | /// Gets the currently focused output. 327 | /// 328 | /// # Safety 329 | /// This function will crash the program if run when wlc is not running. 330 | pub fn focused() -> WlcOutput { 331 | unsafe { WlcOutput(wlc_get_focused_output()) } 332 | } 333 | 334 | /// Gets the name of the WlcOutput. 335 | /// 336 | /// Names are usually assigned in the format WLC-n, 337 | /// where the first output is WLC-1. 338 | pub fn get_name(self) -> String { 339 | unsafe { 340 | let name = wlc_output_get_name(self.0); 341 | pointer_to_string(name) 342 | } 343 | } 344 | 345 | /// Gets the sleep status of the output. 346 | /// 347 | /// Returns `true` if the monitor is sleeping, 348 | /// such as having been set with `set_sleep`. 349 | pub fn get_sleep(self) -> bool { 350 | unsafe { wlc_output_get_sleep(self.0) } 351 | } 352 | 353 | /// Sets the sleep status of the output. 354 | pub fn set_sleep(self, sleep: bool) { 355 | unsafe { wlc_output_set_sleep(self.0, sleep); } 356 | } 357 | 358 | /// Gets the output's real resolution. Do not use for coordinate boundary. 359 | pub fn get_resolution(self) -> Option { 360 | unsafe { wlc_output_get_resolution(self.0).as_ref().map(|&x| x) } 361 | } 362 | 363 | /// Get the virtual resolution. Helpful for getting resolution on high dpi displays. 364 | /// Use this to calculate coordinate boundary. 365 | pub fn get_virtual_resolution(self) -> Option { 366 | unsafe { wlc_output_get_virtual_resolution(self.0).as_ref().map(|&x| x) } 367 | } 368 | 369 | /// Sets the resolution of the output. 370 | /// 371 | /// # Safety 372 | /// This method will crash the program if use when wlc is not running. 373 | pub fn set_resolution(self, size: Size, scaling: u32) { 374 | unsafe { wlc_output_set_resolution(self.0, &size, scaling); } 375 | } 376 | 377 | /// Get the scaling for the output. 378 | pub fn get_scale(self) -> u32 { 379 | unsafe { wlc_output_get_scale(self.0) as u32} 380 | } 381 | 382 | /// Get views in stack order. 383 | /// 384 | /// This is mainly useful for wm's who need another view stack for inplace sorting. 385 | /// For example tiling wms, may want to use this to keep their tiling order separated 386 | /// from floating order. 387 | /// This handles `wlc_output_get_views` and `wlc_output_get_mutable_views`. 388 | pub fn get_views(self) -> Vec { 389 | unsafe { 390 | let mut out_memb: libc::size_t = 0; 391 | let views = wlc_output_get_views(self.0, &mut out_memb); 392 | let mut result = Vec::with_capacity(out_memb); 393 | if !views.is_null() { 394 | for index in (0 as isize) .. (out_memb as isize) { 395 | result.push(WlcView(*views.offset(index))); 396 | } 397 | } 398 | result 399 | } 400 | } 401 | 402 | /// Gets the mask of this output 403 | pub fn get_mask(self) -> u32 { 404 | unsafe { wlc_output_get_mask(self.0) } 405 | } 406 | 407 | /// Sets the mask for this output 408 | pub fn set_mask(self, mask: u32) { 409 | unsafe { wlc_output_set_mask(self.0, mask) } 410 | } 411 | 412 | /// # Deprecated 413 | /// This function is equivalent to simply calling get_views 414 | #[deprecated(since = "0.5.3", note = "please use `get_views`")] 415 | pub fn get_mutable_views(self) -> Vec { 416 | self.get_views() 417 | } 418 | 419 | /// Attempts to set the views of a given output. 420 | /// 421 | /// Returns success if operation succeeded. An error will be returned 422 | /// if something went wrong or if wlc isn't running. 423 | pub fn set_views(self, views: &[WlcView]) -> Result<(), &'static str> { 424 | let view_len = views.len() as libc::size_t; 425 | let const_views = views.as_ptr() as *const uintptr_t; 426 | 427 | unsafe { 428 | if wlc_output_set_views(self.0, const_views, view_len) { 429 | Ok(()) 430 | } else { 431 | Err("Could not set views on output") 432 | } 433 | } 434 | } 435 | 436 | /// Focuses compositor on a specific output. 437 | /// 438 | /// Pass in Option::None for no focus. 439 | pub fn focus(output: Option) { 440 | unsafe { 441 | wlc_output_focus(output.map(|out| out.0).unwrap_or(0)) 442 | } 443 | } 444 | 445 | /// Gets the renderer in use for this `WlcOutput` 446 | pub fn get_render(&self) -> wlc_renderer { 447 | unsafe { 448 | wlc_output_get_renderer(self.0) 449 | } 450 | } 451 | } 452 | 453 | impl WlcView { 454 | /// Compatability/debugging function. 455 | /// 456 | /// wlc internally stores views and outputs under the same type. 457 | /// If for some reason a conversion between the two was required, 458 | /// this function could be called. If this is the case please submit 459 | /// a bug report. 460 | pub fn as_output(self) -> WlcOutput { 461 | WlcOutput::from(self) 462 | } 463 | 464 | /// Create a dummy WlcView for testing purposes. 465 | /// 466 | /// # Unsafety 467 | /// The following methods on views may crash the program: 468 | /// 469 | /// - `WlcView::focus` if wlc is not running 470 | /// - `WlcView::send_to_back` if wlc is not running 471 | /// - `WlcView::send_below` if wlc is not running 472 | /// - `WlcView::bring_above` if wlc is not running 473 | /// - `WlcView::bring_to_font` if wlc is not running 474 | /// 475 | /// All other methods can be used on dummy views. 476 | /// 477 | /// # Note 478 | /// `WlcView::root()` is equivalent to `WlcView::dummy(0)`. 479 | /// 480 | /// ```rust 481 | /// # use rustwlc::WlcView; 482 | /// assert!(WlcView::root() == unsafe { WlcView::dummy(0) }) 483 | /// ``` 484 | /// # Example 485 | /// ```rust 486 | /// # use rustwlc::WlcView; 487 | /// unsafe { 488 | /// let view = WlcView::dummy(0u32); 489 | /// let view2 = WlcView::dummy(1u32); 490 | /// assert!(view < view2); 491 | /// assert!(view != view2); 492 | /// } 493 | /// ``` 494 | pub unsafe fn dummy(code: u32) -> WlcView { 495 | WlcView(code as uintptr_t) 496 | } 497 | 498 | /// Returns a reference to the root window (desktop background). 499 | /// 500 | /// # Example 501 | /// ``` 502 | /// # use rustwlc::WlcView; 503 | /// let view = WlcView::root(); 504 | /// assert!(view.is_root()); 505 | /// ``` 506 | pub fn root() -> WlcView { 507 | WlcView(0) 508 | } 509 | 510 | /// Whether this view is the root window (desktop background). 511 | /// 512 | /// # Example 513 | /// ```rust 514 | /// # use rustwlc::WlcView; 515 | /// # // This example can be run because WlcView::root() does not interact with wlc 516 | /// let view = WlcView::root(); 517 | /// assert!(view.is_root()); 518 | /// ``` 519 | #[inline] 520 | pub fn is_root(self) -> bool { 521 | self.0 == 0 522 | } 523 | 524 | /// Whether this view is not the root window (desktop background). 525 | /// 526 | /// # Usage 527 | /// A convenience method, the opposite of `view.is_root()`. 528 | /// 529 | /// # Example 530 | /// ```rust 531 | /// # use rustwlc::WlcView; 532 | /// let view = WlcView::root(); 533 | /// assert!(view.is_root()); 534 | /// assert!(!view.is_window()); 535 | /// ``` 536 | #[inline] 537 | pub fn is_window(self) -> bool { 538 | self.0 != 0 539 | } 540 | 541 | /// Gets user-specified data. 542 | /// 543 | /// # Unsafety 544 | /// The wlc implementation of this method uses `void*` pointers 545 | /// for raw C data. This function will internaly do a conversion 546 | /// between the input `T` and a `libc::c_void`. 547 | /// 548 | /// This is a highly unsafe conversion with no guarantees. As 549 | /// such, usage of these functions requires an understanding of 550 | /// what data they will have. Please review wlc's usage of these 551 | /// functions before attempting to use them yourself. 552 | pub unsafe fn get_user_data(&self) -> Option<&mut T> { 553 | (wlc_handle_get_user_data(self.0) as *mut T).as_mut() 554 | } 555 | 556 | /// Sets user-specified data. 557 | /// 558 | /// # Unsafety 559 | /// The wlc implementation of this method uses `void*` pointers 560 | /// for raw C data. This function will internaly do a conversion 561 | /// between the input `T` and a `libc::c_void`. 562 | /// 563 | /// This is a highly unsafe conversion with no guarantees. As 564 | /// such, usage of these functions requires an understanding of 565 | /// what data they will have. Please review wlc's usage of these 566 | /// functions before attempting to use them yourself. 567 | pub unsafe fn set_user_data(&self, data: &T) { 568 | let data_ptr: *const c_void = data as *const _ as *const c_void; 569 | wlc_handle_set_user_data(self.0, data_ptr); 570 | } 571 | 572 | /// Closes this view. 573 | /// 574 | /// For the main windows of most programs, this should close the program where applicable. 575 | /// 576 | /// # Behavior 577 | /// This function will not do anything if `view.is_root()`. 578 | pub fn close(self) { 579 | if self.is_root() { return }; 580 | unsafe { wlc_view_close(self.0); } 581 | } 582 | 583 | /// Gets the WlcOutput this view is currently part of. 584 | pub fn get_output(self) -> WlcOutput { 585 | unsafe { WlcOutput(wlc_view_get_output(self.0)) } 586 | } 587 | 588 | /// Sets the output that the view renders on. 589 | /// 590 | /// This may not be supported by wlc at this time. 591 | pub fn set_output(self, output: WlcOutput) { 592 | unsafe { wlc_view_set_output(self.0, output.0) } 593 | } 594 | 595 | /// Brings this view to focus. 596 | /// 597 | /// Can be called on `WlcView::root()` to lose all focus. 598 | pub fn focus(self) { 599 | unsafe { wlc_view_focus(self.0); } 600 | } 601 | 602 | /// Sends the view to the back of the compositor 603 | pub fn send_to_back(self) { 604 | unsafe { wlc_view_send_to_back(self.0); } 605 | } 606 | 607 | /// Sends this view underneath another. 608 | pub fn send_below(self, other: WlcView) { 609 | unsafe { wlc_view_send_below(self.0, other.0); } 610 | } 611 | 612 | /// Brings this view above another. 613 | pub fn bring_above(self, other: WlcView) { 614 | unsafe { wlc_view_bring_above(self.0, other.0); } 615 | } 616 | 617 | /// Brings this view to the front of the stack 618 | /// within its WlcOutput. 619 | pub fn bring_to_front(self) { 620 | unsafe { wlc_view_bring_to_front(self.0); } 621 | } 622 | 623 | // TODO Get masks enum working properly 624 | /// Gets the current visibilty bitmask for the view. 625 | pub fn get_mask(self) -> u32 { 626 | unsafe { wlc_view_get_mask(self.0) } 627 | } 628 | 629 | // TODO Get masks enum working properly 630 | /// Sets the visibilty bitmask for the view. 631 | pub fn set_mask(self, mask: u32) { 632 | unsafe { wlc_view_set_mask(self.0, mask); } 633 | } 634 | 635 | /// Gets the geometry of the view. 636 | pub fn get_geometry(self) -> Option { 637 | unsafe { 638 | let geometry = wlc_view_get_geometry(self.0); 639 | if geometry.is_null() { 640 | None 641 | } else { 642 | Some(*geometry) 643 | } 644 | } 645 | } 646 | 647 | /// Gets the geometry of the view (that wlc displays). 648 | pub fn get_visible_geometry(self) -> Geometry { 649 | let mut geo = Geometry { origin: Point { x: 0, y: 0}, size: Size { w: 0, h: 0 }}; 650 | unsafe { 651 | wlc_view_get_visible_geometry(self.0, &mut geo); 652 | } 653 | geo 654 | } 655 | 656 | /// Sets the geometry of the view. 657 | /// 658 | /// Set edges if geometry is caused by interactive resize. 659 | pub fn set_geometry(self, edges: ResizeEdge, geometry: Geometry) { 660 | unsafe { wlc_view_set_geometry(self.0, edges.bits(), &geometry as *const Geometry); } 661 | } 662 | 663 | /// Gets the type bitfield of the curent view 664 | pub fn get_type(self) -> ViewType { 665 | unsafe { 666 | ViewType::from_bits(wlc_view_get_type(self.0)) 667 | .expect("View Type returned different bits") 668 | } 669 | } 670 | 671 | /// Set flag in the type field. Toggle indicates whether it is set. 672 | pub fn set_type(self, view_type: ViewType, toggle: bool) { 673 | unsafe { wlc_view_set_type(self.0, view_type.bits(), toggle); } 674 | } 675 | 676 | // TODO get bitflags enums 677 | /// Get the current ViewState bitfield. 678 | pub fn get_state(self) -> ViewState { 679 | unsafe { 680 | ViewState::from_bits(wlc_view_get_state(self.0)) 681 | .expect("View State returned different bits") 682 | } 683 | } 684 | 685 | /// Set ViewState bit. Toggle indicates whether it is set or not. 686 | pub fn set_state(self, state: ViewState, toggle: bool) { 687 | unsafe { wlc_view_set_state(self.0, state.bits(), toggle); } 688 | } 689 | 690 | /// Gets parent view, returns `WlcView::root()` if this view has no parent. 691 | pub fn get_parent(self) -> WlcView { 692 | unsafe { WlcView(wlc_view_get_parent(self.0)) } 693 | } 694 | 695 | /// Set the parent of this view. 696 | /// 697 | /// Call with `WlcView::root()` to make its parent the root window. 698 | pub fn set_parent(self, parent: &WlcView) { 699 | unsafe { wlc_view_set_parent(self.0, parent.0); } 700 | } 701 | 702 | /// Get the title of the view 703 | pub fn get_title(self) -> String { 704 | let chars: *const c_char; 705 | unsafe { 706 | chars = wlc_view_get_title(self.0); 707 | if chars == 0 as *const c_char { 708 | String::new() 709 | } else { 710 | pointer_to_string(chars) 711 | } 712 | } 713 | } 714 | 715 | /// Get class (shell surface only). 716 | pub fn get_class(self) -> String { 717 | let chars: *const c_char; 718 | unsafe { 719 | chars = wlc_view_get_class(self.0); 720 | if chars == 0 as *const c_char { 721 | String::new() 722 | } else { 723 | pointer_to_string(chars) 724 | } 725 | } 726 | } 727 | 728 | /// Get app id (xdg-surface only). 729 | pub fn get_app_id(self) -> String { 730 | let chars: *const c_char; 731 | unsafe { 732 | chars = wlc_view_get_app_id(self.0); 733 | if chars == 0 as *const c_char { 734 | String::new() 735 | } else { 736 | pointer_to_string(chars) 737 | } 738 | } 739 | } 740 | 741 | /// Get the pid associated with this `WlcView`. 742 | pub fn get_pid(self) -> pid_t { 743 | unsafe { wlc_view_get_pid(self.0) } 744 | } 745 | 746 | /// Get the wl_client associated with this `WlcView`. 747 | #[cfg(feature="wlc-wayland")] 748 | pub fn get_client(self) -> *mut wl_client { 749 | unsafe { wlc_view_get_wl_client(self.0) } 750 | } 751 | 752 | /// Get the wl_role associated with surface that this WLC view refers to. 753 | #[cfg(feature="wlc-wayland")] 754 | pub fn get_role(self) -> *mut wl_resource { 755 | unsafe { wlc_view_get_role(self.0) } 756 | } 757 | 758 | #[cfg(feature="wlc-wayland")] 759 | /// Turns a wl_surface into a wlc view. 760 | /// 761 | /// This will trigger the view.created callback. 762 | /// 763 | /// If you are not implementing a Wayland interface for the role, 764 | /// interface can be NULL. 765 | pub fn view_from_surface(surface: WlcResource, 766 | client: *mut wl_client, 767 | interface: *const wl_interface, 768 | implementation: *const c_void, 769 | version: uint32_t, 770 | id: uint32_t, 771 | userdata: *mut c_void ) 772 | -> Option { 773 | unsafe { 774 | let view_handle = wlc_view_from_surface(surface.get_raw(), client, 775 | interface, implementation, 776 | version, id, userdata); 777 | if view_handle == 0 { 778 | None 779 | } else { 780 | Some(WlcView(view_handle)) 781 | } 782 | } 783 | } 784 | } 785 | 786 | #[cfg(test)] 787 | mod tests { 788 | use super::super::*; 789 | 790 | #[test] 791 | fn dummy_views() { 792 | let dummy = unsafe { WlcView::dummy(1) }; 793 | assert!(!dummy.is_root(), "Dummy(1) is root"); 794 | assert!(dummy.is_window(), "Dummy(1) is root"); 795 | let _title = dummy.get_title(); 796 | let _class = dummy.get_class(); 797 | let _app_id = dummy.get_app_id(); 798 | // Let's do some stuff with views 799 | dummy.close(); // works 800 | let output = dummy.get_output(); 801 | assert!(output.0 == 0); 802 | dummy.set_output(output); 803 | // dummy.focus(); // SEGFAULTS 804 | // dummy.send_to_back(); 805 | // dummy.send_below(&dummy); 806 | // dummy.bring_above(&dummy); 807 | // dummy.bring_to_front(); 808 | let mask = dummy.get_mask(); 809 | dummy.set_mask(mask); 810 | let geometry = dummy.get_geometry(); 811 | assert!(geometry.is_none(), "Got geometry from dummy"); 812 | dummy.set_geometry(EDGE_NONE, Geometry { 813 | origin: Point { x: 0, y: 0 }, 814 | size: Size { w: 0, h: 0 } 815 | }); 816 | let view_type = dummy.get_type(); 817 | assert!(view_type.is_empty(), "Dummy had a view type"); 818 | dummy.set_type(ViewType::empty(), true); 819 | let view_state = dummy.get_state(); 820 | assert!(view_state.is_empty(), "Dummu had a view state"); 821 | dummy.set_state(view_state, true); 822 | let parent = dummy.get_parent(); 823 | assert!(parent.is_root(), "Dummy had real parent"); 824 | dummy.set_parent(&parent); 825 | } 826 | 827 | #[test] 828 | fn dummy_outputs() { 829 | let dummy = unsafe { WlcOutput::dummy(1) }; 830 | //let _current = WlcOutput::focused(); 831 | //let _outputs = WlcOutput::list(); 832 | //dummy.set_resolution(resolution.clone()); 833 | dummy.schedule_render(); 834 | let _name = dummy.get_name(); 835 | let sleep = dummy.get_sleep(); 836 | dummy.set_sleep(sleep); 837 | let views = dummy.get_views(); 838 | dummy.set_views(&views).unwrap_err(); 839 | let mask = dummy.get_mask(); 840 | dummy.set_mask(mask); 841 | WlcOutput::focus(Some(dummy)); 842 | } 843 | } 844 | -------------------------------------------------------------------------------- /src/input.rs: -------------------------------------------------------------------------------- 1 | //! Contains methods for interacting with the pointer 2 | //! and keyboard of wlc. 3 | 4 | use libc::{size_t, uint32_t}; 5 | use super::types::{KeyboardModifiers, Point}; 6 | 7 | #[cfg_attr(feature = "static-wlc", link(name = "wlc", kind = "static"))] 8 | #[cfg_attr(not(feature = "static-wlc"), link(name = "wlc"))] 9 | extern "C" { 10 | fn wlc_keyboard_get_current_keys(out_memb: *const size_t) -> *const uint32_t; 11 | 12 | fn wlc_keyboard_get_keysym_for_key(key: uint32_t, 13 | modifiers: *const KeyboardModifiers) -> uint32_t; 14 | 15 | fn wlc_keyboard_get_utf32_for_key(key: uint32_t, 16 | modifiers: *const KeyboardModifiers) -> uint32_t; 17 | 18 | // Pointer functions 19 | #[deprecated(since="0.7.0", note="Use wlc_pointer_get_position_v2 instead")] 20 | fn wlc_pointer_get_position(out_position: *mut Point); 21 | 22 | fn wlc_pointer_get_position_v2(out_x: &mut f64, out_y: &mut f64); 23 | 24 | #[deprecated(since="0.7.0", note="Use wlc_pointer_set_position_v2 instead")] 25 | fn wlc_pointer_set_position(position: *const Point); 26 | 27 | fn wlc_pointer_set_position_v2(x: f64, y: f64); 28 | } 29 | 30 | pub mod pointer { 31 | //! Methods for interacting with the mouse 32 | use super::super::types::{Point}; 33 | 34 | /// Gets the current position of the mouse. 35 | #[deprecated(since="0.7.0", note="Use get_position_v2()->(f64, f64) instead")] 36 | #[allow(deprecated)] 37 | pub fn get_position() -> Point { 38 | unsafe { 39 | let mut point = Point { x: 0, y: 0 }; 40 | super::wlc_pointer_get_position(&mut point); 41 | return point; 42 | } 43 | } 44 | 45 | /// Gets the current position of the mouse. 46 | pub fn get_position_v2() -> (f64, f64){ 47 | let (mut x, mut y) = (0.0, 0.0); 48 | unsafe{ 49 | super::wlc_pointer_get_position_v2(&mut x, &mut y); 50 | } 51 | (x, y) 52 | } 53 | 54 | /// Sets the current mouse position. Required on mouse move callback. 55 | #[deprecated(since="0.7.0", note="Use set_position_v2(x: f64, y: f64) instead")] 56 | #[allow(deprecated)] 57 | pub fn set_position(point: Point) { 58 | unsafe { super::wlc_pointer_set_position(&point); } 59 | } 60 | 61 | /// Sets the current mouse position. Required on mouse move callback. 62 | pub fn set_position_v2(x: f64, y: f64){ 63 | unsafe{ 64 | super::wlc_pointer_set_position_v2(x,y); 65 | } 66 | } 67 | } 68 | 69 | pub mod keyboard { 70 | //! Methods for interacting with the keyboard 71 | 72 | use std::slice; 73 | use libc::size_t; 74 | use super::super::types::KeyboardModifiers; 75 | #[allow(deprecated)] 76 | use super::super::xkb::Keysym; 77 | 78 | /// Get currently held keys. 79 | /// # Panics 80 | /// All the time, this function hasn't been implemented yet 81 | pub fn get_current_keys<'a>() -> Option<&'a[u32]> { 82 | let mut size: size_t = 0; 83 | unsafe { 84 | let out_ptr = super::wlc_keyboard_get_current_keys(&mut size); 85 | if size == 0 || out_ptr.is_null() { 86 | None 87 | } 88 | else { 89 | Some(slice::from_raw_parts(out_ptr, size as usize)) 90 | } 91 | } 92 | } 93 | 94 | /// Gets a keysym given a key and modifiers. 95 | /// 96 | /// In order to delay breaking backwards compatibility this method is _not_ 97 | /// deprecated. Please use `Keysym::raw` on the Keysym returned from this 98 | /// function for now. **In version 0.6 this will return a u32**. 99 | #[allow(deprecated)] 100 | pub fn get_keysym_for_key(key: u32, modifiers: KeyboardModifiers) -> Keysym { 101 | unsafe { 102 | Keysym::from(super::wlc_keyboard_get_keysym_for_key(key, &modifiers) as u32) 103 | } 104 | } 105 | 106 | /// Gets a UTF32 value for a given key and modifiers. 107 | pub fn get_utf32_for_key(key: u32, modifiers: KeyboardModifiers) -> u32 { 108 | unsafe { super::wlc_keyboard_get_utf32_for_key(key, &modifiers) } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! `rustwlc` is a wrapper for [wlc][], a library for writing a window 2 | //! manager using the [wayland][] protocol. Compositors using rustwlc will 3 | //! not need unsafe code for basic interaction with wayland. 4 | //! 5 | //! # wlc 6 | //! 7 | //! [wlc][] is a library written in C which acts as a wayland compositor. It 8 | //! provides abstractions over wayland via structs such as `WlcView`, 9 | //! `WlcOutput`, `Geometry`, or `KeyboardModifiers`. It provides callbacks 10 | //! (found in the `callback` module) for events such as `view_created`, 11 | //! `mouse_move`, or `view_focused`. 12 | //! 13 | //! # Example 14 | //! 15 | //! For more information on how to use rustwlc, see the `callbacks` module 16 | //! and the `run_wlc()` method. 17 | //! 18 | //! For a more complete example, see [the example program][] on 19 | //! [our GitHub page][]. 20 | //! 21 | //! ```rust 22 | //! extern crate rustwlc; 23 | //! use rustwlc::callback; 24 | //! // VIEW_ACTIVATED is a bitflags enum variant, and those must be imported 25 | //! // manually, or using a wildcatd. 26 | //! use rustwlc::{WlcView, VIEW_ACTIVATED}; 27 | //! 28 | //! // Callbacks must be labeled extern as they will be called from C 29 | //! extern "C" fn view_created(view: WlcView) -> bool { 30 | //! view.bring_to_front(); 31 | //! view.focus(); 32 | //! return true; 33 | //! } 34 | //! 35 | //! extern "C" fn view_focus(view: WlcView, focused: bool) { 36 | //! view.set_state(VIEW_ACTIVATED, focused); 37 | //! } 38 | //! 39 | //! // Entry point for a compositor 40 | //! fn compositor_main() { 41 | //! callback::view_created(view_created); 42 | //! callback::view_focus(view_focus); 43 | //! 44 | //! // The default log handler will print wlc logs to stdout 45 | //! rustwlc::log_set_default_handler(); 46 | //! let run_fn = rustwlc::init().expect("Unable to initialize!"); 47 | //! // This will run wlc's event loop and launch wayland. 48 | //! run_fn(); 49 | //! } 50 | //! # fn main() {} 51 | //! ``` 52 | //! For a more full-featured compositor using rustwlc, see [way-cooler][]. 53 | //! [wlc]: https://github.com/Cloudef/wlc 54 | //! [wayland]: https://wayland.freedesktop.org/ 55 | //! [the example program]: https://github.com/Immington-Industries/rust-wlc/blob/master/example/src/main.rs 56 | //! [our GitHub page]: https://github.com/Immington-Industries/rustwlc 57 | //! [way-cooler]: https://github.com/Immington-Industries/way-cooler 58 | 59 | #![warn(missing_docs)] 60 | 61 | extern crate libc; 62 | 63 | #[macro_use] 64 | extern crate bitflags; 65 | 66 | #[cfg(feature="wlc-wayland")] 67 | #[macro_use] 68 | extern crate wayland_sys; 69 | 70 | use std::ffi; 71 | 72 | #[cfg(feature = "dummy")] 73 | mod dummy_handle; 74 | 75 | #[cfg(not(feature = "dummy"))] 76 | pub mod handle; 77 | 78 | #[cfg(feature = "dummy")] 79 | pub mod dummy_callback; 80 | 81 | #[cfg(not(feature = "dummy"))] 82 | pub mod callback; 83 | pub mod types; 84 | 85 | #[cfg(feature = "dummy")] 86 | pub mod dummy_input; 87 | 88 | #[cfg(not(feature = "dummy"))] 89 | pub mod input; 90 | 91 | #[cfg(feature="wlc-wayland")] 92 | #[cfg(feature="dummy")] 93 | pub mod dummy_wayland; 94 | 95 | #[cfg(feature="wlc-wayland")] 96 | #[cfg(not(feature="dummy"))] 97 | pub mod wayland; 98 | 99 | #[deprecated] 100 | pub mod xkb; 101 | pub mod render; 102 | 103 | pub use types::*; 104 | 105 | #[cfg(not(feature = "dummy"))] 106 | pub use handle::{WlcOutput, WlcView}; 107 | 108 | #[cfg(feature = "dummy")] 109 | pub use dummy_handle::{WlcOutput, WlcView}; 110 | 111 | #[cfg(feature="wlc-wayland")] 112 | #[cfg(not(feature = "dummy"))] 113 | pub use wayland::WlcResource; 114 | 115 | #[cfg(feature="wlc-wayland")] 116 | #[cfg(feature = "dummy")] 117 | pub use dummy_wayland::WlcResource; 118 | 119 | // Log Handler hack 120 | #[cfg(not(feature = "dummy"))] 121 | static mut RUST_LOGGING_FN: fn(_type: LogType, string: &str) = default_log_callback; 122 | 123 | // External WLC functions 124 | 125 | #[cfg_attr(feature = "static-wlc", link(name = "wlc", kind = "static"))] 126 | #[cfg_attr(not(feature = "static-wlc"), link(name = "wlc"))] 127 | #[cfg(not(feature = "dummy"))] 128 | extern "C" { 129 | // init2 -> init :( 130 | fn wlc_init() -> bool; 131 | 132 | fn wlc_run(); 133 | 134 | fn wlc_terminate(); 135 | 136 | fn wlc_log_set_handler(callback: extern "C" fn(log_type: LogType, text: *const libc::c_char)); 137 | 138 | fn wlc_get_backend_type() -> BackendType; 139 | } 140 | 141 | /// Query backend wlc is using. 142 | /// 143 | /// # Results 144 | /// * None: Unknown backend type 145 | /// * DRM: "Direct Rendering Manager" - running on tty 146 | /// * X11: Running inside an X server 147 | #[cfg(not(feature = "dummy"))] 148 | pub fn get_backend_type() -> BackendType { 149 | unsafe { wlc_get_backend_type() } 150 | } 151 | 152 | /// Query backend wlc is using. 153 | /// For dummy feature, will always return `BackendType::None`. 154 | #[cfg(feature = "dummy")] 155 | pub fn get_backend_type() -> BackendType { 156 | BackendType::None 157 | } 158 | 159 | /// Initialize wlc's callbacks and logger with a `WlcInterface`. 160 | /// 161 | /// # Deprecated 162 | /// wlc has deprecated this callback interface. They offer a new API with a 163 | /// series of methods found in the `callback` module 164 | /// 165 | /// To initialize wlc, register your callbacks with the functions described in 166 | /// the `callbacks` module, and the logger using `log_set_handler` or 167 | /// `log_set_default_handler`. Then call `init2()`. 168 | /// 169 | /// # Permissions 170 | /// If a compositor is initialized from the tty using suid or logind, it will 171 | /// drop extra permissions after a call to `init()` or `init2()`. It is strongly 172 | /// recommended to delay code which is not registering callbacks until after 173 | /// this call. 174 | /// 175 | /// # wlc Example 176 | /// ```no_run 177 | /// use rustwlc; 178 | /// use rustwlc::callback; 179 | /// use rustwlc::WlcView; 180 | /// 181 | /// // An example callback function 182 | /// // See the various functions in the callback module for more information 183 | /// extern "C" fn view_focus_callback(view: WlcView, focused: bool) { 184 | /// println!("A view came into focus!"); 185 | /// } 186 | /// 187 | /// // Set a default log callback 188 | /// rustwlc::log_set_default_handler(); 189 | /// 190 | /// // Register some callbacks 191 | /// callback::view_focus(view_focus_callback); 192 | /// // ... and additional callbacks 193 | /// 194 | /// // The only thing your code should do before init2 is register callbacks 195 | /// // and log handlers. 196 | /// let run_wlc = rustwlc::init() 197 | /// .expect("Unable to initialize wlc!"); 198 | /// 199 | /// run_wlc(); 200 | /// ``` 201 | #[cfg(not(feature = "dummy"))] 202 | pub fn init() -> Option ()> { 203 | if unsafe { wlc_init() } { 204 | Some(run_wlc) 205 | } 206 | else { 207 | None 208 | } 209 | } 210 | 211 | /// For dummy, performs no initilization and returns the dummy version of 212 | /// `run_wlc` (which just prints a string to stdout). 213 | #[cfg(feature = "dummy")] 214 | pub fn init() -> Option ()> { 215 | Some(run_wlc) 216 | } 217 | 218 | /// Deprecated alias to init(). 219 | /// 220 | /// When wlc went to 0.0.1, they added an argumentless init2 221 | /// to replace the old init that took a WlcInterface. Now, 222 | /// init2 has been renamed init and init is removed. 223 | #[deprecated(since = "0.5.3", note = "please use `init`")] 224 | pub fn init2() -> Option ()> { 225 | init() 226 | } 227 | 228 | /// Runs wlc's event loop. 229 | /// 230 | /// The initialize functions will return this function in an Option. 231 | /// Only then can it be called to being wlc's main event loop. 232 | #[cfg(not(feature = "dummy"))] 233 | fn run_wlc() { 234 | unsafe { 235 | wlc_run(); 236 | } 237 | } 238 | 239 | #[cfg(feature = "dummy")] 240 | fn run_wlc() { 241 | println!("Dummy call to wlc_run") 242 | } 243 | 244 | /// Halts execution of wlc. 245 | #[cfg(not(feature = "dummy"))] 246 | pub fn terminate() { 247 | unsafe { 248 | wlc_terminate(); 249 | } 250 | } 251 | 252 | /// Dummy halt for wlc. Does nothing but print line to stdout. 253 | #[cfg(feature = "dummy")] 254 | pub fn terminate() { 255 | println!("Dummy call to wlc_terminate") 256 | } 257 | 258 | /// Registers a C callback for wlc logging. 259 | /// 260 | /// Note that `rustwlc::log_set_default_handler()` will register a simple callback 261 | /// that will print the type and text to the console. 262 | /// 263 | /// # Parameters 264 | /// The `handler` callback has two parameters: 265 | /// * `type`: The `LogType` of the message being printed. 266 | /// * `text`: The text to be logged, currently in C form. One may call `rustwlc::pointer_to_string` 267 | /// to convert it to a Rust String. 268 | /// 269 | /// # Safety 270 | /// The callback function (like other callbacks in `rustwlc`) must be marked as extern as it is called 271 | /// from C code. 272 | /// 273 | /// In addition, `unsafe` will be required to convert the text into a Rust String. 274 | #[cfg(not(feature = "dummy"))] 275 | pub fn log_set_handler(handler: extern "C" fn(type_: LogType, text: *const libc::c_char)) { 276 | unsafe { 277 | wlc_log_set_handler(handler); 278 | } 279 | } 280 | 281 | /// Dummy call to wlc_log_set_handler. Does nothing. 282 | #[cfg(feature = "dummy")] 283 | pub fn log_set_handler(_handler: extern "C" fn(type_: LogType, text: *const libc::c_char)) { 284 | println!("Dummy call to wlc_log_set_handler") 285 | } 286 | 287 | /// Registers a Rust callback for wlc logging. 288 | 289 | /// This is a nice convenience function that should be used in place of 290 | /// `log_set_handler`. That way you can just pass a safe Rust `&str` 291 | /// and not depend on libc`. 292 | #[cfg(not(feature = "dummy"))] 293 | pub fn log_set_rust_handler(handler: fn(type_: LogType, text: &str)) { 294 | // Set global handler function 295 | unsafe { 296 | RUST_LOGGING_FN = handler; 297 | extern "C" fn c_handler(type_: LogType, text: *const libc::c_char) { 298 | unsafe { 299 | let string = ffi::CStr::from_ptr(text).to_string_lossy().into_owned(); 300 | RUST_LOGGING_FN(type_, &string); 301 | } 302 | } 303 | wlc_log_set_handler(c_handler); 304 | } 305 | } 306 | 307 | /// Dummy call to wlc_log_set_handler w/ custom function. Does nothing. 308 | #[cfg(feature = "dummy")] 309 | pub fn log_set_rust_handler(_handler: fn(type_: LogType, text: &str)) { 310 | println!("Dummy call to wlc_log_set_handler w/ custom handler function") 311 | } 312 | 313 | fn default_log_callback(log_type: LogType, text: &str) { 314 | println!("wlc [{:?}] {}", log_type, text); 315 | } 316 | 317 | /// Sets the wlc log callback to a simple function that prints to console. 318 | /// 319 | /// Not calling any `log_set_handler` will have no logging, use this or 320 | /// `log_set_handler` with a callback to use wlc logging. 321 | /// 322 | /// # Example 323 | /// ```no_run 324 | /// use rustwlc; 325 | /// 326 | /// // An example where only the default log handler is registered 327 | /// rustwlc::log_set_default_handler(); 328 | /// 329 | /// if let Some(run_wlc) = rustwlc::init2() { 330 | /// run_wlc(); 331 | /// } 332 | /// else { 333 | /// panic!("Unable to initialize wlc!"); 334 | /// } 335 | /// ``` 336 | pub fn log_set_default_handler() { 337 | log_set_rust_handler(default_log_callback); 338 | } 339 | 340 | /// Unsafe strings conversion function. 341 | /// 342 | /// Converts a `*const libc::c_char` to an owned `String`. 343 | /// Useful for log callbacks. 344 | /// 345 | /// # Example 346 | /// Standard usage may be for the log callbacks. 347 | /// ```rust 348 | /// extern "C" fn default_log_callback(log_type: LogType, text: *const libc::c_char) { 349 | /// let string = unsafe { pointer_to_string(text) }; 350 | /// println!("wlc [{:?}]: {}", log_type, string); 351 | /// } 352 | /// ``` 353 | pub unsafe fn pointer_to_string(pointer: *const libc::c_char) -> String { 354 | if pointer.is_null() { 355 | return "".to_string(); 356 | } 357 | let slice = ffi::CStr::from_ptr(pointer); 358 | slice.to_string_lossy().into_owned() 359 | } 360 | -------------------------------------------------------------------------------- /src/render.rs: -------------------------------------------------------------------------------- 1 | //! Contains definitions for wlc render functions (wlc-render.h) 2 | 3 | use libc::{c_void, uint32_t, uintptr_t}; 4 | use std::mem; 5 | use super::types::{Geometry}; 6 | 7 | /// Number of bits per pixel (RGBA8888) 8 | pub const BITS_PER_PIXEL: u32 = 32; 9 | 10 | #[repr(C)] 11 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 12 | /// Allowed pixel formats 13 | pub enum wlc_pixel_format { 14 | /// RGBA8888 format 15 | WLC_RGBA8888 16 | } 17 | 18 | #[repr(C)] 19 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 20 | /// Enabled renderers 21 | pub enum wlc_renderer { 22 | /// Render using GLE 23 | WLC_RENDERER_GLES2, 24 | /// Don't render (headless) 25 | WLC_NO_RENDERER 26 | } 27 | 28 | #[allow(missing_docs)] 29 | #[repr(C)] 30 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 31 | pub enum wlc_surface_format { 32 | SURFACE_RGB, 33 | SURFACE_RGBA, 34 | SURFACE_EGL, 35 | SURFACE_Y_UV, 36 | SURFACE_Y_U_V, 37 | SURFACE_Y_XUXV, 38 | } 39 | 40 | #[cfg_attr(feature = "static-wlc", link(name = "wlc", kind = "static"))] 41 | #[cfg_attr(not(feature = "static-wlc"), link(name = "wlc"))] 42 | extern "C" { 43 | /// Write pixel data with the specific format to output's framebuffer. 44 | /// If the geometry is out of bounds, it will be automatically clamped. 45 | pub fn wlc_pixels_write(format: wlc_pixel_format, geometry: *const Geometry, data: *const c_void); 46 | 47 | pub fn wlc_pixels_read(format: wlc_pixel_format, 48 | geometry: *const Geometry, 49 | out_geo: *mut Geometry, 50 | data: *mut c_void); 51 | 52 | /** Renders surface. */ 53 | pub fn wlc_surface_render(surface: uintptr_t, geometry: *const Geometry); 54 | 55 | /// Read pixel data from output's framebuffer. 56 | /// If theif output is currently rendering, it will render immediately after. 57 | pub fn wlc_output_schedule_render(output: uintptr_t) -> wlc_renderer; 58 | 59 | /// Adds frame callbacks of the given surface for the next output frame. 60 | /// It applies recursively to all subsurfaces. 61 | /// Useful when the compositor creates custom animations which require disabling internal rendering, 62 | /// but still need to update the surface textures (for ex. video players). 63 | pub fn wlc_surface_flush_frame_callbacks(surface: uintptr_t); 64 | 65 | /// Returns currently active renderer on the given output 66 | pub fn wlc_output_get_renderer(output: uintptr_t) -> wlc_renderer; 67 | 68 | /// Fills out_textures[] with the textures of a surface. Returns false if surface is invalid. 69 | /// Array must have at least 3 elements and should be refreshed at each frame. 70 | /// Note that these are not only OpenGL textures but rather render-specific. 71 | /// For more info what they are check the renderer's source code */ 72 | pub fn wlc_surface_get_textures(surface: uintptr_t, 73 | out_textures: *mut uint32_t, 74 | out_format: *mut wlc_surface_format) -> bool; 75 | 76 | pub fn wlc_output_set_gamma(output: uintptr_t, 77 | size: u16, 78 | red: *mut u16, 79 | green: *mut u16, 80 | blue: *mut u16); 81 | 82 | pub fn wlc_output_get_gamma_size(output: uintptr_t) -> u16 ; 83 | } 84 | 85 | 86 | /// Write pixel data with the specific format to output's framebuffer. 87 | /// If the geometry is out of bounds, it will be automatically clamped. 88 | /// 89 | /// # Unsafety 90 | /// The data is converted to a *mut c_void and then passed to C to read. 91 | /// The size of it should be the stride of the geometry * height of the geometry. 92 | pub fn write_pixels(format: wlc_pixel_format, geometry: Geometry, data: &[u8]) { 93 | unsafe { 94 | let data = data as *const _ as *const c_void; 95 | wlc_pixels_write(format, &geometry as *const Geometry, data); 96 | } 97 | } 98 | 99 | /// Reads the pixels at the specified geometry 100 | pub fn read_pixels(format: wlc_pixel_format, mut geometry: Geometry) -> ([u8; 9], Vec) { 101 | let data_size = (geometry.size.w * geometry.size.h * 4) as usize; 102 | // magic response header size 103 | let header_size = 9; 104 | let mut in_buf: Vec = Vec::with_capacity(header_size + data_size); 105 | let in_buf_ptr = in_buf.as_mut_ptr(); 106 | mem::forget(in_buf); 107 | let mut out_buf = unsafe { 108 | let mut out_geo = Geometry::zero(); 109 | wlc_pixels_read(format, 110 | &mut geometry as *mut _, 111 | &mut out_geo as *mut _, 112 | in_buf_ptr as *mut c_void); 113 | // TODO read the header for this information! 114 | let size = header_size + 115 | out_geo.size.w as usize * out_geo.size.h as usize * 4; 116 | Vec::from_raw_parts(in_buf_ptr, size, size) 117 | }; 118 | let mut header_response = [0u8; 9]; 119 | let response: Vec = out_buf.drain(0..9).collect(); 120 | header_response.copy_from_slice(response.as_slice()); 121 | (header_response, out_buf) 122 | } 123 | 124 | /// Calculates the stride for ARGB32 encoded buffers 125 | pub fn calculate_stride(width: u32) -> u32 { 126 | // function stolen from CAIRO_STRIDE_FOR_WIDTH macro in carioint.h 127 | // can be found in the most recent version of the cairo source 128 | let stride_alignment = ::std::mem::size_of::() as u32; 129 | ((BITS_PER_PIXEL * width + 7 ) / 8 + (stride_alignment - 1)) & (stride_alignment.overflowing_neg().0) 130 | } 131 | -------------------------------------------------------------------------------- /src/types.rs: -------------------------------------------------------------------------------- 1 | //! Contains struct and enum declarations for 2 | //! structs defined by wlc. 3 | 4 | use std::fmt; 5 | use std::cmp; 6 | 7 | /// Log level to pass into wlc logging 8 | #[repr(C)] 9 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 10 | pub enum LogType { 11 | /// Info log type 12 | Info, 13 | /// Warn log type 14 | Warn, 15 | /// Error log type 16 | Error, 17 | /// Wayland logs 18 | Wayland 19 | } 20 | 21 | /// Type of backend that a window is being composited in 22 | #[repr(C)] 23 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 24 | pub enum BackendType { 25 | /// Backend type is unknown 26 | None, 27 | /// Standard wayland client 28 | DRM, 29 | /// wayland-x11 client 30 | X11 31 | } 32 | 33 | bitflags! { 34 | /// Flags describing wayland events 35 | #[repr(C)] 36 | pub flags EventBit: u32 { 37 | /// Event can be read 38 | const EVENT_READABLE = 1, 39 | /// Event can be written 40 | const EVENT_WRITEABLE = 2, 41 | /// Event is hung up (?) 42 | const EVENT_HANGUP = 4, 43 | /// Event is in error 44 | const EVENT_ERROR = 8 45 | } 46 | } 47 | 48 | bitflags! { 49 | /// How window is being viewed 50 | #[repr(C)] 51 | pub flags ViewState: u32 { 52 | /// Window maximized 53 | const VIEW_MAXIMIZED = 1, 54 | /// Window fullscreen 55 | const VIEW_FULLSCREEN = 2, 56 | /// Window resizing 57 | const VIEW_RESIZING = 4, 58 | /// Window moving 59 | const VIEW_MOVING = 8, 60 | /// Window activated 61 | const VIEW_ACTIVATED = 16 62 | } 63 | } 64 | 65 | bitflags! { 66 | /// Viewtype - like x11 flags 67 | #[repr(C)] 68 | pub flags ViewType: u32 { 69 | /// Override redirect (X11) 70 | const VIEW_BIT_OVERRIDE_REDIRECT = 1, 71 | /// Tooltips (X11) 72 | const VIEW_BIT_UNMANAGED = 2, 73 | /// Splash Screens (X11) 74 | const VIEW_BIT_SPLASH = 4, 75 | /// Modal Windows (X11) 76 | const VIEW_BIT_MODAL = 8, 77 | /// xdg-shell, wl-shell popups 78 | const VIEW_BIT_POPUP = 16 79 | } 80 | } 81 | 82 | bitflags! { 83 | /// Which edge is being used to resize a window. 84 | #[repr(C)] 85 | pub flags ResizeEdge: u32 { 86 | /// No edge 87 | const EDGE_NONE = 0, 88 | /// Top edge 89 | const RESIZE_TOP = 1, 90 | /// Bottom edge 91 | const RESIZE_BOTTOM = 2, 92 | /// Left edge 93 | const RESIZE_LEFT = 4, 94 | /// Top left edge 95 | const RESIZE_TOPLEFT = 5, 96 | /// Bottom left edge 97 | const RESIZE_BOTTOMLEFT = 6, 98 | /// Right edge 99 | const RESIZE_RIGHT = 8, 100 | /// Top right edge 101 | const RESIZE_TOPRIGHT = 9, 102 | /// Bottom right edge 103 | const RESIZE_BOTTOMRIGHT = 10 104 | } 105 | } 106 | 107 | bitflags! { 108 | /// Which view property is being updated 109 | #[repr(C)] 110 | pub flags ViewPropertyType: u32 { 111 | /// View title is being updated 112 | const PROPERTY_TITLE = 0, 113 | /// View class is being updated 114 | const PROPRETY_CLASS = 1, 115 | /// View app id is being updated 116 | const PROPERTY_APP_ID = 2, 117 | /// PID of the view is being updated 118 | const PROPERTY_PID = 4 119 | } 120 | } 121 | 122 | bitflags! { 123 | /// Represents which keyboard meta keys are being pressed. 124 | #[repr(C)] 125 | pub flags KeyMod: u32 { 126 | /// No modifiers 127 | const MOD_NONE = 0, 128 | /// Shift 129 | const MOD_SHIFT = 1, 130 | /// Caps lock 131 | const MOD_CAPS = 2, 132 | /// Control 133 | const MOD_CTRL = 4, 134 | /// Alt 135 | const MOD_ALT = 8, 136 | /// Mod2 137 | const MOD_MOD2 = 16, 138 | /// Mod3 139 | const MOD_MOD3 = 32, 140 | /// Mod4/logo 141 | const MOD_MOD4 = 64, 142 | /// 5Mod5Me 143 | const MOD_MOD5 = 128 144 | } 145 | } 146 | 147 | bitflags! { 148 | /// "LEDs" or active key-locks. 149 | /// i.e. caps lock, scroll lock 150 | #[repr(C)] 151 | pub flags KeyboardLed: u32 { 152 | /// Num lock is pressed 153 | const NUM_LOCK = 1, 154 | /// Caps lock is pressed 155 | const CAPS_LOCK = 2, 156 | /// Original typo of SCROLL_LOCK 157 | /// 158 | /// # Deprecated 159 | /// Please use SCROLL_LOCK instead. 160 | const SCROL_LLOCK = 4, 161 | /// Scroll lock key is being pressed. 162 | const SCROLL_LOCK = 4 163 | } 164 | } 165 | 166 | bitflags! { 167 | #[repr(C)] 168 | pub flags PositionerAnchorBit: u32 { 169 | const WLC_BIT_ANCHOR_NONE = 0, 170 | const WLC_BIT_ANCHOR_TOP = 1<<0, 171 | const WLC_BIT_ANCHOR_BOTTOM = 1<<1, 172 | const WLC_BIT_ANCHOR_LEFT = 1<<2, 173 | const WLC_BIT_ANCHOR_RIGHT = 1<<3 174 | } 175 | } 176 | 177 | bitflags! { 178 | #[repr(C)] 179 | pub flags PositionerGravityBit: u32 { 180 | const WLC_BIT_GRAVITY_NONE = 0, 181 | const WLC_BIT_GRAVITY_TOP = 1<<0, 182 | const WLC_BIT_GRAVITY_BOTTOM = 1<<1, 183 | const WLC_BIT_GRAVITY_LEFT = 1<<2, 184 | const WLC_BIT_GRAVITY_RIGHT = 1<<3 185 | 186 | } 187 | } 188 | 189 | bitflags! { 190 | #[repr(C)] 191 | pub flags PositionerConstraintAdjustmentBits: u32 { 192 | const WLC_BIT_CONSTRAINT_ADJUSTMENT_NONE = 0, 193 | const WLC_BIT_CONSTRAINT_ADJUSTMENT_SLIDE_X = 1<<0, 194 | const WLC_BIT_CONSTRAINT_ADJUSTMENT_SLIDE_Y = 1<<1, 195 | const WLC_BIT_CONSTRAINT_ADJUSTMENT_FLIP_X = 1<<2, 196 | const WLC_BIT_CONSTRAINT_ADJUSTMENT_FLIP_Y = 1<<3, 197 | const WLC_BIT_CONSTRAINT_ADJUSTMENT_RESIZE_X = 1<<4, 198 | const WLC_BIT_CONSTRAINT_ADJUSTMENT_RESIZE_Y = 1<<5 199 | } 200 | } 201 | 202 | /// Represents a key state in key events 203 | #[repr(C)] 204 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 205 | pub enum KeyState { 206 | /// Key is being pressed 207 | Released = 0, 208 | /// Key is being released 209 | Pressed = 1 210 | } 211 | 212 | /// Represents a button state in button events 213 | #[repr(C)] 214 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 215 | pub enum ButtonState { 216 | /// Button is being pressed 217 | Released = 0, 218 | /// Button is being released 219 | Pressed = 1 220 | } 221 | 222 | /// Which axis of the scroll wheel is being used 223 | #[repr(C)] 224 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 225 | pub enum ScrollAxis { 226 | /// No axes 227 | None = 0, 228 | /// Vertical scroll 229 | Vertical = 1, 230 | /// Horizontal scroll 231 | Horizontal = 2, 232 | /// Both scrolls 233 | Both = 3 234 | } 235 | 236 | /// Touch type in touch interface handler 237 | #[repr(C)] 238 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 239 | pub enum TouchType { 240 | /// Touch down 241 | Down, 242 | /// Touch up 243 | Up, 244 | /// Touch motion 245 | Motion, 246 | /// Touch frame 247 | Frame, 248 | /// Touch cancelled 249 | Cancel 250 | } 251 | 252 | /// State of keyoard modifiers. 253 | /// i.e. control key, caps lock on 254 | #[repr(C)] 255 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 256 | pub struct KeyboardModifiers { 257 | /// Which "lock" keys are being pressed 258 | pub leds: KeyboardLed, 259 | /// Which control/meta keys are being pressed 260 | pub mods: KeyMod 261 | } 262 | 263 | /// Represents the location of a view. 264 | #[repr(C)] 265 | #[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] 266 | pub struct Point { 267 | /// x coordinate 268 | pub x: i32, 269 | /// y coordinate 270 | pub y: i32 271 | } 272 | 273 | impl Point { 274 | /// The point defined as (0, 0). 275 | pub fn origin() -> Point { 276 | Point { x: 0, y: 0 } 277 | } 278 | 279 | /// Create a new point from the given x and y coordinates. 280 | pub fn new(x: i32, y: i32) -> Point { 281 | Point { x: x, y: y } 282 | } 283 | 284 | /// Creates a new point with an x and y which are the smallest of the two 285 | /// points. 286 | /// 287 | /// # Examples: 288 | /// ```rust 289 | /// # use rustwlc::Point; 290 | /// let a = Point::new(0i32, 12i32); 291 | /// let b = Point::new(12i32, 0i32); 292 | /// 293 | /// assert_eq!(Point::from_min_coords(a, b), Point::new(0, 0)); 294 | /// ``` 295 | pub fn from_min_coords(a: Point, b: Point) -> Point { 296 | Point::new(cmp::min(a.x, b.x), cmp::min(a.y, b.y)) 297 | } 298 | 299 | /// Creates a new point with an x and y which are the largest of the two 300 | /// points. 301 | /// 302 | /// # Examples: 303 | /// ```rust 304 | /// # use rustwlc::Point; 305 | /// let a = Point::new(0i32, 12i32); 306 | /// let b = Point::new(12i32, 0i32); 307 | /// 308 | /// assert_eq!(Point::from_max_coords(a, b), Point::new(12i32, 12i32)); 309 | /// ``` 310 | pub fn from_max_coords(a: Point, b: Point) -> Point { 311 | Point::new(cmp::max(a.x, b.x), cmp::max(a.y, b.y)) 312 | } 313 | } 314 | 315 | impl fmt::Display for Point { 316 | fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result { 317 | write!(format, "({}, {})", self.x, self.y) 318 | } 319 | } 320 | 321 | /// Represents the height and width of a view. 322 | #[repr(C)] 323 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 324 | pub struct Size { 325 | /// Width 326 | pub w: u32, 327 | /// Height 328 | pub h: u32 329 | } 330 | 331 | impl Size { 332 | /// A size with zero width and height. 333 | pub fn zero() -> Size { 334 | Size { w: 0, h: 0 } 335 | } 336 | 337 | /// Create a new Size from the given height and width. 338 | pub fn new(w: u32, h: u32) -> Size { 339 | Size { w: w, h: h } 340 | } 341 | 342 | /// Creates a new size with a height and width of the smallest of the two 343 | /// sizes. 344 | /// 345 | /// # Examples: 346 | /// ```rust 347 | /// # use rustwlc::Size; 348 | /// let a = Size::new(0u32, 12u32); 349 | /// let b = Size::new(12u32, 0u32); 350 | /// 351 | /// assert_eq!(Size::from_min_dimensions(a, b), Size::new(0u32, 0u32)); 352 | /// ``` 353 | pub fn from_min_dimensions(a: Size, b: Size) -> Size { 354 | Size::new(cmp::min(a.h, b.h), cmp::min(a.w, b.w)) 355 | } 356 | 357 | /// Creates a new size with a height and width of the smallest of the two 358 | /// sizes. 359 | /// 360 | /// # Examples: 361 | /// ```rust 362 | /// # use rustwlc::Size; 363 | /// let a = Size::new(0u32, 12u32); 364 | /// let b = Size::new(12u32, 0u32); 365 | /// 366 | /// assert_eq!(Size::from_max_dimensions(a, b), Size::new(12u32, 12u32)); 367 | /// ``` 368 | pub fn from_max_dimensions(a: Size, b: Size) -> Size { 369 | Size::new(cmp::max(a.h, b.h), cmp::max(a.w, b.w)) 370 | } 371 | } 372 | 373 | impl fmt::Display for Size { 374 | fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result { 375 | write!(format, "{} x {}", self.w, self.h) 376 | } 377 | } 378 | 379 | /// Represents the location and size of a view 380 | #[repr(C)] 381 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 382 | pub struct Geometry { 383 | /// The location of the object 384 | pub origin: Point, 385 | /// The size of the object 386 | pub size: Size 387 | } 388 | 389 | impl Geometry { 390 | /// Creates a geometry with zero size at the origin. 391 | pub fn zero() -> Geometry { 392 | Geometry { origin: Point::origin(), size: Size::zero() } 393 | } 394 | 395 | /// Creates a new geometry with the given size and location. 396 | pub fn new(origin: Point, size: Size) -> Geometry { 397 | Geometry { origin: origin, size: size } 398 | } 399 | 400 | /// Determines if this geometry contains a point. 401 | /// 402 | /// If the point's coordinates are less than or equal to this geometry's 403 | /// dimensions plus its size. 404 | pub fn contains_point(self, point: Point) -> bool { 405 | point.x <= self.origin.x + self.size.w as i32 && 406 | point.y <= self.origin.y + self.size.h as i32 407 | } 408 | 409 | /// Determines if this geometry contains another. 410 | /// 411 | /// If the other geometry's borders could be fully contained (less than 412 | /// or equal to) within self. 413 | pub fn contains_geometry(self, other: Geometry) -> bool { 414 | self.origin.x <= other.origin.x 415 | && self.origin.y <= other.origin.y 416 | && self.origin.x + self.size.w as i32 417 | >= other.origin.x + other.size.w as i32 418 | && self.origin.y + self.size.h as i32 419 | >= other.origin.y + other.size.h as i32 420 | } 421 | } 422 | 423 | impl fmt::Display for Geometry { 424 | fn fmt(&self, format: &mut fmt::Formatter) -> fmt::Result { 425 | write!(format, "[{} at {}]", self.size, self.origin) 426 | } 427 | } 428 | 429 | /// Not currently supporting libinput 430 | #[repr(C)] 431 | pub struct LibinputDevice; 432 | -------------------------------------------------------------------------------- /src/wayland.rs: -------------------------------------------------------------------------------- 1 | //! # The wlc-wayland feature 2 | //! This crate requires the `wlc-wayland` feature to be enabled. 3 | //! The `wlc-wayland` feature adds additional methods to `WlcHandle` and 4 | //! `WlcOutput` as well. It uses the [wayland_sys_crate][] crate for Wayland 5 | //! types. See [the wayland_sys docs](wayland_sys_docs) for info on how to use 6 | //! them. 7 | //! 8 | //! Usage of `wlc-wayland` or Wayland bindings _is not_ required to make a 9 | //! compositor with rustwlc. wlc itself provides enough API around Wayland's 10 | //! that a complete compositor can be written without any Rust bindings 11 | //! to Wayland itself. `way-cooler` only uses Wayland for the standard Wayland 12 | //! protocol and some `wl_surface` info. 13 | //! 14 | //! That said, if you already use `wayland-client` or `wayland-sys`, this module 15 | //! provides compatibility. 16 | //! 17 | //! # Wayland bindings 18 | //! This crate contains wlc bindings to Wayland objects (defined in [wayland_sys] 19 | //! (wayland_sys_docs)) and the `WlcResource` struct, which represents 20 | //! wlc's Wayland resources. 21 | //! 22 | //! [wayland_sys_docs]:http://vberger.github.io/wayland-client-rs/wayland_sys/index.html 23 | //! [wayland_sys_crate]:https://crates.io/crates/wayland_sys 24 | use wayland_sys::server::{wl_display, wl_resource, wl_client}; 25 | 26 | use libc::{uintptr_t, size_t}; 27 | 28 | use std::ptr; 29 | 30 | use types::{Size, Geometry, Point}; 31 | 32 | /// ## Requires `wlc-wayland` feature 33 | /// 34 | /// A wlc resource for Wayland interop 35 | #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] 36 | pub struct WlcResource(uintptr_t); 37 | 38 | /// Functions defined in wlc-wayland.h 39 | #[cfg_attr(feature = "static-wlc", link(name = "wlc", kind = "static"))] 40 | #[cfg_attr(not(feature = "static-wlc"), link(name = "wlc"))] 41 | extern "C" { 42 | pub fn wlc_get_wl_display() -> *mut wl_display; 43 | pub fn wlc_resource_from_wl_surface_resource(resource: *const wl_resource) -> uintptr_t; 44 | pub fn wlc_surface_get_size(resource: uintptr_t) -> *const Size; 45 | pub fn wlc_surface_get_subsurfaces(parent: uintptr_t, out_size: *mut size_t) 46 | -> *const uintptr_t; 47 | pub fn wlc_get_subsurface_geometry(surface: uintptr_t, out_geo: *mut Geometry); 48 | pub fn wlc_view_get_surface(view: uintptr_t) -> uintptr_t; // returns wlc_resource 49 | pub fn wlc_surface_get_wl_resource(resource: uintptr_t) -> *mut wl_resource; 50 | pub fn wlc_view_get_wl_client(handle: uintptr_t) -> *mut wl_client; 51 | } 52 | 53 | /// Get the wayland display for the current session. 54 | pub fn get_display() -> *mut wl_display { 55 | unsafe { wlc_get_wl_display() } 56 | } 57 | 58 | impl Into<*mut wl_resource> for WlcResource { 59 | fn into(self) -> *mut wl_resource { 60 | unsafe {wlc_surface_get_wl_resource(self.0) } 61 | } 62 | } 63 | 64 | impl From for WlcResource { 65 | /// ## Requires `wlc-wayland` feature 66 | /// 67 | /// Creates a new WlcResource from the given pointer. 68 | fn from(ptr: uintptr_t) -> WlcResource { 69 | WlcResource(ptr) 70 | } 71 | } 72 | 73 | impl Into for wl_resource { 74 | /// ## Requires `wlc-wayland` feature 75 | /// 76 | /// Creates a new WlResource (wayland resource) from a WlcResource 77 | fn into(self) -> WlcResource { 78 | unsafe { WlcResource(wlc_resource_from_wl_surface_resource(&self)) } 79 | } 80 | } 81 | 82 | impl WlcResource { 83 | /// # Requires `wlc-wayland` feature 84 | /// 85 | /// Gets the size of this surface 86 | pub fn get_surface_size(self) -> Size { 87 | unsafe { *wlc_surface_get_size(self.0).clone() } 88 | } 89 | 90 | /// Gets the inner uintptr_t value that resource uses. 91 | pub fn get_raw(self) -> uintptr_t { 92 | self.0 93 | } 94 | 95 | /// ## Requires `wlc-wayland` feature 96 | /// 97 | /// Gets a list of subsurfaces from the given view 98 | pub fn get_subsurfaces(self) -> Vec { 99 | unsafe { 100 | let mut out_memb: size_t = 0; 101 | let subs = wlc_surface_get_subsurfaces(self.0, &mut out_memb as *mut usize); 102 | if subs.is_null() { 103 | return Vec::new() 104 | } 105 | let mut result = Vec::with_capacity(out_memb); 106 | for index in 0isize .. out_memb as isize { 107 | result.push(WlcResource::from(ptr::read(subs.offset(index)))) 108 | } 109 | return result 110 | } 111 | } 112 | 113 | /// # Requires `wlc-wayland` feature 114 | /// 115 | /// Gets the subsurface geometry of this WlcResource 116 | pub fn get_subsurface_geometry(self) -> Geometry { 117 | let mut geo = Geometry { 118 | origin: Point { x: 0, y: 0}, 119 | size: Size { w: 0, h: 0} 120 | }; 121 | unsafe { 122 | wlc_get_subsurface_geometry(self.0, &mut geo as *mut Geometry); 123 | } 124 | geo 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/xkb/convert.lua: -------------------------------------------------------------------------------- 1 | local define_pattern = "^#define XKB_KEY_([_%a%w]+)%s+(0x%x+)" 2 | local bad_define_pattern = "^#define _" 3 | local comment_pattern = "/%* ([_%w%+%s]+) %*/" 4 | local ifs_line_pattern = "^#[e|i]" 5 | local output_name = "keysyms.rs" 6 | 7 | local input_name = "xkbcommon-keysyms.h" 8 | 9 | local key_start_index = 54 10 | 11 | local output_file = io.open(output_name, "w") 12 | assert(output_file) 13 | 14 | output_file:write("#![allow(dead_code)]\n#![allow(missing_docs)]\n#![allow(non_upper_case_globals)]\n\n") 15 | 16 | output_file:write("//! Keysyms defined in xkbcommon-keysyms.h\n") 17 | output_file:write("//!\n//! Autogenerated by convert.lua.\n\n") 18 | 19 | output_file:write("use super::Keysym;\n") 20 | 21 | for line in io.lines(input_name) do 22 | if not line:match(ifs_line_pattern) then 23 | local name, value = line:match(define_pattern) 24 | if name == nil or value == nil then 25 | if not line:match(bad_define_pattern) then 26 | output_file:write(line..'\n') 27 | end -- Don't add the #define _xkb_thing 28 | else -- Match 29 | local comment = line:match(comment_pattern) 30 | if comment ~= nil then 31 | output_file:write("/// " .. comment .. "\n") 32 | end 33 | local first = "pub const KEY_" .. name .. ": Keysym = " 34 | local space_count = math.abs(key_start_index - first:len()) 35 | output_file:write(first .. string.rep(" ", space_count)) 36 | output_file:write("Keysym(" .. value .. "u32);\n") 37 | end 38 | end 39 | end 40 | output_file:close() -- Flush output 41 | print("File converted.") 42 | -------------------------------------------------------------------------------- /src/xkb/mod.rs: -------------------------------------------------------------------------------- 1 | //! Deprecated libxkbcommon bindings. 2 | //! # Deprecation 3 | //! The keysyms module is deprecated. 4 | //! Please use the [xkbcommon crate](https://crates.io/crates/xkbcommon) 5 | //! instead. **The xkb module will be removed in version 0.6**. 6 | 7 | #![allow(deprecated)] 8 | 9 | #[cfg(test)] 10 | mod tests; 11 | pub mod keysyms; 12 | 13 | /* 14 | * Copyright 1985, 1987, 1990, 1998 The Open Group 15 | * Copyright 2008 Dan Nicholson 16 | * 17 | * Permission is hereby granted, free of charge, to any person obtaining a 18 | * copy of this software and associated documentation files (the "Software"), 19 | * to deal in the Software without restriction, including without limitation 20 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 21 | * and/or sell copies of the Software, and to permit persons to whom the 22 | * Software is furnished to do so, subject to the following conditions: 23 | * 24 | * The above copyright notice and this permission notice shall be included in 25 | * all copies or substantial portions of the Software. 26 | * 27 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | * AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 31 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 32 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 | * 34 | * Except as contained in this notice, the names of the authors or their 35 | * institutions shall not be used in advertising or otherwise to promote the 36 | * sale, use or other dealings in this Software without prior written 37 | * authorization from the authors. 38 | */ 39 | 40 | /************************************************************ 41 | * Copyright (c) 1993 by Silicon Graphics Computer Systems, Inc. 42 | * 43 | * Permission to use, copy, modify, and distribute this 44 | * software and its documentation for any purpose and without 45 | * fee is hereby granted, provided that the above copyright 46 | * notice appear in all copies and that both that copyright 47 | * notice and this permission notice appear in supporting 48 | * documentation, and that the name of Silicon Graphics not be 49 | * used in advertising or publicity pertaining to distribution 50 | * of the software without specific prior written permission. 51 | * Silicon Graphics makes no representation about the suitability 52 | * of this software for any purpose. It is provided "as is" 53 | * without any express or implied warranty. 54 | * 55 | * SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS 56 | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 57 | * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON 58 | * GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL 59 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 60 | * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 61 | * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH 62 | * THE USE OR PERFORMANCE OF THIS SOFTWARE. 63 | * 64 | ********************************************************/ 65 | 66 | /* 67 | * Copyright © 2009-2012 Daniel Stone 68 | * Copyright © 2012 Intel Corporation 69 | * Copyright © 2012 Ran Benita 70 | * 71 | * Permission is hereby granted, free of charge, to any person obtaining a 72 | * copy of this software and associated documentation files (the "Software"), 73 | * to deal in the Software without restriction, including without limitation 74 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 75 | * and/or sell copies of the Software, and to permit persons to whom the 76 | * Software is furnished to do so, subject to the following conditions: 77 | * 78 | * The above copyright notice and this permission notice (including the next 79 | * paragraph) shall be included in all copies or substantial portions of the 80 | * Software. 81 | * 82 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 83 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 84 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 85 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 86 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 87 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 88 | * DEALINGS IN THE SOFTWARE. 89 | * 90 | * Author: Daniel Stone 91 | */ 92 | 93 | use libc::{c_char, size_t}; 94 | use std::ffi::CString; 95 | use std::mem; 96 | // Keysym utils functions 97 | 98 | /// An xkb keysym. 99 | /// 100 | /// # Deprecation 101 | /// The keysyms module is deprecated. 102 | /// Please use the [xkbcommon crate](https://crates.io/crates/xkbcommon) 103 | /// instead. **The xkb module will be removed in version 0.6**. 104 | /// 105 | /// # From xkb 106 | /// A number used to represent the symbols generated from a key on a keyboard. 107 | /// 108 | /// A key, represented by a keycode, may generate different symbols according 109 | /// to keyboard state. For example, on a QWERTY keyboard, pressing the key 110 | /// labled \ generates the symbol 'a'. If the Shift key is held, it 111 | /// generates the symbol 'A'. If a different layout is used, say Greek, 112 | /// it generates the symbol 'α'. And so on. 113 | /// 114 | /// Each such symbol is represented by a keysym. Note that keysyms are 115 | /// somewhat more general, in that they can also represent some "function", 116 | /// such as "Left" or "Right" for the arrow keys. For more information, 117 | /// see: 118 | /// http://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#keysym_encoding 119 | /// 120 | /// Specifically named keysyms can be found in the 121 | /// `xkbcommon/xkbcommon-keysyms.h` header file. Their name does not include 122 | /// the XKB_KEY_ prefix. 123 | /// 124 | /// Besides those, any Unicode/ISO 10646 character in the range U0100 to 125 | /// U10FFFF can be represented by a keysym value in the range 0x01000100 to 126 | /// 0x0110FFFF. The name of Unicode keysyms is "U", e.g. "UA1B2". 127 | /// 128 | /// The name of other unnamed keysyms is the hexadecimal representation of 129 | /// their value, e.g. "0xabcd1234". Keysym names are case-sensitive. 130 | /// 131 | #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 132 | pub struct Keysym(u32); 133 | 134 | impl Keysym { 135 | /// Get the raw value of the keysym 136 | pub fn raw(self) -> u32 { 137 | self.0 138 | } 139 | } 140 | 141 | /// Represents flags used for `Keysym::from_name` 142 | /// # Deprecation 143 | /// The keysyms module is deprecated. 144 | /// Please use the [xkbcommon crate](https://crates.io/crates/xkbcommon) 145 | /// instead. **The xkb module will be removed in version 0.6**. 146 | #[repr(C)] 147 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] 148 | pub enum NameFlags { 149 | /// None, or "Case sensitive" 150 | None = 0, 151 | /// Case insensitive name search 152 | CaseInsensitive = 1 153 | } 154 | 155 | /// Opaque keyboard state object. 156 | /// 157 | /// # Deprecation 158 | /// The keysyms module is deprecated. 159 | /// Please use the [xkbcommon crate](https://crates.io/crates/xkbcommon) 160 | /// instead. **The xkb module will be removed in version 0.6**. 161 | /// 162 | /// State objects contain the active state of a keyboard (or keyboards), such 163 | /// as the currently effective layout and the active modifiers. It acts as a 164 | /// simple state machine, wherein key presses and releases are the input, and 165 | /// key symbols (keysyms) are the output. 166 | #[repr(C)] 167 | pub struct XKBState; 168 | 169 | /// Opaque compiled keymap object. 170 | /// 171 | /// # Deprecation 172 | /// The keysyms module is deprecated. 173 | /// Please use the [xkbcommon crate](https://crates.io/crates/xkbcommon) 174 | /// instead. **The xkb module will be removed in version 0.6**. 175 | /// 176 | /// The keymap object holds all of the static keyboard information obtained 177 | /// from compiling XKB files. 178 | /// 179 | /// A keymap is immutable after it is created (besides reference counts, etc.); 180 | /// if you need to change it, you must create a new one. 181 | #[repr(C)] 182 | pub struct XKBKeymap; 183 | 184 | #[link(name = "xkbcommon")] 185 | extern "C" { 186 | fn xkb_keysym_get_name(keysym: u32, buffer: *mut c_char, size: size_t) -> i32; 187 | 188 | fn xkb_keysym_from_name(name: *const c_char, flags: NameFlags) -> u32; 189 | 190 | fn xkb_keysym_to_utf8(keysym: u32, buffer: *mut c_char, size: size_t) -> i32; 191 | 192 | fn xkb_keysym_to_utf32(keysym: u32) -> u32; 193 | } 194 | 195 | impl Keysym { 196 | 197 | /// Whether this keysym is a valid keysym. 198 | /// 199 | /// This checks whether the Keysym's value isn't `0` or `0xffffffff`. 200 | /// 201 | /// Tested on `libxkbcommon 0.5.0-1`, keysyms less than `0x20000000` 202 | /// stopped having meaningful names (`.get_name()` returned `None`). 203 | /// 204 | /// # Validity 205 | /// If a call to `Keysym::from_name(some_name)` returns a `Some(named_sym)` 206 | /// , `named_sym.is_valid()` will return true. 207 | /// 208 | /// In general, whenever a Keysym `sym` passes `sym.is_valid()`, 209 | /// `sym.get_name()` will be a `Some` (for keysyms less than 0x20000000). 210 | /// 211 | /// In addition, if `sym.get_name()` is a `Some(name)`, 212 | /// `Keysym::from_name(name)` will also return a valid Keysym. 213 | /// # Examples 214 | /// ```rust 215 | /// use rustwlc::xkb::Keysym; 216 | /// 217 | /// let sym = Keysym::from(0x41); // Something 218 | /// assert!(sym.is_valid()); 219 | /// ``` 220 | #[inline] 221 | pub fn is_valid(&self) -> bool { 222 | self.0 != 0 && self.0 != 0xffffffff 223 | } 224 | 225 | /// Whether a Keysym is invalid. 226 | /// 227 | /// See `is_valid()`. 228 | #[inline] 229 | pub fn is_invalid(&self) -> bool { 230 | self.0 == 0 || self.0 == 0xffffffff 231 | } 232 | 233 | /// Gets the `Keysym` as a `u32`. 234 | pub fn get_code(&self) -> u32 { 235 | self.0 236 | } 237 | 238 | /// Gets the Keysym for the given name. 239 | /// 240 | /// # Arguments 241 | /// name: The name of a keysym. See docs for `get_name`. 242 | /// This function will accept any name returned by that function. 243 | /// 244 | /// flags: A set of flags controlling how the search is done. 245 | /// If the KeyboardFlags::CaseInsensitive flag is used and two keysym names 246 | /// differ only by case, then the lower-case keysym is returned. For 247 | /// instance, for KEY_a and KEY_A, this function would return KEY_a for the 248 | /// case-insensitive search. If this functionality is needed, it is 249 | /// recommended to first call this function without this flag, and if that 250 | /// fails, only then to try with this flag, while possibly warning the user 251 | /// that they have misspelled the name, and might get wrong results. 252 | /// 253 | /// returns: The keysym. If the name is invalid, returns None. 254 | /// 255 | /// # Examples 256 | /// ```rust 257 | /// use rustwlc::xkb::{Keysym, NameFlags}; 258 | /// 259 | /// let key_match_a = Keysym::from_name("a".to_string(), NameFlags::None); 260 | /// assert!(key_match_a.is_some()); 261 | /// 262 | /// let key_a = key_match_a.unwrap(); 263 | /// assert!(key_a.is_valid()); 264 | /// ``` 265 | pub fn from_name(name: String, flags: NameFlags) -> Option { 266 | unsafe { 267 | let c_name = CString::new(name).unwrap(); 268 | let sym_val: u32 = xkb_keysym_from_name(c_name.as_ptr() as *const c_char, flags); 269 | match sym_val { 270 | 0 => None, 271 | _ => Some(Keysym(sym_val)) 272 | } 273 | } 274 | } 275 | 276 | /// Gets name name of the keysym. 277 | /// 278 | /// # Examples 279 | /// ```rust 280 | /// use rustwlc::xkb::{Keysym, NameFlags}; 281 | /// 282 | /// let key = Keysym::from_name("a".to_string(), NameFlags::None).unwrap(); 283 | /// 284 | /// assert_eq!(key.get_name(), Some("a".to_string())); 285 | /// ``` 286 | pub fn get_name(&self) -> Option { 287 | // The xkb documentation specifically recommends 64 as a buffer length 288 | unsafe { 289 | let mut buffer_vec: [c_char; 64] = mem::uninitialized(); 290 | let buffer: *mut c_char = buffer_vec.as_mut_ptr(); 291 | let length = xkb_keysym_get_name(self.0, buffer, 64); 292 | match length { 293 | -1 => None, 294 | _ => Some(super::pointer_to_string(buffer)) 295 | } 296 | } 297 | } 298 | 299 | /// Gets the Unicode/UTF8 representation of this keysym. 300 | pub fn to_utf8(&self) -> Option { 301 | unsafe { 302 | let mut buffer_vec: [c_char; 64] = mem::uninitialized(); 303 | let buffer: *mut c_char = buffer_vec.as_mut_ptr(); 304 | let result = xkb_keysym_to_utf8(self.0, buffer, 64); 305 | match result { 306 | -1 => None, 307 | _ => Some(super::pointer_to_string(buffer)) 308 | } 309 | } 310 | } 311 | 312 | /// Gets the Unicode/UTF32 representation of this keysym. 313 | pub fn to_utf32(&self) -> u32 { 314 | unsafe { 315 | xkb_keysym_to_utf32(self.0) 316 | } 317 | } 318 | } 319 | 320 | /// An error returned from attempting to crete a Keysym. 321 | /// 322 | /// # Deprecation 323 | /// The keysyms module is deprecated. 324 | /// Please use the [xkbcommon crate](https://crates.io/crates/xkbcommon) 325 | /// instead. **The xkb module will be removed in version 0.6**. 326 | /// Returned by `Keysym::from()`, `Keysym::from_name()` 327 | pub struct KeysymParseError; 328 | 329 | impl From for Keysym { 330 | #[inline] 331 | fn from(value: u32) -> Self { 332 | Keysym(value) 333 | } 334 | } 335 | -------------------------------------------------------------------------------- /src/xkb/tests.rs: -------------------------------------------------------------------------------- 1 | //! # Deprecation 2 | //! The keysyms module is deprecated. 3 | //! Please use the [xkbcommon crate](https://crates.io/crates/xkbcommon) 4 | //! instead. **The xkb module will be removed in version 0.6**. 5 | 6 | use super::*; 7 | 8 | #[test] 9 | fn sanity_test() { 10 | assert!(true); 11 | assert_eq!(1, 1); 12 | } 13 | 14 | #[test] 15 | fn from_name_get_name() { 16 | // Test a small (but most likely to be used) subset of keysyms 17 | let names = vec![ 18 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", 19 | "BackSpace", "Tab", "Return", "Escape", "Delete", 20 | "Left", "Right", "Up", "Down", "Home", "End", 21 | "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", 22 | "Shift_L", "Shift_R", "Super_L", "Meta_R", "Caps_Lock", 23 | "space", "exclam", "dollar", "ampersand", "apostrophe"]; 24 | for name in names { 25 | let msym = Keysym::from_name(name.to_string(), NameFlags::None); 26 | assert!(msym.is_some()); 27 | let sym = msym.unwrap(); 28 | assert!(sym.is_valid()); 29 | let mname = sym.get_name(); 30 | assert!(mname.is_some()); 31 | let sym_name = mname.unwrap(); 32 | assert_eq!(sym_name, name.to_string()); 33 | } 34 | } 35 | 36 | #[test] 37 | fn some_unexpected_keysyms() { 38 | let non_names = vec![ 39 | "soda", "caps lock", "Hypermeta_L", "key", 40 | "keyboard", "aa", "kk"]; 41 | for name in non_names { 42 | let sym = Keysym::from_name(name.to_string(), NameFlags::None); 43 | assert!(sym.is_none()); 44 | } 45 | } 46 | 47 | #[test] 48 | // keysym.is_valid() implies keysym.get_name().is_some() 49 | fn valitity_implications() { 50 | for val in 0u32..999999u32 { 51 | let sym = Keysym::from(val); 52 | if sym.is_valid() { 53 | let name = sym.get_name(); 54 | assert!(name.is_some()); 55 | let sym2 = Keysym::from_name(name.unwrap(), NameFlags::None); 56 | assert!(sym2.is_some()); 57 | assert_eq!(sym, sym2.unwrap()); 58 | } 59 | } 60 | } 61 | 62 | #[test] 63 | fn case_insensitive_from_name() { 64 | let names = vec![ 65 | "caps_lock", "super_l", "escape", 66 | "ESCAPE", "RETURN", "SELECT"]; 67 | for name in names { 68 | let sym = Keysym::from_name(name.to_string(), NameFlags::CaseInsensitive); 69 | let none_sym = Keysym::from_name(name.to_string(), NameFlags::None); 70 | assert!(sym.is_some()); 71 | assert!(none_sym.is_none()); 72 | } 73 | } 74 | --------------------------------------------------------------------------------