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)
                }
            }
        )*
    };
);