reference counted management of the editor state
parent
9c91d8bd01
commit
3b8e285d93
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue