1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
//! Message sinks //! //! The Wayland model naturally uses callbacks to handle the message you receive from the server. //! However in some contexts, an iterator-based interface may be more practical to use, this is //! what this module provides. //! //! The `message_iterator` function allows you to create a new message iterator. It is just a //! regular MPSC, however its sending end (the `Sink<T>`) can be directly used as an implementation //! for Wayland objects. This just requires that `T: From<(I::Event, I)>` (where `I` is the //! interface of the object you're trying to implement). The `event_enum!` macro is provided to //! easily generate an appropriate type joining events from different interfaces into a single //! iterator. //! //! The `blocking_message_iterator` function is very similar, except the created message iterator //! will be linked to an event queue, and will block on it rather than returning `None`, and is //! thus able to drive an event loop. use std::rc::Rc; use wayland_commons::Interface; use imp::EventQueueInner; use {HandledBy, QueueToken}; pub use wayland_commons::sinks::{message_iterator, MsgIter, Sink}; impl<M, I> HandledBy<Sink<M>> for I where I: Interface, M: From<(I::Event, I)>, { fn handle(sink: &mut Sink<M>, event: I::Event, proxy: I) { sink.push((event, proxy)); } } /// A message iterator linked to an event queue /// /// Like a `MsgIter<T>`, but it is linked with an event queue, and /// will `dispatch()` and block instead of returning `None` if no /// events are pending. pub struct BlockingMsgIter<T> { evt_queue: Rc<EventQueueInner>, iter: MsgIter<T>, } impl<T> Iterator for BlockingMsgIter<T> { type Item = T; fn next(&mut self) -> Option<T> { loop { match self.iter.next() { Some(msg) => return Some(msg), None => { self.evt_queue .dispatch() .expect("Connection to the wayland server lost."); } } } } } /// Create a blokcing message iterator /// /// Contrarily to `message_iterator`, this one will block on the event queue /// represented by the provided token rather than returning `None` if no event is available. pub fn blocking_message_iterator<T>(token: QueueToken) -> (Sink<T>, BlockingMsgIter<T>) { let (sink, iter) = message_iterator(); ( sink, BlockingMsgIter { iter, evt_queue: token.inner, }, ) } /// Generate an enum joining several objects events /// /// This macro allows you to easily create a enum type for use with your message iterators. It is /// used like so: /// /// ```ignore /// event_enum!( /// MyEnum | /// Pointer => WlPointer, /// Keyboard => WlKeyboard, /// Surface => WlSurface /// ); /// ``` /// /// This will generate the following enum, unifying the events from each of the provided interface: /// /// ```ignore /// pub enum MyEnum { /// Pointer { event: WlPointer::Event, object: WlPointer }, /// Keyboard { event: WlKeyboard::Event, object: WlKeyboard }, /// Surface { event: WlSurface::Event, object: WlSurface } /// } /// ``` /// /// It will also generate the appropriate `From<_>` implementation so that a `Sink<MyEnum>` can be /// used as an implementation for `WlPointer`, `WlKeyboard` and `WlSurface`. /// /// If you want to add custom messages to the enum, the macro also supports it: /// /// ```ignore /// event_enum!( /// MyEnum | /// Pointer => WlPointer, /// Keyboard => WlKeyboard, /// Surface => WlSurface | /// MyMessage => SomeType, /// OtherMessage => OtherType /// ); /// ``` /// /// will generate the following enum: /// /// ```ignore /// pub enum MyEnum { /// Pointer { event: WlPointer::Event, object: WlPointer }, /// Keyboard { event: WlKeyboard::Event, object: WlKeyboard }, /// Surface { event: WlSurface::Event, object: WlSurface }, /// MyMessage(SomeType), /// OtherMessage(OtherType) /// } /// ``` /// /// as well as implementations of `From<SomeType>` and `From<OtherType>`, so that these types can /// directly be provided into a `Sink<MyEnum>`. #[macro_export] macro_rules! event_enum( ($enu:ident | $($evt_name:ident => $iface:ty),*) => { event_enum!($enu | $($evt_name => $iface),* | ); }; ($enu:ident | $($evt_name:ident => $iface:ty),* | $($name:ident => $value:ty),*) => { pub enum $enu { $( $evt_name { event: <$iface as $crate::Interface>::Event, object: $iface }, )* $( $name($value) )* } $( impl From<(<$iface as $crate::Interface>::Event, $iface)> for $enu { fn from((event, object): (<$iface as $crate::Interface>::Event, $iface)) -> $enu { $enu::$evt_name { event, object } } } )* $( impl From<$value> for $enu { fn from(value: $value) -> $enu { $enu::$name(value) } } )* }; );