1 #![cfg(target_os = "ios")]
2 
3 use std::os::raw::c_void;
4 
5 use crate::{
6     event_loop::EventLoop,
7     monitor::{MonitorHandle, VideoMode},
8     window::{Window, WindowBuilder},
9 };
10 
11 /// Additional methods on [`EventLoop`] that are specific to iOS.
12 pub trait EventLoopExtIOS {
13     /// Returns the [`Idiom`] (phone/tablet/tv/etc) for the current device.
idiom(&self) -> Idiom14     fn idiom(&self) -> Idiom;
15 }
16 
17 impl<T: 'static> EventLoopExtIOS for EventLoop<T> {
idiom(&self) -> Idiom18     fn idiom(&self) -> Idiom {
19         self.event_loop.idiom()
20     }
21 }
22 
23 /// Additional methods on [`Window`] that are specific to iOS.
24 pub trait WindowExtIOS {
25     /// Returns a pointer to the [`UIWindow`] that is used by this window.
26     ///
27     /// The pointer will become invalid when the [`Window`] is destroyed.
28     ///
29     /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
ui_window(&self) -> *mut c_void30     fn ui_window(&self) -> *mut c_void;
31 
32     /// Returns a pointer to the [`UIViewController`] that is used by this window.
33     ///
34     /// The pointer will become invalid when the [`Window`] is destroyed.
35     ///
36     /// [`UIViewController`]: https://developer.apple.com/documentation/uikit/uiviewcontroller?language=objc
ui_view_controller(&self) -> *mut c_void37     fn ui_view_controller(&self) -> *mut c_void;
38 
39     /// Returns a pointer to the [`UIView`] that is used by this window.
40     ///
41     /// The pointer will become invalid when the [`Window`] is destroyed.
42     ///
43     /// [`UIView`]: https://developer.apple.com/documentation/uikit/uiview?language=objc
ui_view(&self) -> *mut c_void44     fn ui_view(&self) -> *mut c_void;
45 
46     /// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`.
47     ///
48     /// The default value is device dependent, and it's recommended GLES or Metal applications set
49     /// this to [`MonitorHandle::scale_factor()`].
50     ///
51     /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
52     /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
set_scale_factor(&self, scale_factor: f64)53     fn set_scale_factor(&self, scale_factor: f64);
54 
55     /// Sets the valid orientations for the [`Window`].
56     ///
57     /// The default value is [`ValidOrientations::LandscapeAndPortrait`].
58     ///
59     /// This changes the value returned by
60     /// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc),
61     /// and then calls
62     /// [`-[UIViewController attemptRotationToDeviceOrientation]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621400-attemptrotationtodeviceorientati?language=objc).
set_valid_orientations(&self, valid_orientations: ValidOrientations)63     fn set_valid_orientations(&self, valid_orientations: ValidOrientations);
64 
65     /// Sets whether the [`Window`] prefers the home indicator hidden.
66     ///
67     /// The default is to prefer showing the home indicator.
68     ///
69     /// This changes the value returned by
70     /// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc),
71     /// and then calls
72     /// [`-[UIViewController setNeedsUpdateOfHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887509-setneedsupdateofhomeindicatoraut?language=objc).
73     ///
74     /// This only has an effect on iOS 11.0+.
set_prefers_home_indicator_hidden(&self, hidden: bool)75     fn set_prefers_home_indicator_hidden(&self, hidden: bool);
76 
77     /// Sets the screen edges for which the system gestures will take a lower priority than the
78     /// application's touch handling.
79     ///
80     /// This changes the value returned by
81     /// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc),
82     /// and then calls
83     /// [`-[UIViewController setNeedsUpdateOfScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887507-setneedsupdateofscreenedgesdefer?language=objc).
84     ///
85     /// This only has an effect on iOS 11.0+.
set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge)86     fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge);
87 
88     /// Sets whether the [`Window`] prefers the status bar hidden.
89     ///
90     /// The default is to prefer showing the status bar.
91     ///
92     /// This changes the value returned by
93     /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc),
94     /// and then calls
95     /// [`-[UIViewController setNeedsStatusBarAppearanceUpdate]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621354-setneedsstatusbarappearanceupdat?language=objc).
set_prefers_status_bar_hidden(&self, hidden: bool)96     fn set_prefers_status_bar_hidden(&self, hidden: bool);
97 }
98 
99 impl WindowExtIOS for Window {
100     #[inline]
ui_window(&self) -> *mut c_void101     fn ui_window(&self) -> *mut c_void {
102         self.window.ui_window() as _
103     }
104 
105     #[inline]
ui_view_controller(&self) -> *mut c_void106     fn ui_view_controller(&self) -> *mut c_void {
107         self.window.ui_view_controller() as _
108     }
109 
110     #[inline]
ui_view(&self) -> *mut c_void111     fn ui_view(&self) -> *mut c_void {
112         self.window.ui_view() as _
113     }
114 
115     #[inline]
set_scale_factor(&self, scale_factor: f64)116     fn set_scale_factor(&self, scale_factor: f64) {
117         self.window.set_scale_factor(scale_factor)
118     }
119 
120     #[inline]
set_valid_orientations(&self, valid_orientations: ValidOrientations)121     fn set_valid_orientations(&self, valid_orientations: ValidOrientations) {
122         self.window.set_valid_orientations(valid_orientations)
123     }
124 
125     #[inline]
set_prefers_home_indicator_hidden(&self, hidden: bool)126     fn set_prefers_home_indicator_hidden(&self, hidden: bool) {
127         self.window.set_prefers_home_indicator_hidden(hidden)
128     }
129 
130     #[inline]
set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge)131     fn set_preferred_screen_edges_deferring_system_gestures(&self, edges: ScreenEdge) {
132         self.window
133             .set_preferred_screen_edges_deferring_system_gestures(edges)
134     }
135 
136     #[inline]
set_prefers_status_bar_hidden(&self, hidden: bool)137     fn set_prefers_status_bar_hidden(&self, hidden: bool) {
138         self.window.set_prefers_status_bar_hidden(hidden)
139     }
140 }
141 
142 /// Additional methods on [`WindowBuilder`] that are specific to iOS.
143 pub trait WindowBuilderExtIOS {
144     /// Sets the root view class used by the [`Window`], otherwise a barebones [`UIView`] is provided.
145     ///
146     /// An instance of the class will be initialized by calling [`-[UIView initWithFrame:]`](https://developer.apple.com/documentation/uikit/uiview/1622488-initwithframe?language=objc).
147     ///
148     /// [`UIView`]: https://developer.apple.com/documentation/uikit/uiview?language=objc
with_root_view_class(self, root_view_class: *const c_void) -> WindowBuilder149     fn with_root_view_class(self, root_view_class: *const c_void) -> WindowBuilder;
150 
151     /// Sets the [`contentScaleFactor`] of the underlying [`UIWindow`] to `scale_factor`.
152     ///
153     /// The default value is device dependent, and it's recommended GLES or Metal applications set
154     /// this to [`MonitorHandle::scale_factor()`].
155     ///
156     /// [`UIWindow`]: https://developer.apple.com/documentation/uikit/uiwindow?language=objc
157     /// [`contentScaleFactor`]: https://developer.apple.com/documentation/uikit/uiview/1622657-contentscalefactor?language=objc
with_scale_factor(self, scale_factor: f64) -> WindowBuilder158     fn with_scale_factor(self, scale_factor: f64) -> WindowBuilder;
159 
160     /// Sets the valid orientations for the [`Window`].
161     ///
162     /// The default value is [`ValidOrientations::LandscapeAndPortrait`].
163     ///
164     /// This sets the initial value returned by
165     /// [`-[UIViewController supportedInterfaceOrientations]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621435-supportedinterfaceorientations?language=objc).
with_valid_orientations(self, valid_orientations: ValidOrientations) -> WindowBuilder166     fn with_valid_orientations(self, valid_orientations: ValidOrientations) -> WindowBuilder;
167 
168     /// Sets whether the [`Window`] prefers the home indicator hidden.
169     ///
170     /// The default is to prefer showing the home indicator.
171     ///
172     /// This sets the initial value returned by
173     /// [`-[UIViewController prefersHomeIndicatorAutoHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887510-prefershomeindicatorautohidden?language=objc).
174     ///
175     /// This only has an effect on iOS 11.0+.
with_prefers_home_indicator_hidden(self, hidden: bool) -> WindowBuilder176     fn with_prefers_home_indicator_hidden(self, hidden: bool) -> WindowBuilder;
177 
178     /// Sets the screen edges for which the system gestures will take a lower priority than the
179     /// application's touch handling.
180     ///
181     /// This sets the initial value returned by
182     /// [`-[UIViewController preferredScreenEdgesDeferringSystemGestures]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/2887512-preferredscreenedgesdeferringsys?language=objc).
183     ///
184     /// This only has an effect on iOS 11.0+.
with_preferred_screen_edges_deferring_system_gestures( self, edges: ScreenEdge, ) -> WindowBuilder185     fn with_preferred_screen_edges_deferring_system_gestures(
186         self,
187         edges: ScreenEdge,
188     ) -> WindowBuilder;
189 
190     /// Sets whether the [`Window`] prefers the status bar hidden.
191     ///
192     /// The default is to prefer showing the status bar.
193     ///
194     /// This sets the initial value returned by
195     /// [`-[UIViewController prefersStatusBarHidden]`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621440-prefersstatusbarhidden?language=objc).
with_prefers_status_bar_hidden(self, hidden: bool) -> WindowBuilder196     fn with_prefers_status_bar_hidden(self, hidden: bool) -> WindowBuilder;
197 }
198 
199 impl WindowBuilderExtIOS for WindowBuilder {
200     #[inline]
with_root_view_class(mut self, root_view_class: *const c_void) -> WindowBuilder201     fn with_root_view_class(mut self, root_view_class: *const c_void) -> WindowBuilder {
202         self.platform_specific.root_view_class = unsafe { &*(root_view_class as *const _) };
203         self
204     }
205 
206     #[inline]
with_scale_factor(mut self, scale_factor: f64) -> WindowBuilder207     fn with_scale_factor(mut self, scale_factor: f64) -> WindowBuilder {
208         self.platform_specific.scale_factor = Some(scale_factor);
209         self
210     }
211 
212     #[inline]
with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> WindowBuilder213     fn with_valid_orientations(mut self, valid_orientations: ValidOrientations) -> WindowBuilder {
214         self.platform_specific.valid_orientations = valid_orientations;
215         self
216     }
217 
218     #[inline]
with_prefers_home_indicator_hidden(mut self, hidden: bool) -> WindowBuilder219     fn with_prefers_home_indicator_hidden(mut self, hidden: bool) -> WindowBuilder {
220         self.platform_specific.prefers_home_indicator_hidden = hidden;
221         self
222     }
223 
224     #[inline]
with_preferred_screen_edges_deferring_system_gestures( mut self, edges: ScreenEdge, ) -> WindowBuilder225     fn with_preferred_screen_edges_deferring_system_gestures(
226         mut self,
227         edges: ScreenEdge,
228     ) -> WindowBuilder {
229         self.platform_specific
230             .preferred_screen_edges_deferring_system_gestures = edges;
231         self
232     }
233 
234     #[inline]
with_prefers_status_bar_hidden(mut self, hidden: bool) -> WindowBuilder235     fn with_prefers_status_bar_hidden(mut self, hidden: bool) -> WindowBuilder {
236         self.platform_specific.prefers_status_bar_hidden = hidden;
237         self
238     }
239 }
240 
241 /// Additional methods on [`MonitorHandle`] that are specific to iOS.
242 pub trait MonitorHandleExtIOS {
243     /// Returns a pointer to the [`UIScreen`] that is used by this monitor.
244     ///
245     /// [`UIScreen`]: https://developer.apple.com/documentation/uikit/uiscreen?language=objc
ui_screen(&self) -> *mut c_void246     fn ui_screen(&self) -> *mut c_void;
247 
248     /// Returns the preferred [`VideoMode`] for this monitor.
249     ///
250     /// This translates to a call to [`-[UIScreen preferredMode]`](https://developer.apple.com/documentation/uikit/uiscreen/1617823-preferredmode?language=objc).
preferred_video_mode(&self) -> VideoMode251     fn preferred_video_mode(&self) -> VideoMode;
252 }
253 
254 impl MonitorHandleExtIOS for MonitorHandle {
255     #[inline]
ui_screen(&self) -> *mut c_void256     fn ui_screen(&self) -> *mut c_void {
257         self.inner.ui_screen() as _
258     }
259 
260     #[inline]
preferred_video_mode(&self) -> VideoMode261     fn preferred_video_mode(&self) -> VideoMode {
262         self.inner.preferred_video_mode()
263     }
264 }
265 
266 /// Valid orientations for a particular [`Window`].
267 #[derive(Clone, Copy, Debug)]
268 pub enum ValidOrientations {
269     /// Excludes `PortraitUpsideDown` on iphone
270     LandscapeAndPortrait,
271 
272     Landscape,
273 
274     /// Excludes `PortraitUpsideDown` on iphone
275     Portrait,
276 }
277 
278 impl Default for ValidOrientations {
279     #[inline]
default() -> ValidOrientations280     fn default() -> ValidOrientations {
281         ValidOrientations::LandscapeAndPortrait
282     }
283 }
284 
285 /// The device [idiom].
286 ///
287 /// [idiom]: https://developer.apple.com/documentation/uikit/uidevice/1620037-userinterfaceidiom?language=objc
288 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
289 pub enum Idiom {
290     Unspecified,
291 
292     /// iPhone and iPod touch.
293     Phone,
294 
295     /// iPad.
296     Pad,
297 
298     /// tvOS and Apple TV.
299     TV,
300     CarPlay,
301 }
302 
303 bitflags! {
304     /// The [edges] of a screen.
305     ///
306     /// [edges]: https://developer.apple.com/documentation/uikit/uirectedge?language=objc
307     #[derive(Default)]
308     pub struct ScreenEdge: u8 {
309         const NONE   = 0;
310         const TOP    = 1 << 0;
311         const LEFT   = 1 << 1;
312         const BOTTOM = 1 << 2;
313         const RIGHT  = 1 << 3;
314         const ALL = ScreenEdge::TOP.bits | ScreenEdge::LEFT.bits
315             | ScreenEdge::BOTTOM.bits | ScreenEdge::RIGHT.bits;
316     }
317 }
318