screencapturekit/shareable_content/
running_application.rs

1use core::fmt;
2use std::ffi::c_void;
3
4use crate::utils::ffi_string::ffi_string_owned_or_empty;
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
43impl SCRunningApplication {
44    /// Create from raw pointer (used internally by shareable content)
45    pub(crate) unsafe fn from_ptr(ptr: *const c_void) -> Self {
46        Self(ptr)
47    }
48
49    /// Create from FFI-owned pointer (caller transfers ownership)
50    #[allow(dead_code)]
51    pub(crate) fn from_ffi_owned(ptr: *const c_void) -> Self {
52        Self(ptr)
53    }
54
55    /// Get the raw pointer (used internally)
56    pub(crate) fn as_ptr(&self) -> *const c_void {
57        self.0
58    }
59
60    /// Get process ID
61    pub fn process_id(&self) -> i32 {
62        unsafe { crate::ffi::sc_running_application_get_process_id(self.0) }
63    }
64
65    /// Get application name
66    pub fn application_name(&self) -> String {
67        unsafe {
68            ffi_string_owned_or_empty(|| {
69                crate::ffi::sc_running_application_get_application_name_owned(self.0)
70            })
71        }
72    }
73
74    /// Get bundle identifier
75    pub fn bundle_identifier(&self) -> String {
76        unsafe {
77            ffi_string_owned_or_empty(|| {
78                crate::ffi::sc_running_application_get_bundle_identifier_owned(self.0)
79            })
80        }
81    }
82}
83
84impl Drop for SCRunningApplication {
85    fn drop(&mut self) {
86        if !self.0.is_null() {
87            unsafe {
88                crate::ffi::sc_running_application_release(self.0);
89            }
90        }
91    }
92}
93
94impl Clone for SCRunningApplication {
95    fn clone(&self) -> Self {
96        unsafe { Self(crate::ffi::sc_running_application_retain(self.0)) }
97    }
98}
99
100impl fmt::Debug for SCRunningApplication {
101    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102        f.debug_struct("SCRunningApplication")
103            .field("bundle_identifier", &self.bundle_identifier())
104            .field("application_name", &self.application_name())
105            .field("process_id", &self.process_id())
106            .finish()
107    }
108}
109
110impl fmt::Display for SCRunningApplication {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        write!(
113            f,
114            "{} ({}) [PID: {}]",
115            self.application_name(),
116            self.bundle_identifier(),
117            self.process_id()
118        )
119    }
120}
121
122unsafe impl Send for SCRunningApplication {}
123unsafe impl Sync for SCRunningApplication {}