1 // Take a look at the license at the top of the repository in the LICENSE file.
2 
3 //! General — Library initialization and miscellaneous functions
4 
5 use std::cell::Cell;
6 use std::ptr;
7 use std::sync::atomic::{AtomicBool, Ordering};
8 
9 thread_local! {
10     static IS_MAIN_THREAD: Cell<bool> = Cell::new(false)
11 }
12 
13 static INITIALIZED: AtomicBool = AtomicBool::new(false);
14 
15 /// Asserts that this is the main thread and either `gdk::init` or `gtk::init` has been called.
16 macro_rules! assert_initialized_main_thread {
17     () => {
18         if !crate::rt::is_initialized_main_thread() {
19             if crate::rt::is_initialized() {
20                 panic!("GDK may only be used from the main thread.");
21             } else {
22                 panic!("GDK has not been initialized. Call `gdk::init` or `gtk::init` first.");
23             }
24         }
25     };
26 }
27 
28 /// No-op.
29 macro_rules! skip_assert_initialized {
30     () => {};
31 }
32 
33 /// Asserts that neither `gdk::init` nor `gtk::init` has been called.
34 macro_rules! assert_not_initialized {
35     () => {
36         if crate::rt::is_initialized() {
37             panic!("This function has to be called before `gdk::init` or `gtk::init`.");
38         }
39     };
40 }
41 
42 /// Returns `true` if GDK has been initialized.
43 #[inline]
is_initialized() -> bool44 pub fn is_initialized() -> bool {
45     skip_assert_initialized!();
46     INITIALIZED.load(Ordering::Acquire)
47 }
48 
49 /// Returns `true` if GDK has been initialized and this is the main thread.
50 #[inline]
is_initialized_main_thread() -> bool51 pub fn is_initialized_main_thread() -> bool {
52     skip_assert_initialized!();
53     IS_MAIN_THREAD.with(|c| c.get())
54 }
55 
56 /// Informs this crate that GDK has been initialized and the current thread is the main one.
set_initialized()57 pub unsafe fn set_initialized() {
58     skip_assert_initialized!();
59     if is_initialized_main_thread() {
60         return;
61     } else if is_initialized() {
62         panic!("Attempted to initialize GDK from two different threads.");
63     }
64     INITIALIZED.store(true, Ordering::Release);
65     IS_MAIN_THREAD.with(|c| c.set(true));
66 }
67 
68 #[doc(alias = "gdk_init")]
init()69 pub fn init() {
70     assert_not_initialized!();
71     unsafe {
72         ffi::gdk_init(ptr::null_mut(), ptr::null_mut());
73         set_initialized();
74     }
75 }
76