use droppable structure for unref things

gui-branch
an 2019-03-29 13:48:36 -04:00
parent 75e354a16b
commit b8e624fecd
1 changed files with 69 additions and 51 deletions

View File

@ -8,7 +8,7 @@ use glib_sys::*;
use gobject_sys::*; use gobject_sys::*;
use gtk_sys::*; use gtk_sys::*;
use maraiah::{c_str, durandal::ffi}; use maraiah::{c_str, durandal::ffi};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, marker::PhantomData, rc::Rc};
/// Called when the application activates in order to set everything up. /// Called when the application activates in order to set everything up.
unsafe extern "C" fn app_activate(app: *mut GtkApplication, edit: gpointer) unsafe extern "C" fn app_activate(app: *mut GtkApplication, edit: gpointer)
@ -20,40 +20,32 @@ unsafe extern "C" fn app_activate(app: *mut GtkApplication, edit: gpointer)
setup_css(); setup_css();
let path = c_str!("/net/greyserv/maraiah/tycho/ui"); let path = c_str!("/net/greyserv/maraiah/tycho/ui");
let b = gtk_builder_new_from_resource(path); let b = Refc::new(gtk_builder_new_from_resource(path));
setup_draw_area(b, edit.clone()); setup_draw_area(&b, edit.clone());
setup_win_map_view(b); setup_win_map_view(&b);
setup_win_map_tools(b); setup_win_map_tools(&b);
setup_win_map_prop(b); setup_win_map_prop(&b);
setup_about_dlg(b); setup_about_dlg(&b);
setup_win_main(b, app, edit.clone()); setup_win_main(&b, app, edit.clone());
g_object_unref(b as _);
} }
/// Sets up the map view window's drawing area. /// Sets up the map view window's drawing area.
unsafe fn setup_draw_area(b: *mut GtkBuilder, edit: Rc<MapEditorRef>) unsafe fn setup_draw_area(b: &Refc<GtkBuilder>, edit: Rc<MapEditorRef>)
{ {
/// All of the state necessary for the drawing area. /// All of the state necessary for the drawing area.
struct RenderState struct RenderState
{ {
im_nomap: *mut GdkPixbuf, im_nomap: Refc<'static, GdkPixbuf>,
ax: *mut GtkAdjustment, ax: Refc<'static, GtkAdjustment>,
ay: *mut GtkAdjustment, ay: Refc<'static, GtkAdjustment>,
edit: Rc<MapEditorRef>, edit: Rc<MapEditorRef>,
} }
/// Callback to finalize the drawing area. /// Callback to finalize the drawing area.
unsafe extern "C" fn c_done(_: *mut GtkWidget, rend: gpointer) unsafe extern "C" fn c_done(_: *mut GtkWidget, rend: gpointer)
{ {
let rend = Box::from_raw(rend as *mut RenderState); Box::from_raw(rend as *mut RenderState);
g_object_unref(rend.im_nomap as gpointer as _);
g_object_unref(rend.ax as _);
g_object_unref(rend.ay as _);
// data is dropped and freed here
} }
/// Callback to draw on the drawing area. /// Callback to draw on the drawing area.
@ -68,13 +60,13 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder, edit: Rc<MapEditorRef>)
let w = f64::from(gtk_widget_get_allocated_width(wid)); let w = f64::from(gtk_widget_get_allocated_width(wid));
let h = f64::from(gtk_widget_get_allocated_height(wid)); let h = f64::from(gtk_widget_get_allocated_height(wid));
gtk_adjustment_set_lower(rend.ax, 0.0); gtk_adjustment_set_lower(*rend.ax, 0.0);
gtk_adjustment_set_upper(rend.ax, w); gtk_adjustment_set_upper(*rend.ax, w);
gtk_adjustment_set_lower(rend.ay, 0.0); gtk_adjustment_set_lower(*rend.ay, 0.0);
gtk_adjustment_set_upper(rend.ay, h); gtk_adjustment_set_upper(*rend.ay, h);
let im = CrImage(rend.im_nomap); let im = CrImage(*rend.im_nomap);
let mut dr = CrDrawArea::new(ctx, w, h); let mut dr = CrDrawArea::new(ctx, w, h);
rend.edit.borrow().draw(&mut dr, &im); rend.edit.borrow().draw(&mut dr, &im);
@ -87,13 +79,14 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder, edit: Rc<MapEditorRef>)
edit.borrow_mut().set_draw(wid as _); edit.borrow_mut().set_draw(wid as _);
// get all of the necessary state and related objects // get all of the necessary state and related objects
let ax: *mut GtkAdjustment = get_obj(b, c_str!("adj-map-horz")); let ax = Refc::<GtkAdjustment>::new(get_obj(b, c_str!("adj-map-horz")));
let ay: *mut GtkAdjustment = get_obj(b, c_str!("adj-map-vert")); let ay = Refc::<GtkAdjustment>::new(get_obj(b, c_str!("adj-map-vert")));
g_object_ref(ax as _); g_object_ref(*ax as _);
g_object_ref(ay as _); g_object_ref(*ay as _);
let im_nomap = load_img(c_str!("/net/greyserv/maraiah/tycho/tycho1.png")); let im_nomap = load_img(c_str!("/net/greyserv/maraiah/tycho/tycho1.png"));
let im_nomap = Refc::new(im_nomap);
let rend = RenderState{im_nomap, ax, ay, edit}; let rend = RenderState{im_nomap, ax, ay, edit};
let rend = Box::into_raw(Box::new(rend)); let rend = Box::into_raw(Box::new(rend));
@ -103,7 +96,7 @@ unsafe fn setup_draw_area(b: *mut GtkBuilder, edit: Rc<MapEditorRef>)
} }
/// Sets up the map view window. /// Sets up the map view window.
unsafe fn setup_win_map_view(b: *mut GtkBuilder) unsafe fn setup_win_map_view(b: &Refc<GtkBuilder>)
{ {
let win: *mut GtkWindow = get_obj(b, c_str!("win-map-view")); let win: *mut GtkWindow = get_obj(b, c_str!("win-map-view"));
let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-show-map-view")); let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-show-map-view"));
@ -113,7 +106,7 @@ unsafe fn setup_win_map_view(b: *mut GtkBuilder)
} }
/// Sets up the map tools window. /// Sets up the map tools window.
unsafe fn setup_win_map_tools(b: *mut GtkBuilder) unsafe fn setup_win_map_tools(b: &Refc<GtkBuilder>)
{ {
let win: *mut GtkWindow = get_obj(b, c_str!("win-map-tools")); let win: *mut GtkWindow = get_obj(b, c_str!("win-map-tools"));
let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-show-map-tools")); let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-show-map-tools"));
@ -123,7 +116,7 @@ unsafe fn setup_win_map_tools(b: *mut GtkBuilder)
} }
/// Sets up the map properties window. /// Sets up the map properties window.
unsafe fn setup_win_map_prop(b: *mut GtkBuilder) unsafe fn setup_win_map_prop(b: &Refc<GtkBuilder>)
{ {
let win: *mut GtkWindow = get_obj(b, c_str!("win-map-prop")); let win: *mut GtkWindow = get_obj(b, c_str!("win-map-prop"));
let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-show-map-prop")); let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-show-map-prop"));
@ -133,7 +126,7 @@ unsafe fn setup_win_map_prop(b: *mut GtkBuilder)
} }
/// Sets up the about dialogue. /// Sets up the about dialogue.
unsafe fn setup_about_dlg(b: *mut GtkBuilder) unsafe fn setup_about_dlg(b: &Refc<GtkBuilder>)
{ {
/// Callback to show the dialogue when the "About" button is pressed, and /// Callback to show the dialogue when the "About" button is pressed, and
/// hide it when the "Close" button is pressed on it. /// hide it when the "Close" button is pressed on it.
@ -149,20 +142,19 @@ unsafe fn setup_about_dlg(b: *mut GtkBuilder)
let it = env!("CARGO_PKG_AUTHORS").split(';'); let it = env!("CARGO_PKG_AUTHORS").split(';');
let mut v = ffi::CStringVec::new_from_iter(it).unwrap(); let mut v = ffi::CStringVec::new_from_iter(it).unwrap();
let img = load_img(c_str!("/net/greyserv/maraiah/tycho/tycho2.png")); let img = load_img(c_str!("/net/greyserv/maraiah/tycho/tycho2.png"));
let img = Refc::new(img);
gtk_about_dialog_set_authors(dlg, v.as_mut_ptr()); gtk_about_dialog_set_authors(dlg, v.as_mut_ptr());
gtk_about_dialog_set_version(dlg, c_str!(env!("CARGO_PKG_VERSION"))); gtk_about_dialog_set_version(dlg, c_str!(env!("CARGO_PKG_VERSION")));
gtk_about_dialog_set_website(dlg, c_str!(env!("CARGO_PKG_HOMEPAGE"))); gtk_about_dialog_set_website(dlg, c_str!(env!("CARGO_PKG_HOMEPAGE")));
gtk_about_dialog_set_logo(dlg, img); gtk_about_dialog_set_logo(dlg, *img);
connect_hide(dlg as _); connect_hide(dlg as _);
connect(btn as _, c_str!("activate"), c_show_act as _, dlg as _); connect(btn as _, c_str!("activate"), c_show_act as _, dlg as _);
g_object_unref(img as gpointer as _);
} }
/// Sets up explicit window finalization for the main window. /// Sets up explicit window finalization for the main window.
unsafe fn setup_explicit_drop(b: *mut GtkBuilder, win: *mut GtkWindow) unsafe fn setup_explicit_drop(b: &Refc<GtkBuilder>, win: *mut GtkWindow)
{ {
/// Callback to explicitly finalize all windows on exit. /// Callback to explicitly finalize all windows on exit.
unsafe extern "C" fn c_done(_: *mut GtkWidget, exp_del: gpointer) unsafe extern "C" fn c_done(_: *mut GtkWidget, exp_del: gpointer)
@ -179,7 +171,7 @@ unsafe fn setup_explicit_drop(b: *mut GtkBuilder, win: *mut GtkWindow)
let mut exp_del = Vec::new(); let mut exp_del = Vec::new();
// so, we get all of the objects from the builder, and iterate through them // so, we get all of the objects from the builder, and iterate through them
let head = gtk_builder_get_objects(b); let head = gtk_builder_get_objects(**b);
let mut lst = &*head; let mut lst = &*head;
loop { loop {
@ -214,7 +206,7 @@ unsafe fn setup_explicit_drop(b: *mut GtkBuilder, win: *mut GtkWindow)
} }
/// Sets up the main menu window. /// Sets up the main menu window.
unsafe fn setup_win_main(b: *mut GtkBuilder, unsafe fn setup_win_main(b: &Refc<GtkBuilder>,
app: *mut GtkApplication, app: *mut GtkApplication,
edit: Rc<MapEditorRef>) edit: Rc<MapEditorRef>)
{ {
@ -277,14 +269,12 @@ unsafe fn setup_win_main(b: *mut GtkBuilder,
unsafe fn setup_css() unsafe fn setup_css()
{ {
let path = c_str!("/net/greyserv/maraiah/tycho/css"); let path = c_str!("/net/greyserv/maraiah/tycho/css");
let css = gtk_css_provider_new(); let css = Refc::new(gtk_css_provider_new());
gtk_css_provider_load_from_resource(css, path); gtk_css_provider_load_from_resource(*css, path);
let scr = gdk_screen_get_default(); let scr = gdk_screen_get_default();
let pri = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION as u32; let pri = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION as u32;
gtk_style_context_add_provider_for_screen(scr, css as _, pri); gtk_style_context_add_provider_for_screen(scr, *css as _, pri);
g_object_unref(css as _);
} }
/// Runs a modal OK/Cancel dialogue. /// Runs a modal OK/Cancel dialogue.
@ -343,9 +333,9 @@ unsafe fn connect_show(btn: *mut GtkWidget, wid: *mut GtkWidget)
} }
/// Gets an object from a `GtkBuilder`. /// Gets an object from a `GtkBuilder`.
unsafe fn get_obj<T>(b: *mut GtkBuilder, name: ffi::NT) -> *mut T unsafe fn get_obj<T>(b: &Refc<GtkBuilder>, name: ffi::NT) -> *mut T
{ {
let obj = gtk_builder_get_object(b, name); let obj = gtk_builder_get_object(**b, name);
obj as _ obj as _
} }
@ -388,14 +378,14 @@ fn main()
// create and run the app // create and run the app
let name = c_str!("net.greyserv.maraiah.tycho"); let name = c_str!("net.greyserv.maraiah.tycho");
let app = gtk_application_new(name, 0); let app = Refc::new(gtk_application_new(name, 0));
connect(app as _, c_str!("activate"), app_activate as _, eptr as _); connect(*app as _, c_str!("activate"), app_activate as _, eptr as _);
g_application_run(app as _, 0, ffi::null_mut()); g_application_run(*app as _, 0, ffi::null_mut());
// ok, clean up all this crap now // ok, clean up all this crap now
g_object_unref(app as _); drop(app);
assert_eq!(Rc::strong_count(&edit), 1); assert_eq!(Rc::strong_count(&edit), 1);
drop(edit); drop(edit);
@ -405,4 +395,32 @@ fn main()
} }
} }
impl<T> std::ops::Deref for Refc<'_, T>
{
type Target = *mut T;
fn deref(&self) -> &Self::Target {&self.p}
}
impl<T> Drop for Refc<'_, T>
{
fn drop(&mut self)
{
unsafe {
g_object_unref(self.p as _);
}
}
}
impl<T> Refc<'_, T>
{
fn new(p: *mut T) -> Self {Self{p, l: PhantomData}}
}
struct Refc<'a, T>
{
p: *mut T,
l: PhantomData<&'a *mut T>,
}
// EOF // EOF