reference counted management of the editor state

gui-branch
an 2019-03-25 20:44:06 -04:00
parent 9c91d8bd01
commit 3b8e285d93
1 changed files with 67 additions and 39 deletions

View File

@ -10,13 +10,14 @@ use glib_sys::*;
use gobject_sys::*;
use gtk_sys::*;
use maraiah::{c_str, durandal::ffi};
use std::rc::Rc;
/// Called whne the application activates in order to set everything up.
unsafe extern "C" fn app_activate(app: *mut GtkApplication, dat: gpointer)
unsafe extern "C" fn app_activate(app: *mut GtkApplication, edit: gpointer)
{
let dat = dat as *mut Option<MapEditorState>;
let dat = &mut *dat;
let _ = dat;
// this ref will be cloned around a bit, but will ultimately be dropped at
// the end of this function.
let edit = Rc::from_raw(edit as *mut Option<MapEditorState>);
setup_css();
@ -28,7 +29,7 @@ unsafe extern "C" fn app_activate(app: *mut GtkApplication, dat: gpointer)
setup_win_map_tools(b);
setup_win_map_prop(b);
setup_about_dlg(b);
setup_win_main(b, app);
setup_win_main(b, app, edit.clone());
g_object_unref(b as _);
}
@ -43,35 +44,35 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder)
ay: *mut GtkAdjustment,
}
unsafe extern "C" fn c_done(_: *mut GtkWidget, dat: gpointer)
unsafe extern "C" fn c_done(_: *mut GtkWidget, rend: gpointer)
{
let dat = Box::from_raw(dat as *mut RenderState);
let rend = Box::from_raw(rend as *mut RenderState);
g_object_unref(dat.im_nomap as _);
g_object_unref(dat.ax as _);
g_object_unref(dat.ay as _);
g_object_unref(rend.im_nomap as _);
g_object_unref(rend.ax as _);
g_object_unref(rend.ay as _);
// data is dropped and freed here
}
unsafe extern "C" fn c_draw(wid: *mut GtkWidget,
ctx: *mut cairo_sys::cairo_t,
dat: gpointer)
rend: gpointer)
-> gboolean
{
let dat = dat as *mut RenderState;
let dat = &mut *dat;
let rend = rend as *mut RenderState;
let rend = &mut *rend;
let w = f64::from(gtk_widget_get_allocated_width(wid));
let h = f64::from(gtk_widget_get_allocated_height(wid));
gtk_adjustment_set_lower(dat.ax, 0.0);
gtk_adjustment_set_upper(dat.ax, w);
gtk_adjustment_set_lower(rend.ax, 0.0);
gtk_adjustment_set_upper(rend.ax, w);
gtk_adjustment_set_lower(dat.ay, 0.0);
gtk_adjustment_set_upper(dat.ay, h);
gtk_adjustment_set_lower(rend.ay, 0.0);
gtk_adjustment_set_upper(rend.ay, h);
let im = CrImage(dat.im_nomap);
let im = CrImage(rend.im_nomap);
let dr = CrDrawArea::new(ctx, w, h);
MapEditorState::draw_none(&dr, &im);
@ -89,11 +90,11 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder)
let im_nomap = load_img(c_str!("/net/greyserv/maraiah/tycho/tycho1.png"));
let dat = RenderState{im_nomap, ax, ay};
let dat = Box::into_raw(Box::new(dat));
let rend = RenderState{im_nomap, ax, ay};
let rend = Box::into_raw(Box::new(rend));
connect(wid as _, c_str!("destroy"), c_done as _, dat as _);
connect(wid as _, c_str!("draw"), c_draw as _, dat as _);
connect(wid as _, c_str!("destroy"), c_done as _, rend as _);
connect(wid as _, c_str!("draw"), c_draw as _, rend as _);
}
/// Sets up the map view window.
@ -131,7 +132,7 @@ unsafe fn setup_about_dlg(b: *mut GtkBuilder)
{
/// Callback to show the dialogue when the "About" button is pressed, and
/// hide it when the "Close" button is pressed on it.
unsafe extern "C" fn c_show(_: *mut GtkWidget, dlg: gpointer)
unsafe extern "C" fn c_show_act(_: *mut GtkWidget, dlg: gpointer)
{
gtk_dialog_run(dlg as _);
gtk_widget_hide(dlg as _);
@ -150,16 +151,18 @@ unsafe fn setup_about_dlg(b: *mut GtkBuilder)
gtk_about_dialog_set_logo(dlg, img);
connect_hide(dlg as _);
connect(btn as _, c_str!("activate"), c_show as _, dlg as _);
connect(btn as _, c_str!("activate"), c_show_act as _, dlg as _);
g_object_unref(img as _);
}
/// Sets up the main menu window.
unsafe fn setup_win_main(b: *mut GtkBuilder, app: *mut GtkApplication)
unsafe fn setup_win_main(b: *mut GtkBuilder,
app: *mut GtkApplication,
edit: Rc<Option<MapEditorState>>)
{
/// Callback to close the window when the "Quit" button is pressed.
unsafe extern "C" fn c_quit(_: *mut GtkWidget, win: gpointer)
unsafe extern "C" fn c_quit_act(_: *mut GtkWidget, win: gpointer)
{
gtk_window_close(win as _);
}
@ -170,7 +173,29 @@ unsafe fn setup_win_main(b: *mut GtkBuilder, app: *mut GtkApplication)
gtk_window_set_application(win, app);
gtk_widget_show_all(win as _);
connect(btn as _, c_str!("activate"), c_quit as _, win as _);
connect(btn as _, c_str!("activate"), c_quit_act as _, win as _);
/// Callback to create a new editor state when the "New" button is pressed.
unsafe extern "C" fn c_new_act(_: *mut GtkWidget, edit: gpointer)
{
let edit = edit as *mut Option<MapEditorState>;
let edit = &mut *edit;
*edit = Some(MapEditorState::new());
}
/// Callback to destroy the editor state reference.
unsafe extern "C" fn c_new_done(_: *mut GtkWidget, edit: gpointer)
{
Rc::from_raw(edit);
}
let edit = Rc::into_raw(edit);
let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-new"));
connect(btn as _, c_str!("activate"), c_new_act as _, edit as _);
connect(btn as _, c_str!("destroy"), c_new_done as _, edit as _);
}
/// Sets up the CSS styling providers.
@ -187,29 +212,30 @@ unsafe fn setup_css()
g_object_unref(css as _);
}
/// Connects a handler that shows a widget when activated.
/// Connects a handler that hides a toplevel widget when deleted.
unsafe fn connect_hide(wid: *mut GtkWidget)
{
/// Callback to hide a widget.
unsafe extern "C" fn c_hide(wid: *mut GtkWidget,
_: *mut GdkEvent,
_: gpointer)
/// Callback to hide the widget.
unsafe extern "C" fn c_hide_del(wid: *mut GtkWidget,
_: *mut GdkEvent,
_: gpointer)
{
gtk_widget_hide(wid);
}
connect(wid as _, c_str!("delete-event"), c_hide as _, ffi::null_mut());
connect(wid as _, c_str!("delete-event"), c_hide_del as _, ffi::null_mut());
}
/// Connects a handler that shows a widget when activated.
unsafe fn connect_show(btn: *mut GtkWidget, wid: *mut GtkWidget)
{
unsafe extern "C" fn c_show(_: *mut GtkWidget, wid: gpointer)
/// Callback to show the widget.
unsafe extern "C" fn c_show_act(_: *mut GtkWidget, wid: gpointer)
{
gtk_widget_show_all(wid as _);
}
connect(btn as _, c_str!("activate"), c_show as _, wid as _);
connect(btn as _, c_str!("activate"), c_show_act as _, wid as _);
}
/// Gets an object from a `GtkBuilder`.
@ -251,20 +277,22 @@ fn main()
g_static_resource_init(&mut resource);
// create a container for the editor state
let dat = Box::into_raw(Box::new(None::<MapEditorState>));
let edit = Rc::new(None::<MapEditorState>);
let eptr = Rc::into_raw(edit.clone());
// create and run the app
let name = c_str!("net.greyserv.maraiah.tycho");
let app = gtk_application_new(name, 0);
let app = gtk_application_new(name, 0);
connect(app as _, c_str!("activate"), app_activate as _, dat as _);
connect(app as _, c_str!("activate"), app_activate as _, eptr as _);
g_application_run(app as _, 0, ffi::null_mut());
// ok, clean up all this crap now
g_object_unref(app as _);
drop(Box::from_raw(dat));
assert!(Rc::strong_count(&edit) == 1);
drop(edit);
// deinit the "static" data, and everything will be done
g_static_resource_fini(&mut resource);