From d818e579f9ce1359e4a0f4cca9db968c4b779f0b Mon Sep 17 00:00:00 2001 From: Marrub Date: Sat, 23 Mar 2019 08:33:04 -0400 Subject: [PATCH] get rid of gtk-rs high level bindings --- source/durandal/ffi.rs | 2 +- source/tycho/Cargo.toml | 24 +- source/tycho/data/ui.xml | 498 ++++++++++++++++++++------------------- source/tycho/main.rs | 401 ++++++++++++++++++------------- source/tycho/noroom.rs | 79 ++++--- 5 files changed, 554 insertions(+), 450 deletions(-) diff --git a/source/durandal/ffi.rs b/source/durandal/ffi.rs index 7140912..37ee01c 100644 --- a/source/durandal/ffi.rs +++ b/source/durandal/ffi.rs @@ -33,7 +33,7 @@ impl CStringVec /// Pushes a new `CString`. pub fn push(&mut self, st: CString) { - self.cv.insert(self.cv.len() - 1, st.as_c_str().as_ptr()); + self.cv.insert(self.cv.len() - 1, st.as_ptr()); self.sv.push(st); } diff --git a/source/tycho/Cargo.toml b/source/tycho/Cargo.toml index 3903586..7dabec6 100644 --- a/source/tycho/Cargo.toml +++ b/source/tycho/Cargo.toml @@ -10,21 +10,15 @@ build = "build.rs" [dependencies] maraiah = {path = "../.."} -# note: these have to be updated all at once, check the gtk crate for versions -atk = "0.6" -cairo-rs = "0.6" -cairo-sys-rs = "0.8" -gdk = "0.10" -gdk-pixbuf = "0.6" -gio = "0.6" -gio-sys = "0.8" -glib = "0.7" -glib-sys = "0.8" -gobject-sys = "0.8" -gtk = {version = "0.6", features = ["v3_16"]} -gtk-sys = "0.8" -pango = "0.6" -pango-sys = "0.8" +atk-sys = "0.8" +cairo-sys-rs = "0.8" +gdk-pixbuf-sys = "0.8" +gdk-sys = "0.8" +gio-sys = "0.8" +glib-sys = "0.8" +gobject-sys = "0.8" +gtk-sys = {version = "0.8", features = ["v3_16"]} +pango-sys = "0.8" [[bin]] name = "tycho" diff --git a/source/tycho/data/ui.xml b/source/tycho/data/ui.xml index 13ec04b..15be70a 100644 --- a/source/tycho/data/ui.xml +++ b/source/tycho/data/ui.xml @@ -411,7 +411,18 @@ Author: Alison Sanderson True False vertical - True + + + True + False + Vanilla + + + False + True + 0 + + Extermination @@ -424,7 +435,7 @@ Author: Alison Sanderson False True - 0 + 1 @@ -439,7 +450,7 @@ Author: Alison Sanderson False True - 1 + 2 @@ -454,7 +465,7 @@ Author: Alison Sanderson False True - 2 + 3 @@ -469,7 +480,7 @@ Author: Alison Sanderson False True - 3 + 4 @@ -484,7 +495,64 @@ Author: Alison Sanderson False True - 4 + 5 + + + + + True + False + Aleph One + + + False + True + 6 + + + + + M1 Exploration + True + True + False + The same as Exploration, but you only need to look at each marked polygon, not actually walk in them. + True + + + False + True + 7 + + + + + M1 Rescue + True + True + False + The same as Rescue, but uses the Marathon 1 class numbers. + True + + + False + True + 8 + + + + + M1 Repair + True + True + False + The same as Repair, except it only requires that the last switch (by side index) be switched to succeed. + True + + + False + True + 9 @@ -522,6 +590,18 @@ Author: Alison Sanderson True False vertical + + + True + False + Vanilla + + + False + True + 0 + + Vacuum @@ -534,7 +614,7 @@ Author: Alison Sanderson False True - 0 + 1 @@ -549,7 +629,7 @@ Author: Alison Sanderson False True - 1 + 2 @@ -564,7 +644,7 @@ Author: Alison Sanderson False True - 2 + 3 @@ -579,7 +659,124 @@ Author: Alison Sanderson False True - 3 + 4 + + + + + True + False + Aleph One + + + False + True + 5 + + + + + Marathon 1 Glue + True + True + False + Glue handles like Marathon 1. + True + + + False + True + 6 + + + + + Lava Floor + True + True + False + The floor damages you. + True + + + False + True + 7 + + + + + Rebellion (No strip) + True + True + False + The same as Rebellion, but your items and health aren't stripped. + True + + + False + True + 8 + + + + + Music + True + True + False + The map has Marathon 1-style music. + True + + + False + True + 9 + + + + + Terminals Stop Time + True + True + False + Terminals will pause the game in Solo. + True + + + False + True + 10 + + + + + M1 Monster Limits + True + True + False + Sets the monster activation limits to Marathon 1's. + True + + + False + True + 11 + + + + + M1 Weapon Differences + True + True + False + Doubles weapon pickups on Total Carnage and makes grenades low-gravity. + True + + + False + True + 12 @@ -624,12 +821,57 @@ Author: Alison Sanderson True False - vertical 5 + True True False + This field is unused and must be either 0 or 1. It used to be used to give different physics to the map editor and low gravity before it was made into an environment flag. + 0 + none + + + True + False + 0 + 0 + 0 + 0 + 12 + + + True + True + 0 + True + adj-phys-id + True + True + True + + + + + + + True + False + Physics ID + + + + + False + True + 0 + + + + + True + False + This field overrides the Landscape field, and is used for Marathon 1 maps which have music. 0 none @@ -660,242 +902,10 @@ Author: Alison Sanderson True False - Physics ID + Song ID - - False - True - 0 - - - - - True - False - 10 - - - True - False - These flags were added by Aleph One but are hidden and probably not meant to be used. - 0 - in - - - True - False - 12 - - - True - False - vertical - - - M1 Exploration - True - True - False - The same as Exploration, but you only need to look at each marked polygon, not actually walk in them. - True - - - False - True - 0 - - - - - M1 Rescue - True - True - False - The same as Rescue, but uses the Marathon 1 class numbers. - True - - - False - True - 1 - - - - - M1 Repair - True - True - False - The same as Repair, except it only requires that the last switch (by side index) be switched to succeed. - True - - - False - True - 2 - - - - - - - - - True - False - Hidden Mission Flags - - - - - True - True - 0 - - - - - True - False - These flags were added by Aleph One but are hidden and probably not meant to be used. - 0 - in - - - True - False - 12 - - - True - False - vertical - - - Marathon 1 Glue - True - True - False - Glue handles like Marathon 1. - True - - - False - True - 0 - - - - - Lava Floor - True - True - False - The floor damages you. - True - - - False - True - 1 - - - - - Rebellion (No strip) - True - True - False - The same as Rebellion, but your items and health aren't stripped. - True - - - False - True - 2 - - - - - Music - True - True - False - The map has Marathon 1-style music. - True - - - False - True - 3 - - - - - Terminals Stop Time - True - True - False - Terminals will pause the game in Solo. - True - - - False - True - 4 - - - - - M1 Monster Limits - True - True - False - Sets the monster activation limits to Marathon 1's. - True - - - False - True - 5 - - - - - M1 Weapon Differences - True - True - False - Doubles weapon pickups on Total Carnage and makes grenades low-gravity. - True - - - False - True - 6 - - - - - - - - - True - False - Hidden Environment Flags - - - - - True - True - 1 - - - False True diff --git a/source/tycho/main.rs b/source/tycho/main.rs index 5196792..75e942c 100644 --- a/source/tycho/main.rs +++ b/source/tycho/main.rs @@ -2,176 +2,259 @@ 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}; +use cairo_sys::*; +use gdk_pixbuf_sys::*; +use gdk_sys::*; +use gio_sys::*; +use glib_sys::*; +use gobject_sys::*; +use gtk_sys::*; +use maraiah::{c_str, durandal::ffi}; -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 +unsafe extern "C" fn app_activate(app: *mut GtkApplication, dat: gpointer) { - win.hide(); - Inhibit(true) + let dat = dat as *mut Option; + let dat = &mut *dat; + let _ = dat; + + setup_css(); + + let path = c_str!("/net/greyserv/maraiah/tycho/ui"); + let b = gtk_builder_new_from_resource(path); + + setup_draw_area(b); + setup_win_map_view(b); + setup_win_map_tools(b); + setup_win_map_prop(b); + setup_about_dlg(b); + setup_win_main(b, app); + + g_object_unref(b as _); } -fn mk_draw_area(b: >k::Builder) +unsafe fn setup_draw_area(b: *mut GtkBuilder) { - 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.png")); - - 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 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 b = >k::Builder::new_from_resource("/net/greyserv/maraiah/tycho/ui"); - - // TODO: signal quit instead of quitting directly to not add a ref here - 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.png")); - - 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); + struct RenderState + { + im_nomap: *mut GdkPixbuf, + ax: *mut GtkAdjustment, + ay: *mut GtkAdjustment, } - let ret = { - // create the application first - let app = gtk::Application::new("net.greyserv.maraiah.tycho", - gio::ApplicationFlags::empty())?; + unsafe extern "C" fn c_done(_: *mut GtkWidget, dat: gpointer) + { + let dat = Box::from_raw(dat as *mut RenderState); - app.connect_activate(run_app); + // unref everything + g_object_unref(dat.im_nomap as _); + g_object_unref(dat.ax as _); + g_object_unref(dat.ay as _); - // 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); + // data is dropped and freed here } - ret + unsafe extern "C" fn c_draw(wid: *mut GtkWidget, + ctx: *mut cairo_t, + dat: gpointer) + -> gboolean + { + let dat = dat as *mut RenderState; + let dat = &mut *dat; + + 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(dat.ay, 0.0); + gtk_adjustment_set_upper(dat.ay, h); + + let im = CrImage(dat.im_nomap); + let dr = CrDrawArea::new(ctx, w, h); + + draw_map_none(&dr, &im); + + 1 + } + + let wid: *mut GtkDrawingArea = get_obj(b, c_str!("draw-area")); + + let ax: *mut GtkAdjustment = get_obj(b, c_str!("adj-map-horz")); + let ay: *mut GtkAdjustment = get_obj(b, c_str!("adj-map-vert")); + + g_object_ref(ax as _); + g_object_ref(ay as _); + + 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)); + + connect(wid as _, c_str!("destroy"), c_done as _, dat as _); + connect(wid as _, c_str!("draw"), c_draw as _, dat as _); +} + +unsafe fn setup_win_map_view(b: *mut 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")); + + connect_hide(win as _); + connect_show(btn as _, win as _); +} + +unsafe fn setup_win_map_tools(b: *mut 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")); + + connect_hide(win as _); + connect_show(btn as _, win as _); +} + +unsafe fn setup_win_map_prop(b: *mut 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")); + + connect_hide(win as _); + connect_show(btn as _, win as _); +} + +unsafe fn setup_about_dlg(b: *mut GtkBuilder) +{ + unsafe extern "C" fn c_show(_: *mut GtkWidget, dlg: gpointer) + { + gtk_dialog_run(dlg as _); + gtk_widget_hide(dlg as _); + } + + let dlg: *mut GtkAboutDialog = get_obj(b, c_str!("win-about")); + let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-about")); + + 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")); + + 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); + + connect_hide(dlg as _); + connect(btn as _, c_str!("activate"), c_show as _, dlg as _); + + g_object_unref(img as _); +} + +unsafe fn setup_win_main(b: *mut GtkBuilder, app: *mut GtkApplication) +{ + unsafe extern "C" fn c_quit(_: *mut GtkWidget, win: gpointer) + { + gtk_window_close(win as _); + } + + let win: *mut GtkWindow = get_obj(b, c_str!("win-main")); + let btn: *mut GtkMenuItem = get_obj(b, c_str!("btn-quit")); + + gtk_window_set_application(win, app); + gtk_widget_show_all(win as _); + + connect(btn as _, c_str!("activate"), c_quit as _, win as _); +} + +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 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 _); +} + +unsafe fn connect_hide(wid: *mut GtkWidget) +{ + unsafe extern "C" fn c_hide(wid: *mut GtkWidget, + _: *mut GdkEvent, + _: gpointer) + { + gtk_widget_hide(wid); + } + + connect(wid as _, c_str!("delete-event"), c_hide as _, ffi::null_mut()); +} + +unsafe fn connect_show(btn: *mut GtkWidget, wid: *mut GtkWidget) +{ + unsafe extern "C" fn c_show(_: *mut GtkWidget, wid: gpointer) + { + gtk_widget_show_all(wid as _); + } + + connect(btn as _, c_str!("activate"), c_show as _, wid as _); +} + +/// Gets an object from a `GtkBuilder`. +unsafe fn get_obj(b: *mut GtkBuilder, name: ffi::NT) -> *mut T +{ + let obj = gtk_builder_get_object(b, name); + obj as _ +} + +/// Connects a signal handler. +unsafe fn connect(obj: *mut GObject, name: ffi::NT, cb: gpointer, d: gpointer) +{ + let cb = std::mem::transmute(cb); + g_signal_connect_data(obj, name, cb, d, None, 0); +} + +unsafe fn load_img(path: ffi::NT) -> *mut GdkPixbuf +{ + gdk_pixbuf_new_from_resource(path, ffi::null_mut()) +} + +/// Entry point. +fn main() +{ + unsafe { + // 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 resource = GStaticResource{data: RESOURCE_DATA.as_ptr(), + data_len: RESOURCE_DATA.len(), + resource: ffi::null_mut(), + next: ffi::null_mut(), + padding: ffi::null_mut()}; + + // init it, now we can use it throughout the entire app without copying! + g_static_resource_init(&mut resource); + + // create a container for the editor state + let dat = Box::into_raw(Box::new(None::)); + + // create and run the app + let name = c_str!("net.greyserv.maraiah.tycho"); + let app = gtk_application_new(name, 0); + + connect(app as _, c_str!("activate"), app_activate as _, dat 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)); + + // deinit the "static" data, and everything will be done + g_static_resource_fini(&mut resource); + } } // EOF diff --git a/source/tycho/noroom.rs b/source/tycho/noroom.rs index a2390d5..83bc00c 100644 --- a/source/tycho/noroom.rs +++ b/source/tycho/noroom.rs @@ -1,4 +1,7 @@ -use maraiah::{durandal::image::*, rozinante::draw::*}; +use cairo_sys::*; +use gdk_pixbuf_sys::*; +use gdk_sys::*; +use maraiah::{c_str, durandal::{ffi::*, image::*}, rozinante::draw::*}; fn flt_color(cr: impl Color) -> (f64, f64, f64) { @@ -7,75 +10,89 @@ fn flt_color(cr: impl Color) -> (f64, f64, f64) (flt_color(cr.r()), flt_color(cr.g()), flt_color(cr.b())) } -impl CacheImage for CairoPixbuf +impl CacheImage for CrImage { - fn w(&self) -> Coord {self.0.get_width() as Coord} - fn h(&self) -> Coord {self.0.get_height() as Coord} + fn w(&self) -> Coord {unsafe {gdk_pixbuf_get_width(self.0) as Coord}} + fn h(&self) -> Coord {unsafe {gdk_pixbuf_get_height(self.0) as Coord}} } -impl CairoDrawArea +impl CrDrawArea { - pub const fn new(ctx: cairo::Context, w: f64, h: f64) -> Self + pub const fn new(ctx: *mut cairo_t, w: f64, h: f64) -> Self { - CairoDrawArea{ctx, w: w as Coord, h: h as Coord} + CrDrawArea{ctx, w: w as Coord, h: h as Coord} } } -impl DrawArea for CairoDrawArea +impl DrawArea for CrDrawArea { - type NativeImage = CairoPixbuf; + type NativeImage = CrImage; fn w(&self) -> Coord {self.w} fn h(&self) -> Coord {self.h} fn clear(&self, cr: impl Color) { - use cairo::{FontSlant, FontWeight}; - self.rect(Rect{x: 0, y: 0, w: self.w(), h: self.h()}, cr); - self.ctx - .select_font_face("Sans", FontSlant::Normal, FontWeight::Normal); - self.ctx.set_font_size(14.0); + let sl = FONT_SLANT_NORMAL; + let wt = FONT_WEIGHT_NORMAL; + + unsafe { + cairo_select_font_face(self.ctx, c_str!("Monospace"), sl, wt); + cairo_set_font_size(self.ctx, 14.0); + } } fn rect(&self, rect: Rect, cr: impl Color) { - let x1 = f64::from(rect.x); - let y1 = f64::from(rect.y); - let x2 = f64::from(rect.w) + x1; - let y2 = f64::from(rect.h) + y1; + let px = f64::from(rect.x); + let py = f64::from(rect.y); + let sx = f64::from(rect.w); + let sy = f64::from(rect.h); let (r, g, b) = flt_color(cr); - self.ctx.set_source_rgb(r, g, b); - self.ctx.rectangle(x1, y1, x2, y2); - self.ctx.fill(); + unsafe { + cairo_set_source_rgb(self.ctx, r, g, b); + cairo_rectangle(self.ctx, px, py, sx, sy); + cairo_fill(self.ctx); + } } fn text(&self, pos: Point, text: &str, cr: impl Color) { let (r, g, b) = flt_color(cr); - self.ctx.set_source_rgb(r, g, b); - self.ctx.move_to(f64::from(pos.0), f64::from(pos.1)); - self.ctx.show_text(text); + let x = f64::from(pos.0); + let y = f64::from(pos.1); + + let text = CString::new(text).unwrap(); + + unsafe { + cairo_set_source_rgb(self.ctx, r, g, b); + cairo_move_to(self.ctx, x, y); + cairo_show_text(self.ctx, text.as_ptr()); + } } fn image(&self, pos: Point, im: &Self::NativeImage) { - use gdk::prelude::*; - self.ctx - .set_source_pixbuf(&im.0, f64::from(pos.0), f64::from(pos.1)); - self.ctx.paint(); + let x = f64::from(pos.0); + let y = f64::from(pos.1); + + unsafe { + gdk_cairo_set_source_pixbuf(self.ctx, im.0, x, y); + cairo_paint(self.ctx); + } } } -pub struct CairoPixbuf(pub gdk_pixbuf::Pixbuf); +pub struct CrImage(pub *const GdkPixbuf); -pub struct CairoDrawArea +pub struct CrDrawArea { - ctx: cairo::Context, + ctx: *mut cairo_t, w: Coord, h: Coord, }