<NME> source.rs
<BEF> ADDFILE
<MSG> Merge pull request #670 from Smithay/feature/primary_selection

wayland: Add support for the wp_primary_selection protocol
<DFF> @@ -0,0 +1,86 @@
+use std::sync::Mutex;
+
+use wayland_protocols::wp::primary_selection::zv1::server::zwp_primary_selection_source_v1::{
+    self as primary_source, ZwpPrimarySelectionSourceV1 as PrimarySource,
+};
+use wayland_server::{
+    backend::{ClientId, ObjectId},
+    Dispatch, DisplayHandle, Resource,
+};
+
+use crate::utils::{alive_tracker::AliveTracker, IsAlive};
+
+use super::{PrimarySelectionHandler, PrimarySelectionState};
+
+/// The metadata describing a data source
+#[derive(Debug, Default, Clone)]
+pub struct SourceMetadata {
+    /// The MIME types supported by this source
+    pub mime_types: Vec<String>,
+}
+
+#[doc(hidden)]
+#[derive(Debug)]
+pub struct PrimarySourceUserData {
+    inner: Mutex<SourceMetadata>,
+    alive_tracker: AliveTracker,
+}
+
+impl PrimarySourceUserData {
+    pub(super) fn new() -> Self {
+        Self {
+            inner: Default::default(),
+            alive_tracker: Default::default(),
+        }
+    }
+}
+
+impl<D> Dispatch<PrimarySource, PrimarySourceUserData, D> for PrimarySelectionState
+where
+    D: Dispatch<PrimarySource, PrimarySourceUserData>,
+    D: PrimarySelectionHandler,
+    D: 'static,
+{
+    fn request(
+        state: &mut D,
+        _client: &wayland_server::Client,
+        _resource: &PrimarySource,
+        request: primary_source::Request,
+        data: &PrimarySourceUserData,
+        _dhandle: &DisplayHandle,
+        _data_init: &mut wayland_server::DataInit<'_, D>,
+    ) {
+        let _primary_selection_state = state.primary_selection_state();
+        let mut data = data.inner.lock().unwrap();
+
+        match request {
+            primary_source::Request::Offer { mime_type } => {
+                data.mime_types.push(mime_type);
+            }
+            primary_source::Request::Destroy => {}
+            _ => unreachable!(),
+        }
+    }
+
+    fn destroyed(_state: &mut D, _client: ClientId, _resource: ObjectId, data: &PrimarySourceUserData) {
+        data.alive_tracker.destroy_notify();
+    }
+}
+
+impl IsAlive for PrimarySource {
+    fn alive(&self) -> bool {
+        let data: &PrimarySourceUserData = self.data().unwrap();
+        data.alive_tracker.alive()
+    }
+}
+
+/// Access the metadata of a data source
+pub fn with_source_metadata<T, F: FnOnce(&SourceMetadata) -> T>(
+    source: &PrimarySource,
+    f: F,
+) -> Result<T, crate::utils::UnmanagedResource> {
+    match source.data::<PrimarySourceUserData>() {
+        Some(data) => Ok(f(&data.inner.lock().unwrap())),
+        None => Err(crate::utils::UnmanagedResource),
+    }
+}

Merge pull request #670 from Smithay/feature/primary_selection