1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
// Copyright (c) 2023-present, Raphael Amorim.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//
// Originally retired from https://github.com/not-fl3/macroquad licensed under MIT
// https://github.com/not-fl3/macroquad/blob/master/LICENSE-MIT
// The code has suffered several changes like support to multiple windows, extension of windows
// properties, menu support and etc.

#![cfg(target_os = "macos")]

pub mod app;
pub mod conf;
mod event;
pub mod event_loop;
pub mod native;
mod resources;
pub mod sync;
pub use event::*;

use once_cell::sync::OnceCell;
use sync::FairMutex;

macro_rules! unwrap_or_return {
    ( $e:expr ) => {
        match $e {
            Some(x) => x,
            None => return,
        }
    };
}

static NATIVE_DISPLAY: OnceCell<FairMutex<native::Handler>> = OnceCell::new();

fn set_handler() {
    let _ = NATIVE_DISPLAY.set(FairMutex::new(native::Handler::new()));
}

fn get_handler() -> &'static FairMutex<native::Handler> {
    NATIVE_DISPLAY
        .get()
        .expect("Backend has not initialized NATIVE_DISPLAY yet.") //|| Mutex::new(Default::default()))
}

fn set_display(id: u16, display: native::NativeDisplayData) {
    let handler: &FairMutex<native::Handler> = get_handler();
    handler.lock().insert(id, display);
}

pub mod window {
    use super::*;
    pub fn order_quit(id: u16) {
        let mut d = get_handler().lock();
        if let Some(d) = d.get_mut(id) {
            d.quit_ordered = true;
        }
    }
    pub fn quit(id: u16) {
        order_quit(id)
    }
    pub fn request_quit() {
        App::confirm_quit()
    }
    pub fn cancel_quit(id: u16) {
        let mut d = get_handler().lock();
        if let Some(d) = d.get_mut(id) {
            d.quit_requested = false;
        }
    }
    pub fn set_cursor_grab(id: u16, grab: bool) {
        let d = get_handler().lock();
        if let Some(display) = d.get(id) {
            let view = display.view;
            unsafe {
                if let Some(display) = native::macos::get_display_payload(&*view) {
                    display.set_cursor_grab(grab);
                }
            }
        }
    }
    /// Show or hide the mouse cursor
    pub fn show_mouse(id: u16, shown: bool) {
        let d = get_handler().lock();
        let view = unwrap_or_return!(d.get(id)).view;
        // drop view as soon we have it, if let Some() keeps locked until block drop
        drop(d);

        unsafe {
            if let Some(display) = native::macos::get_display_payload(&*view) {
                display.show_mouse(shown);
            }
        }
    }

    /// Show or hide the mouse cursor
    pub fn set_window_title(id: u16, title: String, subtitle: String) {
        let d = get_handler().lock();
        let view = unwrap_or_return!(d.get(id)).view;
        drop(d);
        // drop view as soon we have it, if let Some() keeps locked until block drop

        unsafe {
            if let Some(display) = native::macos::get_display_payload(&*view) {
                display.set_title(&title);
                display.set_subtitle(&subtitle);
            }
        }
    }

    pub fn get_appearance() -> Appearance {
        App::appearance()
    }

    /// Set the mouse cursor icon.
    pub fn set_mouse_cursor(id: u16, cursor_icon: CursorIcon) {
        let d = get_handler().lock();
        let view = unwrap_or_return!(d.get(id)).view;
        drop(d);
        // drop view as soon we have it, if let Some() keeps locked until block drop

        unsafe {
            if let Some(display) = native::macos::get_display_payload(&*view) {
                display.set_mouse_cursor(cursor_icon);
            }
        }
    }

    /// Set the application's window size.
    pub fn set_window_size(id: u16, new_width: u32, new_height: u32) {
        let d = get_handler().lock();
        if let Some(display) = d.get(id) {
            let view = display.view;
            unsafe {
                if let Some(display) = native::macos::get_display_payload(&*view) {
                    display.set_window_size(new_width, new_height);
                }
            }
        }
    }

    pub fn set_fullscreen(id: u16, fullscreen: bool) {
        let d = get_handler().lock();
        if let Some(display) = d.get(id) {
            let view = display.view;
            unsafe {
                if let Some(display) = native::macos::get_display_payload(&*view) {
                    display.set_fullscreen(fullscreen);
                }
            }
        }
    }
    /// Get current OS clipboard value
    pub fn clipboard_get(_id: u16) -> Option<String> {
        // let mut d = get_handler().lock();
        // if let Some(d) = d.get_mut(id) {
        //     d.clipboard.get()
        // } else {
        Some(String::from(""))
        // }
    }
    /// Save value to OS clipboard
    pub fn clipboard_set(_id: u16, _data: &str) {
        // let mut d = get_handler().lock();
        // if let Some(d) = d.get_mut(id) {
        //     d.clipboard.set(data)
        // }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)]
pub enum CursorIcon {
    Default,
    Help,
    Pointer,
    Wait,
    Crosshair,
    Text,
    Move,
    NotAllowed,
    EWResize,
    NSResize,
    NESWResize,
    NWSEResize,
}

#[derive(Copy, Clone, PartialEq)]
pub enum Target {
    Game,
    Application,
}

#[cfg(target_os = "macos")]
pub type App = native::macos::App;
#[cfg(target_os = "macos")]
pub type Window = native::macos::Window;
#[cfg(target_os = "macos")]
pub type MenuItem = native::apple::menu::MenuItem;