Do not allow to create coexisting instances of WindowDrawList

At run time, the environment checks that at most one instance of
WindowDrawList exists using a static boolean: WINDOW_DRAW_LIST_LOADED.

If two WindowDrawList could exist at the same time, there would be
several instances of the same `*mut ImDrawList`, which could lead
to unfathomable bad things.

When a WindowDrawList is created, WINDOW_DRAW_LIST_LOADED is set to
true. And when it is dropped, WINDOW_DRAW_LIST_LOADED is set to false.
Creating a new WindowDrawList while WINDOW_DRAW_LIST_LOADED is true
causes a panic.

AtomicBool could have been used instead of a bool for
WINDOW_DRAW_LIST_LOADED. Though it allows to avoid the use of `unsafe { }`,
the construct we are doing is already inherently unsafe.
WindowDrawList and Ui are !Send and !Sync, so they cannot anyway be shared
among threads.
So we'd better be explicit and use an unsafe block with a normal bool.
This commit is contained in:
Malik Olivier Boussejra 2018-04-15 19:08:12 +09:00
parent 082d5e47f9
commit 454e98037e
2 changed files with 33 additions and 0 deletions

View File

@ -1281,6 +1281,21 @@ impl<'ui> Ui<'ui> {
/// // Continue drawing ...
/// }
/// ```
///
/// This function will panic if several instances of [`WindowDrawList`]
/// coexist. Before a new instance is got, a previous instance should be
/// dropped.
///
/// ```rust
/// # use imgui::*;
/// fn custom_draw(ui: &Ui) {
/// let draw_list = ui.get_window_draw_list();
/// // Draw something...
///
/// // This second call will panic!
/// let draw_list = ui.get_window_draw_list();
/// }
/// ```
pub fn get_window_draw_list(&'ui self) -> WindowDrawList<'ui> {
WindowDrawList::new(self)
}

View File

@ -54,6 +54,10 @@ pub trait DrawAPI {
}
/// Object implementing the custom draw API.
///
/// Called from [`Ui::get_window_draw_list`]. No more than one instance of this
/// structure can live in a program at the same time.
/// The program will panic on creating a second instance.
pub struct WindowDrawList<'ui> {
draw_list: *mut ImDrawList,
_phantom: PhantomData<&'ui Ui<'ui>>,
@ -63,8 +67,22 @@ impl<'ui> DrawAPI for WindowDrawList<'ui> {
fn draw_list(&self) -> *mut ImDrawList { self.draw_list }
}
static mut WINDOW_DRAW_LIST_LOADED: bool = false;
impl<'ui> Drop for WindowDrawList<'ui> {
fn drop(&mut self) {
unsafe { WINDOW_DRAW_LIST_LOADED = false; }
}
}
impl<'ui> WindowDrawList<'ui> {
pub(crate) fn new(_: &Ui<'ui>) -> Self {
unsafe {
if WINDOW_DRAW_LIST_LOADED {
panic!("WindowDrawList is already loaded! You can only load one instance of it!")
}
WINDOW_DRAW_LIST_LOADED = true;
}
Self {
draw_list: unsafe { sys::igGetWindowDrawList() },
_phantom: PhantomData,