1#[cfg(target_os = "macos")]
16mod callback_base;
17#[cfg(target_os = "macos")]
18mod clipboard_data_format_helper;
19#[cfg(target_os = "macos")]
20mod clipboard_data_transfer;
21#[cfg(target_os = "macos")]
22mod clipboard_data_transfer_item;
23#[cfg(target_os = "macos")]
24mod clipboard_impl;
25#[cfg(target_os = "macos")]
26mod clipboard_read_session;
27#[cfg(target_os = "macos")]
28mod cursor;
29#[cfg(target_os = "macos")]
30mod data_transfer_item_to_frn_clipboard_data_item_wrapper;
31#[cfg(target_os = "macos")]
32mod data_transfer_to_frn_clipboard_data_source_wrapper;
33#[cfg(target_os = "macos")]
34mod deferred_framebuffer;
35#[cfg(target_os = "macos")]
36mod dispatcher_impl;
37#[cfg(target_os = "macos")]
38mod double_click_helper;
39#[cfg(target_os = "macos")]
40mod embeddable_top_level_impl;
41#[cfg(target_os = "macos")]
42mod extensions;
43#[cfg(target_os = "macos")]
44mod ferro_native_application_platform;
45#[cfg(target_os = "macos")]
46mod ferro_native_drag_source;
47#[cfg(target_os = "macos")]
48mod ferro_native_gl_platform_graphics;
49#[cfg(target_os = "macos")]
50mod ferro_native_menu_exporter;
51#[cfg(target_os = "macos")]
52mod ferro_native_platform;
53mod ferro_native_platform_extensions;
54#[cfg(target_os = "macos")]
55mod ferro_native_render_timer;
56#[cfg(target_os = "macos")]
57mod ferro_native_text_input_method;
58#[cfg(target_os = "macos")]
59mod frn_automation_peer;
60#[cfg(target_os = "macos")]
61mod frn_dispatcher;
62#[cfg(target_os = "macos")]
63mod frn_menu;
64#[cfg(target_os = "macos")]
65mod frn_menu_item;
66#[cfg(target_os = "macos")]
67mod frn_string;
68#[cfg(target_os = "macos")]
69mod gpu_handle_wrap_feature;
70#[cfg(target_os = "macos")]
71mod helpers;
72#[cfg(target_os = "macos")]
73mod icon_loader;
74#[cfg(target_os = "macos")]
75mod mac_os_activatable_lifetime;
76
77#[cfg(target_os = "macos")]
78mod mac_os_mounted_volume_info_provider;
79#[cfg(target_os = "macos")]
80mod mac_os_native_menu_commands;
81#[cfg(target_os = "macos")]
82mod menu_action_callback;
83#[cfg(target_os = "macos")]
84mod metal;
85#[cfg(target_os = "macos")]
86mod native_control_host_impl;
87
88#[cfg(target_os = "macos")]
89mod native_platform_settings;
90#[cfg(target_os = "macos")]
91mod platform_behavior_inhibition;
92#[cfg(target_os = "macos")]
93mod popup_impl;
94#[cfg(target_os = "macos")]
95mod predicate_callback;
96#[cfg(target_os = "macos")]
97mod screen_impl;
98#[cfg(target_os = "macos")]
99mod storage_item;
100
101#[cfg(target_os = "macos")]
102mod storage_provider_api;
103
104#[cfg(target_os = "macos")]
105mod storage_provider_impl;
106
107#[cfg(target_os = "macos")]
108mod top_level_impl;
109#[cfg(target_os = "macos")]
110mod tray_icon_impl;
111#[cfg(target_os = "macos")]
112mod window_impl;
113#[cfg(target_os = "macos")]
114mod window_impl_base;
115
116pub use ferro_native_platform_extensions::{FerroNativePlatformOptions, FerroNativeRenderingMode, MacOSPlatformOptions};
117
118#[cfg(target_os = "macos")]
119pub use self::{
120 clipboard_impl::ClipboardImpl,
121 cursor::{CursorFactory, FerroNativeCursor},
122 dispatcher_impl::DispatcherImpl,
123 embeddable_top_level_impl::EmbeddableTopLevelImpl,
124 ferro_native_application_platform::FerroNativeApplicationPlatform,
125 ferro_native_drag_source::FerroNativeDragSource,
126 ferro_native_gl_platform_graphics::{
127 FerroNativeGlPlatformGraphics, GlContext, GlDisplay, GlPlatformSurface, GlPlatformSurfaceRenderTarget,
128 GlPlatformSurfaceRenderingSession,
129 },
130 ferro_native_menu_exporter::FerroNativeMenuExporter,
131 ferro_native_platform::FerroNativePlatform,
132 ferro_native_render_timer::FerroNativeRenderTimer,
133 ferro_native_text_input_method::FerroNativeTextInputMethod,
134 frn_string::{frn_string_array_to_vec, frn_string_bytes, frn_string_to_string, FrnString, FrnStringArray},
135 icon_loader::IconLoader,
136 ferro_native_platform_extensions::FerroNativePlatformExtensions,
137 mac_os_activatable_lifetime::MacOSActivatableLifetime,
138 mac_os_native_menu_commands::MacOSNativeMenuCommands,
139 metal::{MetalDevice, MetalDrawingSession, MetalPlatformGraphics, MetalPlatformSurface, MetalRenderTarget},
140 native_platform_settings::NativePlatformSettings,
141 platform_behavior_inhibition::PlatformBehaviorInhibition,
142 popup_impl::PopupImpl,
143 screen_impl::{NativeScreen, ScreenImpl},
144 top_level_impl::{MacOSTopLevelHandle, TopLevelFramebufferSurface, TopLevelImpl},
145 tray_icon_impl::TrayIconImpl,
146 window_impl::WindowImpl,
147 window_impl_base::WindowBaseImpl,
148};
149
150#[cfg(target_os = "macos")]
152#[allow(non_camel_case_types, non_snake_case, clippy::all)]
153pub mod interop {
154 include!(concat!(env!("OUT_DIR"), "/frn_interop.rs"));
155
156 extern "C" {
157 pub fn CreateFerroNative() -> *mut IFerroNativeFactory;
160 }
161
162 impl IFrnWindowBase {
163 pub fn get_frame_size_from(&self, initial: FrnSize) -> Result<FrnSize, ferroui_microcom::HResult> {
170 let mut result = initial;
171 unsafe {
174 ferroui_microcom::HResult::check(((*self.vtbl).GetFrameSize)(
175 self as *const Self as *mut ::core::ffi::c_void,
176 &mut result,
177 ))?;
178 }
179 Ok(result)
180 }
181 }
182
183 pub fn create_ferro_native() -> Option<ComPtr<IFerroNativeFactory>> {
185 unsafe { ComPtr::from_raw(CreateFerroNative()) }
187 }
188}
189
190#[cfg(all(test, target_os = "macos"))]
191mod menu_tests;
192
193#[cfg(all(test, target_os = "macos"))]
194mod tests {
195 use super::interop::*;
196 use ferroui_microcom::{ComPtr, HResult, IUnknown, Interface};
197 use std::cell::Cell;
198 use std::ffi::CStr;
199 use std::mem::size_of;
200 use std::rc::Rc;
201
202 const PTR: usize = size_of::<usize>();
203
204 #[test]
207 fn vtable_sizes() {
208 assert_eq!(size_of::<IFrnStringVtbl>(), (3 + 2) * PTR);
209 assert_eq!(size_of::<IFrnTopLevelVtbl>(), (3 + 16) * PTR);
210 assert_eq!(size_of::<IFrnWindowBaseVtbl>(), (3 + 16 + 17) * PTR);
211 assert_eq!(size_of::<IFrnPopupVtbl>(), (3 + 16 + 17 + 1) * PTR);
212 assert_eq!(size_of::<IFrnWindowVtbl>(), (3 + 16 + 17 + 14) * PTR);
213 assert_eq!(size_of::<IFrnWindowEventsVtbl>(), (3 + 11 + 3 + 3) * PTR);
214 assert_eq!(size_of::<IFrnWindow>(), PTR);
215 }
216
217 #[test]
218 fn struct_layouts_match_cpp() {
219 assert_eq!(size_of::<FrnSize>(), 16);
220 assert_eq!(size_of::<FrnRect>(), 32);
221 assert_eq!(size_of::<FrnColor>(), 4);
222 assert_eq!(size_of::<FrnScreen>(), 32 + 32 + 4 + 4 + 4 + 4);
223 assert_eq!(size_of::<FrnFramebuffer>(), 8 + 4 + 4 + 4 + 4 + 16 + 4 + 4);
224 assert_eq!(size_of::<FrnKey>(), 4);
225 assert_eq!(FrnLandmarkType::LandmarkNone.0, -1);
226 assert_eq!(FrnLandmarkType::LandmarkBanner.0, 0);
227 assert_eq!(FrnKey::FrnKeyEnter, FrnKey::FrnKeyReturn);
228 assert_eq!(format!("{:?}", FrnWindowState(99)), "FrnWindowState(99)");
229 }
230
231 struct Source {
232 calls: Rc<Cell<u32>>,
233 }
234 impl IFrnClipboardDataSourceImpl for Source {
235 fn get_item_count(&self) -> i32 {
236 self.calls.set(self.calls.get() + 1);
237 7
238 }
239 fn get_item(&self, index: i32) -> Result<Option<ComPtr<IFrnClipboardDataItem>>, HResult> {
240 if index == 0 {
241 Ok(None)
242 } else {
243 Err(HResult::INVALIDARG)
244 }
245 }
246 }
247
248 #[test]
250 fn rust_callback_roundtrip() {
251 let calls = Rc::new(Cell::new(0));
252 let source = IFrnClipboardDataSource::from_impl(Source { calls: calls.clone() });
253 assert_eq!(source.get_item_count(), 7);
254 assert_eq!(calls.get(), 1);
255 assert_eq!(source.get_item(0), Ok(None));
256 assert_eq!(source.get_item(3), Err(HResult::INVALIDARG));
257
258 assert!(source.cast::<IFrnClipboardDataSource>().is_ok());
260 assert!(source.cast::<IUnknown>().is_ok());
261 assert_eq!(source.cast::<IFrnClipboard>().unwrap_err(), HResult::NOINTERFACE);
262 assert!(IFrnWindowEvents::matches_iid(&IFrnTopLevelEvents::IID));
263 assert!(!IFrnTopLevelEvents::matches_iid(&IFrnWindowEvents::IID));
264 assert_eq!(Rc::strong_count(&calls), 2);
265 drop(source);
266 assert_eq!(Rc::strong_count(&calls), 1, "implementation dropped with the last reference");
267 }
268
269 struct Peer;
270 impl IFrnTextInputMethodClientImpl for Peer {
271 fn set_preedit_text(&self, preedit_text: Option<&CStr>) {
272 assert_eq!(preedit_text, Some(c"abc"));
273 }
274 fn select_in_surrounding_text(&self, start: i32, end: i32) {
275 assert_eq!((start, end), (1, 2));
276 }
277 }
278
279 #[test]
280 fn rc_and_string_arguments() {
281 let client = IFrnTextInputMethodClient::from_impl(Rc::new(Peer));
282 client.set_preedit_text(Some(c"abc"));
283 client.select_in_surrounding_text(1, 2);
284 }
285
286 #[test]
289 fn native_factory_basic_calls() {
290 let factory = create_ferro_native().expect("factory");
291 let options = factory.get_mac_options().expect("mac options");
292 options.set_disable_set_process_name(1).unwrap();
293 assert!(factory.cast::<IFerroNativeFactory>().is_ok());
295 assert!(factory.cast::<IUnknown>().is_ok());
296 assert_eq!(factory.cast::<IFrnWindow>().unwrap_err(), HResult::NOINTERFACE);
297 let helper = factory.create_memory_management_helper().unwrap().expect("helper");
298 drop(helper);
299 }
300}