1#![allow(clippy::missing_safety_doc)]
2
3use std::cell::Cell;
4use std::ptr;
5use std::sync::atomic::{AtomicBool, Ordering};
6
7thread_local! {
8 static IS_MAIN_THREAD: Cell<bool> = Cell::new(false)
9}
10
11static INITIALIZED: AtomicBool = AtomicBool::new(false);
12
13macro_rules! assert_initialized_main_thread {
15 () => {
16 if !crate::rt::is_initialized_main_thread() {
17 if crate::rt::is_initialized() {
18 panic!("GDK may only be used from the main thread.");
19 } else {
20 panic!("GDK has not been initialized. Call `clutter::init` first.");
21 }
22 }
23 };
24}
25
26macro_rules! skip_assert_initialized {
28 () => {};
29}
30
31macro_rules! assert_not_initialized {
33 () => {
34 if crate::rt::is_initialized() {
35 panic!("This function has to be called before `clutter::init`.");
36 }
37 };
38}
39
40#[inline]
42pub fn is_initialized() -> bool {
43 skip_assert_initialized!();
44 INITIALIZED.load(Ordering::Acquire)
45}
46
47#[inline]
49pub fn is_initialized_main_thread() -> bool {
50 skip_assert_initialized!();
51 IS_MAIN_THREAD.with(|c| c.get())
52}
53
54pub unsafe fn set_initialized() {
56 skip_assert_initialized!();
57 if is_initialized_main_thread() {
58 return;
59 } else if is_initialized() {
60 panic!("Attempted to initialize GDK from two different threads.");
61 }
62 INITIALIZED.store(true, Ordering::Release);
63 IS_MAIN_THREAD.with(|c| c.set(true));
64}
65
66pub fn init() {
67 assert_not_initialized!();
68 unsafe {
69 ffi::clutter_init(ptr::null_mut(), ptr::null_mut());
70 set_initialized();
71 }
72}
73
74pub fn run() {
75 assert_initialized_main_thread!();
76 unsafe {
77 ffi::clutter_main();
78 set_initialized();
79 }
80}
81
82pub fn quit() {
83 assert_initialized_main_thread!();
84 unsafe {
85 ffi::clutter_main_quit();
86 }
87}