1#![allow(trivial_casts)]
2
3use std::sync::Once;
4
5use objc::{
6 class,
7 declare::ClassDecl,
8 runtime::{Class, Object, Sel},
9 sel, sel_impl,
10};
11
12use crate::objective_c_runtime::id;
13
14use super::{NSApplicationTerminateReply, NSMenu, NSAPPLICATION_PTR};
15
16pub trait PNSApplicationDelegate {
20 fn will_finish_launching(&mut self) {}
23
24 fn did_finish_launching(&mut self) {}
26
27 fn did_become_active(&mut self) {}
29
30 fn will_resign_active(&mut self) {}
32
33 fn will_continue_user_activity(&mut self, _activity_type: &str) -> bool {
35 false
36 }
37
38 fn will_terminate(&mut self) {}
40
41 fn will_become_active(&mut self) {}
43
44 fn did_resign_active(&mut self) {}
46
47 fn will_hide(&mut self) {}
49
50 fn did_hide(&mut self) {}
52
53 fn will_unhide(&mut self) {}
55
56 fn did_unhide(&mut self) {}
58
59 fn will_update(&mut self) {}
61
62 fn did_update(&mut self) {}
64
65 fn should_terminate(&mut self) -> NSApplicationTerminateReply {
72 NSApplicationTerminateReply::Now
73 }
74
75 fn should_terminate_after_last_window_closed(&mut self) -> bool {
78 false
79 }
80
81 fn should_handle_reopen(&mut self, _has_visible_windows: bool) -> bool {
99 true
100 }
101
102 fn dock_menu(&mut self) -> Option<NSMenu> {
105 None
106 }
107}
108
109fn app<T>(this: &mut Object) -> &mut T {
112 unsafe {
113 let app_ptr: usize = *this.get_ivar(NSAPPLICATION_PTR);
114 let app = app_ptr as *mut T;
115 &mut *app
116 }
117}
118
119extern "C" fn will_finish_launching<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
121 app::<T>(this).will_finish_launching();
122}
123
124extern "C" fn did_finish_launching<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
126 app::<T>(this).did_finish_launching();
127}
128
129extern "C" fn will_become_active<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
131 app::<T>(this).will_become_active();
132}
133
134extern "C" fn did_become_active<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
136 app::<T>(this).did_become_active();
137}
138
139extern "C" fn will_resign_active<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
141 app::<T>(this).will_resign_active();
142}
143
144extern "C" fn did_resign_active<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
146 app::<T>(this).did_resign_active();
147}
148
149extern "C" fn should_terminate<T: PNSApplicationDelegate>(
151 this: &mut Object,
152 _: Sel,
153 _: id,
154) -> NSApplicationTerminateReply {
155 app::<T>(this).should_terminate()
156}
157
158extern "C" fn will_terminate<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
160 app::<T>(this).will_terminate();
161}
162
163extern "C" fn will_hide<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
165 app::<T>(this).will_hide();
166}
167
168extern "C" fn did_hide<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
170 app::<T>(this).did_hide();
171}
172
173extern "C" fn will_unhide<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
175 app::<T>(this).will_unhide();
176}
177
178extern "C" fn did_unhide<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
180 app::<T>(this).did_unhide();
181}
182
183extern "C" fn will_update<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
185 app::<T>(this).will_update();
186}
187
188extern "C" fn did_update<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) {
190 app::<T>(this).did_update();
191}
192
193extern "C" fn should_terminate_after_last_window_closed<T>(this: &mut Object, _: Sel, _: id) -> bool
194where
195 T: PNSApplicationDelegate,
196{
197 app::<T>(this).should_terminate_after_last_window_closed()
198}
199
200extern "C" fn should_handle_reopen<T: PNSApplicationDelegate>(
203 this: &mut Object,
204 _: Sel,
205 _: id,
206 has_visible_windows: bool,
207) -> bool {
208 app::<T>(this).should_handle_reopen(has_visible_windows)
209}
210
211#[allow(improper_ctypes_definitions)]
213extern "C" fn dock_menu<T: PNSApplicationDelegate>(this: &mut Object, _: Sel, _: id) -> NSMenu {
214 app::<T>(this).dock_menu().unwrap_or_default()
215}
216
217pub fn register_app_delegate_class<T: PNSApplicationDelegate + PNSApplicationDelegate>(
220) -> *const Class {
221 static mut DELEGATE_CLASS: *const Class = 0 as *const Class;
222 static INIT: Once = Once::new();
223
224 INIT.call_once(|| unsafe {
225 let superclass = class!(NSObject);
226 let mut decl = ClassDecl::new("RSTNSApplicationDelegate", superclass).unwrap();
227
228 decl.add_ivar::<usize>(NSAPPLICATION_PTR);
229
230 decl.add_method(
232 sel!(applicationWillFinishLaunching:),
233 will_finish_launching::<T> as extern "C" fn(&mut Object, _, _),
234 );
235 decl.add_method(
236 sel!(applicationDidFinishLaunching:),
237 did_finish_launching::<T> as extern "C" fn(&mut Object, _, _),
238 );
239
240 decl.add_method(
242 sel!(applicationWillBecomeActive:),
243 will_become_active::<T> as extern "C" fn(&mut Object, _, _),
244 );
245 decl.add_method(
246 sel!(applicationDidBecomeActive:),
247 did_become_active::<T> as extern "C" fn(&mut Object, _, _),
248 );
249 decl.add_method(
250 sel!(applicationWillResignActive:),
251 will_resign_active::<T> as extern "C" fn(&mut Object, _, _),
252 );
253 decl.add_method(
254 sel!(applicationDidResignActive:),
255 did_resign_active::<T> as extern "C" fn(&mut Object, _, _),
256 );
257
258 decl.add_method(
260 sel!(applicationShouldTerminate:),
261 should_terminate::<T>
262 as extern "C" fn(&mut Object, _, _) -> NSApplicationTerminateReply,
263 );
264 decl.add_method(
265 sel!(applicationWillTerminate:),
266 will_terminate::<T> as extern "C" fn(&mut Object, _, _),
267 );
268
269 decl.add_method(
271 sel!(applicationWillHide:),
272 will_hide::<T> as extern "C" fn(&mut Object, _, _),
273 );
274 decl.add_method(
275 sel!(applicationDidHide:),
276 did_hide::<T> as extern "C" fn(&mut Object, _, _),
277 );
278 decl.add_method(
279 sel!(applicationWillUnhide:),
280 will_unhide::<T> as extern "C" fn(&mut Object, _, _),
281 );
282 decl.add_method(
283 sel!(applicationDidUnhide:),
284 did_unhide::<T> as extern "C" fn(&mut Object, _, _),
285 );
286
287 decl.add_method(
289 sel!(applicationWillUpdate:),
290 will_update::<T> as extern "C" fn(&mut Object, _, _),
291 );
292 decl.add_method(
293 sel!(applicationDidUpdate:),
294 did_update::<T> as extern "C" fn(&mut Object, _, _),
295 );
296 decl.add_method(
297 sel!(applicationShouldHandleReopen:hasVisibleWindows:),
298 should_handle_reopen::<T> as extern "C" fn(&mut Object, _, _, bool) -> bool,
299 );
300
301 decl.add_method(
303 sel!(applicationDockMenu:),
304 dock_menu::<T> as extern "C" fn(&mut Object, _, _) -> NSMenu,
305 );
306
307 decl.add_method(
308 sel!(applicationShouldTerminateAfterLastWindowClosed:),
309 should_terminate_after_last_window_closed::<T>
310 as extern "C" fn(&mut Object, _, _) -> bool,
311 );
312
313 DELEGATE_CLASS = decl.register();
314 });
315
316 unsafe { DELEGATE_CLASS }
317}