mirror of
https://github.com/SpaceManiac/SpacemanDMM.git
synced 2025-12-23 05:36:47 +00:00
Move DME loading to a background thread
This commit is contained in:
parent
9d2b8bccbd
commit
9ee34bc010
3 changed files with 130 additions and 48 deletions
|
|
@ -117,6 +117,7 @@ macro_rules! action {
|
|||
|
||||
#[allow(unused_mut)]
|
||||
fn main() {
|
||||
// This RefCell is only a minor layer of safety in a wildly unsafe setup
|
||||
let mut state_cell = RefCell::new(State::new());
|
||||
macro_rules! state {
|
||||
() => {&mut *state_cell.borrow_mut()}
|
||||
|
|
@ -359,60 +360,75 @@ impl State {
|
|||
}
|
||||
|
||||
unsafe fn load_env(&mut self, path: PathBuf) {
|
||||
let self_ptr: *mut Self = self;
|
||||
let window_ptr = self.widgets.window;
|
||||
|
||||
println!("Environment: {}", path.display());
|
||||
|
||||
let mut preprocessor;
|
||||
match dm::preprocessor::Preprocessor::new(path.clone()) {
|
||||
Err(_) => return show_error(self.widgets.window(), &format!("Could not open for reading:\n{}", path.display())),
|
||||
Ok(pp) => preprocessor = pp,
|
||||
};
|
||||
let path2 = path.clone();
|
||||
qt::future::spawn(move || -> Option<ObjectTree> {
|
||||
let mut preprocessor;
|
||||
match dm::preprocessor::Preprocessor::new(path2.clone()) {
|
||||
Err(_) => {
|
||||
show_error(&mut *static_cast_mut(window_ptr), &format!("Could not open for reading:\n{}", path2.display()));
|
||||
return None;
|
||||
},
|
||||
Ok(pp) => preprocessor = pp,
|
||||
};
|
||||
|
||||
let objtree;
|
||||
match dm::parser::parse(dm::indents::IndentProcessor::new(&mut preprocessor)) {
|
||||
Err(e) => {
|
||||
let mut message = format!("\
|
||||
Could not parse the environment:\n\
|
||||
{}\n\n\
|
||||
This may be caused by incorrect or unusual code, but is typically a parser bug. \
|
||||
Change the code to use a more common form, or report the parsing problem.\n\
|
||||
", path.display());
|
||||
let mut message_buf = Vec::new();
|
||||
let _ = dm::pretty_print_error(&mut message_buf, &preprocessor, &e);
|
||||
message.push_str(&String::from_utf8_lossy(&message_buf[..]));
|
||||
return show_error(self.widgets.window(), &message);
|
||||
},
|
||||
Ok(t) => objtree = t,
|
||||
}
|
||||
|
||||
// fill the object tree
|
||||
{
|
||||
let widget = self.widgets.tree();
|
||||
widget.clear();
|
||||
let root = objtree.root();
|
||||
for &root_child in ["area", "turf", "obj", "mob"].iter() {
|
||||
let ty = root.child(root_child, &objtree).expect("builtins missing");
|
||||
|
||||
let mut root_item = TreeWidgetItem::new(());
|
||||
root_item.set_text(0, qstr!(&ty.name));
|
||||
add_children(&mut root_item, ty, &objtree);
|
||||
widget.add_top_level_item(qt_own!(root_item));
|
||||
match dm::parser::parse(dm::indents::IndentProcessor::new(&mut preprocessor)) {
|
||||
Err(e) => {
|
||||
let mut message = format!("\
|
||||
Could not parse the environment:\n\
|
||||
{}\n\n\
|
||||
This may be caused by incorrect or unusual code, but is typically a parser bug. \
|
||||
Change the code to use a more common form, or report the parsing problem.\n\
|
||||
", path2.display());
|
||||
let mut message_buf = Vec::new();
|
||||
let _ = dm::pretty_print_error(&mut message_buf, &preprocessor, &e);
|
||||
message.push_str(&String::from_utf8_lossy(&message_buf[..]));
|
||||
show_error(&mut *static_cast_mut(window_ptr), &message);
|
||||
None
|
||||
},
|
||||
Ok(t) => Some(t)
|
||||
}
|
||||
}
|
||||
self.config.make_recent(&path);
|
||||
self.update_recent();
|
||||
self.config.save();
|
||||
}, move |objtree| {
|
||||
let this = &mut *self_ptr;
|
||||
let objtree = match objtree {
|
||||
Some(t) => t,
|
||||
None => return
|
||||
};
|
||||
|
||||
self.env = Some(Environment {
|
||||
root: path.parent().unwrap().to_owned(),
|
||||
dme: path,
|
||||
objtree: objtree,
|
||||
// fill the object tree
|
||||
{
|
||||
let widget = this.widgets.tree();
|
||||
widget.clear();
|
||||
let root = objtree.root();
|
||||
for &root_child in ["area", "turf", "obj", "mob"].iter() {
|
||||
let ty = root.child(root_child, &objtree).expect("builtins missing");
|
||||
|
||||
let mut root_item = TreeWidgetItem::new(());
|
||||
root_item.set_text(0, qstr!(&ty.name));
|
||||
add_children(&mut root_item, ty, &objtree);
|
||||
widget.add_top_level_item(qt_own!(root_item));
|
||||
}
|
||||
}
|
||||
this.config.make_recent(&path);
|
||||
this.update_recent();
|
||||
this.config.save();
|
||||
|
||||
this.env = Some(Environment {
|
||||
root: path.parent().unwrap().to_owned(),
|
||||
dme: path,
|
||||
objtree: objtree,
|
||||
});
|
||||
|
||||
// un-disable the actions
|
||||
let actions = this.widgets.menu_file().actions();
|
||||
for i in 0..actions.count() {
|
||||
(**actions.at(i)).set_disabled(false);
|
||||
}
|
||||
});
|
||||
|
||||
// un-disable the actions
|
||||
let actions = self.widgets.menu_file().actions();
|
||||
for i in 0..actions.count() {
|
||||
(**actions.at(i)).set_disabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn new_map(&mut self) {
|
||||
|
|
|
|||
65
src/qt-extras/future.rs
Normal file
65
src/qt-extras/future.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use std::sync::mpsc;
|
||||
use libc::c_void;
|
||||
|
||||
// doesn't check for Send or Sync
|
||||
pub unsafe fn spawn<F1, F2, R>(task: F1, callback: F2) where
|
||||
F1: 'static + FnOnce() -> R,
|
||||
F2: 'static + FnOnce(R),
|
||||
{
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let (task, task_data) = make_callback(move || {
|
||||
let _ = tx.send(task());
|
||||
});
|
||||
let (cb, cb_data) = make_callback(move || {
|
||||
if let Ok(data) = rx.try_recv() {
|
||||
callback(data);
|
||||
}
|
||||
});
|
||||
qt_spawn_future(task, task_data, cb, cb_data);
|
||||
}
|
||||
|
||||
unsafe fn make_callback<F: FnOnce()>(f: F) -> (callback_fn, *mut c_void) {
|
||||
unsafe extern "C" fn callback<F: FnOnce()>(ptr: *mut c_void) {
|
||||
Box::from_raw(ptr as *mut F)();
|
||||
}
|
||||
(callback::<F>, Box::into_raw(Box::new(f)) as *mut c_void)
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
type callback_fn = unsafe extern "C" fn(*mut c_void);
|
||||
extern {
|
||||
fn qt_spawn_future(task: callback_fn, task_data: *mut c_void, cb: callback_fn, cb_data: *mut c_void);
|
||||
}
|
||||
|
||||
cpp! {{
|
||||
#include <QtCore/QFuture.h>
|
||||
#include <QtCore/QFutureWatcher.h>
|
||||
#include <QtConcurrent/QtConcurrent>
|
||||
|
||||
extern "C" typedef void (*callback_fn)(void*);
|
||||
|
||||
class RustSignaller: public QFutureWatcher<void> {
|
||||
callback_fn callback;
|
||||
void* data;
|
||||
void handleFinished() {
|
||||
callback(data);
|
||||
delete this;
|
||||
}
|
||||
|
||||
public:
|
||||
RustSignaller(callback_fn callback, void* data)
|
||||
: callback(callback)
|
||||
, data(data)
|
||||
{
|
||||
QObject::connect(this, &QFutureWatcher::finished, this, &RustSignaller::handleFinished);
|
||||
}
|
||||
};
|
||||
|
||||
extern "C" void qt_spawn_future(callback_fn task, void* taskData, callback_fn cb, void* cbData) {
|
||||
RustSignaller* signaller = new RustSignaller(cb, cbData);
|
||||
QFuture<void> future = QtConcurrent::run([=]() {
|
||||
task(taskData);
|
||||
});
|
||||
signaller->setFuture(future);
|
||||
}
|
||||
}}
|
||||
|
|
@ -6,6 +6,7 @@ pub extern crate cpp_utils;
|
|||
#[macro_use] extern crate cpp;
|
||||
|
||||
pub mod glium_widget;
|
||||
pub mod future;
|
||||
|
||||
pub use widgets::qt_core as core;
|
||||
pub use widgets::qt_gui as gui;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue