screencapturekit/shareable_content/
running_application.rs

1use core::fmt;
2use std::ffi::c_void;
3
4use crate::utils::ffi_string::{ffi_string_from_buffer_or_empty, DEFAULT_BUFFER_SIZE};
5
6/// Wrapper around `SCRunningApplication` from `ScreenCaptureKit`
7///
8/// Represents a running application that can be captured.
9///
10/// # Examples
11///
12/// ```no_run
13/// use screencapturekit::shareable_content::SCShareableContent;
14///
15/// # fn example() -> Result<(), Box<dyn std::error::Error>> {
16/// let content = SCShareableContent::get()?;
17/// for app in content.applications() {
18///     println!("App: {} (PID: {})",
19///         app.application_name(),
20///         app.process_id()
21///     );
22/// }
23/// # Ok(())
24/// # }
25/// ```
26#[repr(transparent)]
27pub struct SCRunningApplication(*const c_void);
28
29impl PartialEq for SCRunningApplication {
30    fn eq(&self, other: &Self) -> bool {
31        self.0 == other.0
32    }
33}
34
35impl Eq for SCRunningApplication {}
36
37impl std::hash::Hash for SCRunningApplication {
38    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
39        self.0.hash(state);
40    }
41}
42
43/// Raw pointer type for `SCRunningApplication` (for FFI compatibility)
44pub type SCRunningApplicationRef = *const c_void;
45
46impl SCRunningApplication {
47    /// Create from raw pointer (used internally by shareable content)
48    pub(crate) unsafe fn from_ptr(ptr: *const c_void) -> Self {
49        Self(ptr)
50    }
51
52    /// Get the raw pointer (used internally)
53    pub(crate) fn as_ptr(&self) -> *const c_void {
54        self.0
55    }
56
57    /// Get process ID
58    pub fn process_id(&self) -> i32 {
59        unsafe { crate::ffi::sc_running_application_get_process_id(self.0) }
60    }
61
62    /// Get application name
63    pub fn application_name(&self) -> String {
64        unsafe {
65            ffi_string_from_buffer_or_empty(DEFAULT_BUFFER_SIZE, |buf, len| {
66                crate::ffi::sc_running_application_get_application_name(self.0, buf, len)
67            })
68        }
69    }
70
71    /// Get bundle identifier
72    pub fn bundle_identifier(&self) -> String {
73        unsafe {
74            ffi_string_from_buffer_or_empty(DEFAULT_BUFFER_SIZE, |buf, len| {
75                crate::ffi::sc_running_application_get_bundle_identifier(self.0, buf, len)
76            })
77        }
78    }
79}
80
81impl Drop for SCRunningApplication {
82    fn drop(&mut self) {
83        if !self.0.is_null() {
84            unsafe {
85                crate::ffi::sc_running_application_release(self.0);
86            }
87        }
88    }
89}
90
91impl Clone for SCRunningApplication {
92    fn clone(&self) -> Self {
93        unsafe { Self(crate::ffi::sc_running_application_retain(self.0)) }
94    }
95}
96
97impl fmt::Debug for SCRunningApplication {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        f.debug_struct("SCRunningApplication")
100            .field("bundle_identifier", &self.bundle_identifier())
101            .field("application_name", &self.application_name())
102            .field("process_id", &self.process_id())
103            .finish()
104    }
105}
106
107impl fmt::Display for SCRunningApplication {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        write!(
110            f,
111            "{} ({}) [PID: {}]",
112            self.application_name(),
113            self.bundle_identifier(),
114            self.process_id()
115        )
116    }
117}
118
119unsafe impl Send for SCRunningApplication {}
120unsafe impl Sync for SCRunningApplication {}