From 3b8e285d932a98b0dd420d6c0bc1564a41a713ed Mon Sep 17 00:00:00 2001 From: Marrub Date: Mon, 25 Mar 2019 20:44:06 -0400 Subject: [PATCH] reference counted management of the editor state --- source/tycho/main.rs | 106 +++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/source/tycho/main.rs b/source/tycho/main.rs index c65107e..604f12e 100644 --- a/source/tycho/main.rs +++ b/source/tycho/main.rs @@ -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; - 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); 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>) { /// 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; + 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::)); + let edit = Rc::new(None::); + 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);