1 //! Utilities to work with pointers and their icons 2 3 use std::ops::Deref; 4 5 use wayland_client::protocol::{wl_compositor, wl_pointer, wl_seat, wl_shm}; 6 use wayland_client::{NewProxy, Proxy, QueueToken}; 7 8 use wayland_client::protocol::wl_seat::RequestsTrait as SeatRequests; 9 10 mod theme; 11 12 pub use self::theme::{ThemeManager, ThemedPointer}; 13 14 /// Wrapper to gracefully handle a missing `libwayland-cursor` 15 /// 16 /// This wrapper has the same API as `ThemeManager`, but will 17 /// gracefully handle the case of a missing `libwayland-cursor` 18 /// by doing nothing. 19 /// 20 /// It is a convenience wrapper to handle systems where 21 /// `libwayland-client.so` is available but not `libwayland-cursor.so`. 22 pub enum AutoThemer { 23 /// The theme could be loaded 24 Themed(ThemeManager), 25 /// `libwayland-cursor.so` is not available 26 UnThemed, 27 } 28 29 impl AutoThemer { 30 /// Load a system pointer theme 31 /// 32 /// Will use the default theme of the system if name is `None`. 33 /// 34 /// Falls back to `UnThemed` if `libwayland-cursor` is not available. init( name: Option<&str>, compositor: Proxy<wl_compositor::WlCompositor>, shm: &Proxy<wl_shm::WlShm>, ) -> AutoThemer35 pub fn init( 36 name: Option<&str>, 37 compositor: Proxy<wl_compositor::WlCompositor>, 38 shm: &Proxy<wl_shm::WlShm>, 39 ) -> AutoThemer { 40 match ThemeManager::init(name, compositor, &shm) { 41 Ok(mgr) => AutoThemer::Themed(mgr), 42 Err(()) => AutoThemer::UnThemed, 43 } 44 } 45 46 /// Wrap a pointer to theme it theme_pointer(&self, pointer: Proxy<wl_pointer::WlPointer>) -> AutoPointer47 pub fn theme_pointer(&self, pointer: Proxy<wl_pointer::WlPointer>) -> AutoPointer { 48 match *self { 49 AutoThemer::Themed(ref mgr) => AutoPointer::Themed(mgr.theme_pointer(pointer)), 50 AutoThemer::UnThemed => AutoPointer::UnThemed(pointer), 51 } 52 } 53 54 /// Initialize a new pointer as a ThemedPointer with an adapter implementation 55 /// 56 /// You need to provide an implementation as if implementing a `wl_pointer`, but 57 /// it will receive as `meta` argument an `AutoPointer` wrapping your pointer, 58 /// rather than a `Proxy<WlPointer>`. theme_pointer_with_impl<Impl, UD>( &self, seat: &Proxy<wl_seat::WlSeat>, mut implementation: Impl, user_data: UD, ) -> AutoPointer where Impl: FnMut(wl_pointer::Event, AutoPointer) + Send + 'static, UD: Send + Sync + 'static,59 pub fn theme_pointer_with_impl<Impl, UD>( 60 &self, 61 seat: &Proxy<wl_seat::WlSeat>, 62 mut implementation: Impl, 63 user_data: UD, 64 ) -> AutoPointer 65 where 66 Impl: FnMut(wl_pointer::Event, AutoPointer) + Send + 'static, 67 UD: Send + Sync + 'static, 68 { 69 match *self { 70 AutoThemer::Themed(ref mgr) => { 71 let pointer = mgr.theme_pointer_with_impl( 72 seat, 73 move |event, seat| implementation(event, AutoPointer::Themed(seat)), 74 user_data, 75 ); 76 AutoPointer::Themed(pointer) 77 } 78 AutoThemer::UnThemed => { 79 let pointer = seat 80 .get_pointer(|pointer| { 81 pointer.implement( 82 move |event, seat| implementation(event, AutoPointer::UnThemed(seat)), 83 user_data, 84 ) 85 }) 86 .unwrap(); 87 AutoPointer::UnThemed(pointer) 88 } 89 } 90 } 91 92 /// Initialize a new pointer as a ThemedPointer with an adapter implementation 93 /// 94 /// Like `theme_pointer_with_impl` but allows you to have a non-`Send` implementation. 95 /// 96 /// **Unsafe** for the same reasons as `NewProxy::implement_nonsend`. theme_pointer_with_nonsend_impl<Impl, UD>( &self, pointer: NewProxy<wl_pointer::WlPointer>, mut implementation: Impl, user_data: UD, token: &QueueToken, ) -> AutoPointer where Impl: FnMut(wl_pointer::Event, AutoPointer) + Send + 'static, UD: Send + Sync + 'static,97 pub unsafe fn theme_pointer_with_nonsend_impl<Impl, UD>( 98 &self, 99 pointer: NewProxy<wl_pointer::WlPointer>, 100 mut implementation: Impl, 101 user_data: UD, 102 token: &QueueToken, 103 ) -> AutoPointer 104 where 105 Impl: FnMut(wl_pointer::Event, AutoPointer) + Send + 'static, 106 UD: Send + Sync + 'static, 107 { 108 match *self { 109 AutoThemer::Themed(ref mgr) => { 110 let pointer = mgr.theme_pointer_with_nonsend_impl( 111 pointer, 112 move |event, pointer| implementation(event, AutoPointer::Themed(pointer)), 113 user_data, 114 token, 115 ); 116 AutoPointer::Themed(pointer) 117 } 118 AutoThemer::UnThemed => { 119 let pointer = pointer.implement_nonsend( 120 move |event, pointer| implementation(event, AutoPointer::UnThemed(pointer)), 121 user_data, 122 token, 123 ); 124 AutoPointer::UnThemed(pointer) 125 } 126 } 127 } 128 } 129 130 /// A pointer wrapper to gracefully handle a missing `libwayland-cursor` 131 /// 132 /// It has the same API as `ThemedPointer`, but falls back to doing nothing 133 /// in its `Unthemed` variant. 134 pub enum AutoPointer { 135 /// The `ThemedPointer` 136 Themed(ThemedPointer), 137 /// The regular pointer if theme capability is not available 138 UnThemed(Proxy<wl_pointer::WlPointer>), 139 } 140 141 impl AutoPointer { 142 /// Change the cursor to the given cursor name 143 /// 144 /// Possible names depend on the theme. Does nothing and returns 145 /// `Err(())` if given name is not available. 146 /// 147 /// Does nothing an returns `Ok(())` if no theme is loaded (if 148 /// `wayland-cursor` is not available). 149 /// 150 /// If this is done as an answer to an input event, you need to provide 151 /// the associated serial otherwise the server may ignore the request. set_cursor(&self, name: &str, serial: Option<u32>) -> Result<(), ()>152 pub fn set_cursor(&self, name: &str, serial: Option<u32>) -> Result<(), ()> { 153 match *self { 154 AutoPointer::Themed(ref themed) => themed.set_cursor(name, serial), 155 AutoPointer::UnThemed(_) => Ok(()), 156 } 157 } 158 } 159 160 impl Deref for AutoPointer { 161 type Target = Proxy<wl_pointer::WlPointer>; deref(&self) -> &Proxy<wl_pointer::WlPointer>162 fn deref(&self) -> &Proxy<wl_pointer::WlPointer> { 163 match *self { 164 AutoPointer::Themed(ref themed) => &**themed, 165 AutoPointer::UnThemed(ref ptr) => ptr, 166 } 167 } 168 } 169 170 impl Clone for AutoPointer { clone(&self) -> AutoPointer171 fn clone(&self) -> AutoPointer { 172 match *self { 173 AutoPointer::Themed(ref themed) => AutoPointer::Themed(themed.clone()), 174 AutoPointer::UnThemed(ref ptr) => AutoPointer::UnThemed(ptr.clone()), 175 } 176 } 177 } 178