mod hiddenprotocol; mod noroom; use crate::{hiddenprotocol::*, noroom::*}; use gio::prelude::*; use gtk::prelude::*; use maraiah::durandal::err::*; use std::{os::raw::c_char, rc::Rc}; const DATA_NAME: *const c_char = b"tycho data\0".as_ptr() as *const c_char; fn hide_on_delete(win: >k::Window, _: &gdk::Event) -> Inhibit { win.hide(); Inhibit(true) } fn mk_draw_area(b: >k::Builder) { let area: gtk::DrawingArea = get_obj(b, "draw-area"); let ax: gtk::Adjustment = get_obj(b, "adj-map-horz"); let ay: gtk::Adjustment = get_obj(b, "adj-map-vert"); let im = CairoPixbuf(load_img("/net/greyserv/maraiah/tycho/tycho1")); area.connect_draw(move |area, cr| { let w = f64::from(area.get_allocated_width()); let h = f64::from(area.get_allocated_height()); ax.set_lower(0.0); ax.set_upper(w); ay.set_lower(0.0); ay.set_upper(h); let d = CairoDrawArea::new(cr.clone(), w, h); draw_map_none(&d, &im); Inhibit(true) }); } fn run_app(app: >k::Application) { let b = >k::Builder::new_from_resource("/net/greyserv/maraiah/tycho/ui"); let prv = gtk::CssProvider::new(); prv.load_from_resource("/net/greyserv/maraiah/tycho/css"); let scr = gdk::Screen::get_default().expect("no screen found"); let pri = gtk::STYLE_PROVIDER_PRIORITY_APPLICATION; gtk::StyleContext::add_provider_for_screen(&scr, &prv, pri); let app_ = app.downgrade(); let btn: gtk::MenuItem = get_obj(b, "btn-quit"); btn.connect_activate(move |_| { if let Some(app) = app_.upgrade() { app.quit(); } }); let btn: gtk::MenuItem = get_obj(b, "btn-about"); let win: gtk::AboutDialog = get_obj(b, "win-about"); btn.connect_activate(move |_| {win.run(); win.hide();}); let btn: gtk::MenuItem = get_obj(b, "btn-show-map-view"); let win: gtk::Window = get_obj(b, "win-map-view"); win.connect_delete_event(hide_on_delete); btn.connect_activate(move |_| win.show_all()); let btn: gtk::MenuItem = get_obj(b, "btn-show-map-tools"); let win: gtk::Window = get_obj(b, "win-map-tools"); win.connect_delete_event(hide_on_delete); btn.connect_activate(move |_| win.show_all()); let btn: gtk::MenuItem = get_obj(b, "btn-show-map-prop"); let win: gtk::Window = get_obj(b, "win-map-prop"); win.connect_delete_event(hide_on_delete); btn.connect_activate(move |_| win.show_all()); mk_draw_area(b); let win: gtk::AboutDialog = get_obj(b, "win-about"); win.set_authors(&env!("CARGO_PKG_AUTHORS").split(';').collect::>()); win.set_version(env!("CARGO_PKG_VERSION")); win.set_website(env!("CARGO_PKG_HOMEPAGE")); win.set_logo(&load_img("/net/greyserv/maraiah/tycho/tycho2")); let win: gtk::Window = get_obj(b, "win-first-start"); win.show_all(); let win: gtk::Window = get_obj(b, "win-main"); win.set_application(app); win.show_all(); } fn load_img(path: &'static str) -> gdk_pixbuf::Pixbuf { gdk_pixbuf::Pixbuf::new_from_resource(path).unwrap() } fn get_obj(b: >k::Builder, name: &str) -> T where T: glib::object::IsA { b.get_object(name).unwrap() } fn main() -> ResultS<()> { // get jacked, punk. opaque data structures are for nerds. const RESOURCE_DATA: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/resources")); // first we create the static resource header, which is really simple let mut static_resource = gio_sys::GStaticResource{data: RESOURCE_DATA.as_ptr(), data_len: RESOURCE_DATA.len(), resource: std::ptr::null_mut(), next: std::ptr::null_mut(), padding: std::ptr::null_mut()}; // init it, now we can use it throughout the entire app without copying! unsafe { gio_sys::g_static_resource_init(&mut static_resource); } let ret = { // create the application first let app = gtk::Application::new("net.greyserv.maraiah.tycho", gio::ApplicationFlags::empty())?; app.connect_activate(run_app); // then we can attach the editor state to the app's hashtable let app_ptr = app.clone().upcast::().as_ptr(); let dat = Rc::new(None::); unsafe { // this ref will be dropped after the app is run let ptr = Rc::into_raw(dat.clone()) as glib_sys::gpointer; gobject_sys::g_object_set_data(app_ptr, DATA_NAME, ptr); } // run the application and save the return let ret = if app.run(&[]) == 0 { Ok(()) } else { Err(err_msg("bad return")) }; // unref the editor state so it will go away unsafe { let ptr = gobject_sys::g_object_get_data(app_ptr, DATA_NAME); let ptr = Rc::from_raw(ptr); std::mem::drop(ptr); } // destroy the editor state first, and make sure there are no dangling // references to the application. std::mem::drop(dat); assert_eq!(app.ref_count(), 1); ret }; // finally, deinit the "static" data, and everything will be done unsafe { gio_sys::g_static_resource_fini(&mut static_resource); } ret } // EOF