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 gtk_sys::*;
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.
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();
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_win_map_view(b);
setup_win_map_tools(b);
setup_win_map_prop(b);
setup_about_dlg(b);
setup_win_main(b, app, edit.clone());
g_object_unref(b as _);
setup_draw_area(&b, edit.clone());
setup_win_map_view(&b);
setup_win_map_tools(&b);
setup_win_map_prop(&b);
setup_about_dlg(&b);
setup_win_main(&b, app, edit.clone());
}
/// 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.
struct RenderState
{
im_nomap: *mut GdkPixbuf,
ax: *mut GtkAdjustment,
ay: *mut GtkAdjustment,
im_nomap: Refc<'static, GdkPixbuf>,
ax: Refc<'static, GtkAdjustment>,
ay: Refc<'static, GtkAdjustment>,
edit: Rc<MapEditorRef>,
}
/// Callback to finalize the drawing area.
unsafe extern "C" fn c_done(_: *mut GtkWidget, rend: gpointer)
{
let rend = 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
Box::from_raw(rend as *mut RenderState);
}
/// 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 h = f64::from(gtk_widget_get_allocated_height(wid));
gtk_adjustment_set_lower(rend.ax, 0.0);
gtk_adjustment_set_upper(rend.ax, w);
gtk_adjustment_set_lower(*rend.ax, 0.0);
gtk_adjustment_set_upper(*rend.ax, w);
gtk_adjustment_set_lower(rend.ay, 0.0);
gtk_adjustment_set_upper(rend.ay, h);
gtk_adjustment_set_lower(*rend.ay, 0.0);
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);
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 _);
// get all of the necessary state and related objects
let ax: *mut GtkAdjustment = get_obj(b, c_str!("adj-map-horz"));
let ay: *mut GtkAdjustment = get_obj(b, c_str!("adj-map-vert"));
let ax = Refc::<GtkAdjustment>::new(get_obj(b, c_str!("adj-map-horz")));
let ay = Refc::<GtkAdjustment>::new(get_obj(b, c_str!("adj-map-vert")));
g_object_ref(ax as _);
g_object_ref(ay as _);
g_object_ref(*ax as _);
g_object_ref(*ay as _);
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 = 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.
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 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.
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 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.
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 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.
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
/// 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 mut v = ffi::CStringVec::new_from_iter(it).unwrap();
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_version(dlg, c_str!(env!("CARGO_PKG_VERSION")));
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(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.
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.
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();
// 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;
loop {
@ -214,7 +206,7 @@ unsafe fn setup_explicit_drop(b: *mut GtkBuilder, win: *mut GtkWindow)
}
/// 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,
edit: Rc<MapEditorRef>)
{
@ -277,14 +269,12 @@ unsafe fn setup_win_main(b: *mut GtkBuilder,
unsafe fn setup_css()
{
let path = c_str!("/net/greyserv/maraiah/tycho/css");
let css = gtk_css_provider_new();
gtk_css_provider_load_from_resource(css, path);
let css = Refc::new(gtk_css_provider_new());
gtk_css_provider_load_from_resource(*css, path);
let scr = gdk_screen_get_default();
let pri = GTK_STYLE_PROVIDER_PRIORITY_APPLICATION as u32;
gtk_style_context_add_provider_for_screen(scr, css as _, pri);
g_object_unref(css as _);
gtk_style_context_add_provider_for_screen(scr, *css as _, pri);
}
/// 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`.
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 _
}
@ -388,14 +378,14 @@ fn main()
// create and run the app
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
g_object_unref(app as _);
drop(app);
assert_eq!(Rc::strong_count(&edit), 1);
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