screencapturekit/
dispatch_queue.rs

1//! Dispatch Queue wrapper for custom queue management
2//!
3//! This module provides a safe Rust wrapper around GCD (Grand Central Dispatch) queues
4//! that can be used with `ScreenCaptureKit` streams.
5//!
6//! ## When to Use Custom Queues
7//!
8//! By default, stream output handlers are called on a system-managed queue. Use a custom
9//! queue when you need:
10//!
11//! - **Priority control** - Use `UserInteractive` `QoS` for low-latency UI updates
12//! - **Thread isolation** - Ensure handlers run on a specific queue
13//! - **Performance tuning** - Adjust queue priority based on your app's needs
14//!
15//! ## Example
16//!
17//! ```rust,no_run
18//! use screencapturekit::dispatch_queue::{DispatchQueue, DispatchQoS};
19//! use screencapturekit::prelude::*;
20//!
21//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
22//! # let content = SCShareableContent::get()?;
23//! # let display = &content.displays()[0];
24//! # let filter = SCContentFilter::create().with_display(display).with_excluding_windows(&[]).build();
25//! # let config = SCStreamConfiguration::default();
26//! // Create a high-priority queue for frame processing
27//! let queue = DispatchQueue::new("com.myapp.capture", DispatchQoS::UserInteractive);
28//!
29//! let mut stream = SCStream::new(&filter, &config);
30//! stream.add_output_handler_with_queue(
31//!     |_sample, _type| println!("Got frame!"),
32//!     SCStreamOutputType::Screen,
33//!     Some(&queue)
34//! );
35//! # Ok(())
36//! # }
37//! ```
38
39use std::ffi::{c_void, CString};
40use std::fmt;
41
42/// Quality of Service levels for dispatch queues
43///
44/// These `QoS` levels help the system prioritize work appropriately.
45///
46/// # Examples
47///
48/// ```
49/// use screencapturekit::dispatch_queue::{DispatchQueue, DispatchQoS};
50///
51/// // High priority for UI-affecting work
52/// let queue = DispatchQueue::new("com.myapp.ui", DispatchQoS::UserInteractive);
53///
54/// // Lower priority for background tasks
55/// let bg_queue = DispatchQueue::new("com.myapp.background", DispatchQoS::Background);
56/// ```
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
58pub enum DispatchQoS {
59    /// Background `QoS` - for maintenance or cleanup tasks
60    Background = 0,
61    /// Utility `QoS` - for tasks that may take some time
62    Utility = 1,
63    /// Default `QoS` - standard priority
64    #[default]
65    Default = 2,
66    /// User Initiated `QoS` - for tasks initiated by the user
67    UserInitiated = 3,
68    /// User Interactive `QoS` - for tasks that affect the UI
69    UserInteractive = 4,
70}
71
72/// A wrapper around GCD `DispatchQueue`
73///
74/// This allows you to provide a custom dispatch queue for stream output handling
75/// instead of using the default queue.
76///
77/// # Example
78///
79/// ```no_run
80/// use screencapturekit::dispatch_queue::{DispatchQueue, DispatchQoS};
81///
82/// let queue = DispatchQueue::new("com.myapp.capture", DispatchQoS::UserInteractive);
83/// ```
84pub struct DispatchQueue {
85    ptr: *const c_void,
86}
87
88unsafe impl Send for DispatchQueue {}
89unsafe impl Sync for DispatchQueue {}
90
91impl DispatchQueue {
92    /// Creates a new dispatch queue with the specified label and `QoS`
93    ///
94    /// # Arguments
95    ///
96    /// * `label` - A string label for the queue (e.g., "com.myapp.capture")
97    /// * `qos` - The quality of service level for the queue
98    ///
99    /// # Examples
100    ///
101    /// ```
102    /// use screencapturekit::dispatch_queue::{DispatchQueue, DispatchQoS};
103    ///
104    /// let queue = DispatchQueue::new("com.myapp.capture", DispatchQoS::UserInteractive);
105    /// // Use the queue with SCStream's add_output_handler_with_queue
106    /// ```
107    ///
108    /// # Panics
109    ///
110    /// Panics if the label contains null bytes or if queue creation fails
111    pub fn new(label: &str, qos: DispatchQoS) -> Self {
112        let c_label = CString::new(label).expect("Label contains null byte");
113        let ptr = unsafe { crate::ffi::dispatch_queue_create(c_label.as_ptr(), qos as i32) };
114        assert!(!ptr.is_null(), "Failed to create dispatch queue");
115        Self { ptr }
116    }
117
118    /// Returns the raw pointer to the dispatch queue
119    ///
120    /// This is used internally for FFI calls (and for testing)
121    pub fn as_ptr(&self) -> *const c_void {
122        self.ptr
123    }
124}
125
126impl Clone for DispatchQueue {
127    fn clone(&self) -> Self {
128        unsafe {
129            Self {
130                ptr: crate::ffi::dispatch_queue_retain(self.ptr),
131            }
132        }
133    }
134}
135
136impl Drop for DispatchQueue {
137    fn drop(&mut self) {
138        unsafe {
139            crate::ffi::dispatch_queue_release(self.ptr);
140        }
141    }
142}
143
144impl fmt::Debug for DispatchQueue {
145    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146        f.debug_struct("DispatchQueue")
147            .field("ptr", &self.ptr)
148            .finish()
149    }
150}
151
152impl fmt::Display for DispatchQueue {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        write!(f, "DispatchQueue")
155    }
156}