Giter Site home page Giter Site logo

gtk-rs / gtk-rs-core Goto Github PK

View Code? Open in Web Editor NEW
272.0 14.0 105.0 695.8 MB

Rust bindings for GNOME libraries

Home Page: https://gtk-rs.org/gtk-rs-core

License: MIT License

Dockerfile 0.03% Rust 97.50% C 2.47%
gtk-rs cairo gdk-pixbuf gio glib pango pangocairo graphene

gtk-rs-core's Introduction

gtk-rs-core CI

The gtk-rs organization aims to provide safe Rust binding over GObject-based libraries. You can find more about it on https://gtk-rs.org.

This repository contains all the "core" crates of the gtk-rs organization. For more information about each crate, please refer to their README.md file in their directory.

Minimum supported Rust version

Currently, the minimum supported Rust version is 1.70.0.

Documentation

Ecosystem

The gtk-rs-core repository contains Rust crates for the foundational GObject-based libraries. However there is a large ecosystem of GObject libraries and many of these libraries have Rust bindings based on the tooling included in gtk-rs. Of particular note:

Additionally, Rust bindings for various libraries are hosted on GNOME's GitLab instance and can be found at https://gitlab.gnome.org/World/Rust.

When using crates that are not part of the gtk-rs repository, you will need to be careful and ensure that they do not pull in incompatible versions of core crates like glib-rs.

Regenerating

To regenerate crates using gir, please use the generator.py file as follows:

$ python3 generator.py

If you didn't do so yet, please check out all the submodules before via

$ git submodule update --checkout

Development

This repository is mostly split into two branches: master and crate. master contains the not yet released code and is where new developments are happening. crate contains the last release source code and isn't supposed to be updated.

This repository is structured as follows:

- crate/
   |
   |-- README.md
   |-- Gir.toml
   |-- Cargo.toml
   |-- src/
   |-- sys/

The crate is a "top" directory (so "atk" or "gdk" in here for example). Each crate contains:

  • README.md: explanations about the crate itself and eventually some details.
  • Cargo.toml: descriptor of the crate, used by cargo and Rust.
  • Gir.toml: configuration used by gir to generate most of the crates' code.
  • src: the source code of the crate.
  • sys: the 1:1 bindings of the C API.

The gir and gir-files top folders are not crates, but are git submodules which respectively contain the gir tool and the gir files used by the generator.

When running generator.py the tool will automatically update these git submodules and run the gir tool on the gir files to regenerate the code.

During development, it is useful to execute the generator with a different version of the gir tool or of the gir files, for instance to test if the code generation is successful before submitting a pull request to update one of the submodules. This can be done by specifying arguments to the generator script, for instance, to run the generator on a local copy of the gir files:

$ python3 generator.py --gir-files-directory ../gir-files/

See python3 generator.py --help for more details.

gtk-rs-core's People

Contributors

antoyo avatar bilelmoussaoui avatar bpbp-boop avatar brainblasted avatar buster avatar dependabot[bot] avatar epashkin avatar federicomenaquintero avatar fengalin avatar gkoz avatar gsingh93 avatar guillaumegomez avatar hofer-julian avatar ids1024 avatar jeremyletang avatar jf2048 avatar kinnison avatar marijns95 avatar mathijshenquet avatar oakes avatar osa1 avatar pbor avatar philn avatar ranfdev avatar sdroege avatar sfanxiang avatar simonsapin avatar sophie-h avatar susurrus avatar tmiasko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

gtk-rs-core's Issues

Eq / Hash / etc. for glib::object::WeakRef

Would it be a bad idea for weak references to derive Eq / Hash / PartialEq / etc.as the GTK widgets do? Currently in a situation where it would be ideal if I could store a collection of weak references in a HashSet.

Add convenience futures API

Compared to async-std/tokio it's rather verbose and inconvenient to use. Something like the following, inspired by the beforementioned APIs and how gio works. We would then step by step extend this for other types and with more functions.

pub struct SocketClient(gio::SocketClient);

impl SocketClient {
    pub fn new() -> Self {
        SocketClient(gio::SocketClient::new())
    }

    pub async fn connect<P: IsA<gio::SocketConnectable> + Clone + 'static>(
        &self,
        connectable: &P,
    ) -> Result<SocketConnection, glib::Error> {
        let connection = self.0.connect_async_future(connectable).await?;

        // Get the input/output streams and convert them to the AsyncRead and AsyncWrite adapters
        let ostream = connection
            .get_output_stream()
            .unwrap()
            .dynamic_cast::<gio::PollableOutputStream>()
            .unwrap();
        let write = ostream.into_async_write().unwrap();

        let istream = connection
            .get_input_stream()
            .unwrap()
            .dynamic_cast::<gio::PollableInputStream>()
            .unwrap();
        let read = istream.into_async_read().unwrap();

        Ok(SocketConnection {
            connection,
            read,
            write,
        })
    }
}

pub struct SocketConnection {
    connection: gio::SocketConnection,
    read: gio::InputStreamAsyncRead<gio::PollableInputStream>,
    write: gio::OutputStreamAsyncWrite<gio::PollableOutputStream>,
}

// Proxy to the internal AsyncRead
impl AsyncRead for SocketConnection {
    fn poll_read(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<Result<usize, io::Error>> {
        Pin::new(&mut Pin::get_mut(self).read).poll_read(cx, buf)
    }
}

// Proxy to the internal AsyncWrite
impl AsyncWrite for SocketConnection {
    fn poll_write(
        self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize, io::Error>> {
        Pin::new(&mut Pin::get_mut(self).write).poll_write(cx, buf)
    }

    fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
        Pin::new(&mut Pin::get_mut(self).write).poll_close(cx)
    }

    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
        Pin::new(&mut Pin::get_mut(self).write).poll_flush(cx)
    }
}

pub struct SocketListener(gio::SocketListener);

impl SocketListener {
    pub fn new() -> Self {
        SocketListener(gio::SocketListener::new())
    }

    pub fn add_inet_port(&self, port: u16) -> Result<(), glib::Error> {
        self.0.add_inet_port(port, None::<&glib::Object>)
    }

    pub async fn accept(&self) -> Result<SocketConnection, glib::Error> {
        let connection = self.0.accept_async_future().await?.0;

        // Get the input/output streams and convert them to the AsyncRead and AsyncWrite adapters
        let ostream = connection
            .get_output_stream()
            .unwrap()
            .dynamic_cast::<gio::PollableOutputStream>()
            .unwrap();
        let write = ostream.into_async_write().unwrap();

        let istream = connection
            .get_input_stream()
            .unwrap()
            .dynamic_cast::<gio::PollableInputStream>()
            .unwrap();
        let read = istream.into_async_read().unwrap();

        Ok(SocketConnection {
            connection,
            read,
            write,
        })
    }

    pub fn incoming(&self) -> Incoming {
        Incoming(self)
    }
}

pub struct Incoming<'a>(&'a SocketListener);

impl<'a> Stream for Incoming<'a> {
    type Item = Result<SocketConnection, glib::Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        let future = self.0.accept();
        pin_utils::pin_mut!(future);

        let socket = futures::ready!(future.poll(cx))?;
        Poll::Ready(Some(Ok(socket)))
    }
}

Opinions? CC @russel @GuillaumeGomez @EPashkin

Deriving Clone on ObjectSubclass is unsound

It would create a clone of just the instance private struct. Calling ObjectSubclass::get_instance() on it would then get a reference to some random memory.

This needs to be prevented somehow. Maybe via a cleverly placed assert_not_impl_all in the glib_object_subclass! macro.

Reduce usage of BoolError for manual code

We have quite some manual code where we currently use BoolError although there are multiple, proper error cases. For example ObjectExt::set_property() or all the signals related functions.

I would suggest to replace these all with proper error types.

@GuillaumeGomez @EPashkin opinions?

Add clear_cache binding for fontconfig

I am working on this https://gitlab.gnome.org/GNOME/librsvg/issues/536, but getting stuck on the fontconfig cache not clearing. Hopeing someone here can give me some pointers.

I figured out that I could run pangocairo::FontMapExt::set_resolution(&font_map, 96.0) to force a call to flush the cache, but it requires a pangocairo::FontMap and I'm not sure how to cast my pango::FontMap to get that working. Is this even possible with Rust? Pango casts back to PangoFontMap* in the set_resolution function before calling pango_fc_font_map_cache_clear.

Since it is a pango call would it make sense to add a clear_cache function to FontMap here? All I'm seeing at the moment is the load_fontset member for pango::FontMap.

gio::Application::get_default() is unsound

It allows retrieving the application from any thread, not just the main thread (or more general the thread where the application was created). gio::Application is not thread-safe, so this is a problem.

GEnum is a bit strange

I find the GEnum a bit strange. For reference:

#[derive(Debug, Eq, PartialEq, Clone, Copy, glib::GEnum)]
#[repr(u32)]
#[genum(type_name = "SimpleObjectAnimal")]
enum Animal {
    Goat = 0,
    #[genum(name = "The Dog")]
    Dog = 1,
    #[genum(name = "The Cat", nick = "chat")]
    Cat = 2,
}

Why not having a gvariant for variants instead? It got me quite confused at first. Also, what's the point of the derive if we need to add #[genum(type_name = "SimpleObjectAnimal")]?

Consider better glib::wrapper! API

This isn't terrible, but I don't like the way it ends up being a DSL that isn't quite Rust (@extends?), and that it looks like a definition for a struct with a single member of type ObjectSubclass<T>, but that's simply not the case:

glib::wrapper! {
    pub struct SimpleObject(ObjectSubclass<imp::SimpleObject>)
   @extends gtk::Button, gtk::Widget;
}

Here's an idea I had for a different API, using proc macros:

#[glib::wrapper]
#[glib::extends(GtkButton, gtk::Widget)]
struct SimpleObject(glib::ObjectSubclassRef<imp::SimpleObject>);

This way the contents of the struct in the expanded macro would actually match what is specified here. (Though I'm not sure if there's a good way for the macro to test if a particular type name/path refers to glib::ObjectSubclassRef). The macro could still match based on the name of the generic "type" the defined struct contains, but here it would be an actual type that the struct actually contains. glib::ObjectSubclassRef<T> could deref to T, providing a shorter alternative to from_instance.

I think something like this would be better. If not perfect. Still requires design for everything other than sub-classing, but I though I might as well share the idea.

`GlyphItemIter` intialization

Hey 👋

I'm having some trouble using the GlyphItemIter interface. I can't figure out how to instantiate it.

The Pango interface suggests passing an uninitialized variable to pango_glyph_item_iter_init_start, but I'm not sure how to achieve this in Rust.

I tried making a fix by adding the following method to the GlyphItemIter impl block:

    pub fn new_start() -> GlyphItemIter {
        unsafe { GlyphItemIter(Boxed::uninitialized()) }
    }

but I get a panick with the message not yet implemented at runtime.

Any ideas what I might be missing?

Constructing immutable Object

It doesn't seem possible to create an Object subclass that is immutable, i.e. doesn't have setters.

glib::Object::new insists on allocating a default object and using setters to initialize.

I would like to start with already-initialized data, "wrap" it to be an Object, and implement only getters on it, so that I don't need to support interior mutability or default/empty object state.

BoxedType seems close in terms of using an existing Rust object, but I don't know if it can have properties: gtk-rs/glib#629

FromGlibPtr* extension for borrowing

It would be good if FromGlibPtr* could get some variant that can be used for borrowing, mutably and immutably.

Rationale for this is

  1. For types like strings, boxed types that copy, GValue, the current implementation would always create a copy, which is of course not very efficient if you just want to look at the value. In many of these cases, copying is not actually needed
  2. For the same types, if we always copy it's impossible to actually write to the values. There are various cases where a value is returned (or passed to a function as argument), and it should be possible to write to the value to mutate it. Examples are gst_caps_get_structure(), or GObject::set_property() for example, and the [Value] in @antoyo 's pull request here gtk-rs/glib#173

Question now is
a) Should this get their own traits? Should FromGlibPtrNone be extended by a lifetime parameter and/or new functions?
b) How do we teach the code generator to do that, instead of making the copy? I guess another configuration ("borrow" / "borrow_mut" or so) for this effect? Should it maybe do "borrow" (not mut) by default for return values / out parameters that are "transfer none"?

IMHO this should get a FromGlibPtrBorrow trait (which exists already, but how is that actually used? can someone show me some code using it?) and a FromGlibPtrBorrowMut trait.

@EPashkin @GuillaumeGomez Any comments, ideas?

Figure out and document the thread-safety story

In cairo

Many objects in cairo are manipulated through pointer types like cairo_surface_t * and are reference-counted, with functions like cairo_surface_reference and cairo_surface_destroy. (Despite what the name suggests, the later does not free the object unless the refcount reaches zero.)

Unfortunately I couldn’t find any documentation about what is considered correct use of these objects or not, in a multi-threaded application.

I think we can conservatively assume that cairo should be thread-safe when any object created through the public API is only manipulated on the same thread it was created on. Some commit messages and entries in the NEWS file mention for example adding a mutex around the global font cache.

However it is not clear to me what objects can be shared across threads under what conditions, if at all. The NEWS file includes “Making reference counting thread safe” which I assume is similar to using Rust’s Arc instead of Rc, which would be relevant when objects are shared.

In cairo-rs, status quo

Cairo objects are exposed in the Rust API as wrapper structs that implement Clone and Drop by incrementing and decrementing the reference count.

As of cairo-rs 0.6.0 (since PR gtk-rs/cairo#233) most methods take a shared &self rather than exclusive &mut self. This reflects the fact even with exclusive (&mut) access to a reference (copy of the pointer) to an object, there can be other references/pointers to the same object so access is effectively shared.

These structs wrapper are !Sync and !Send as a side-effect of containing a *mut raw pointer. I think it would be good to have explicit negative impls, to show intent to someone reading the code and to have rustc error messages mention e.g. cairo::Surface instead of *mut cairo_sys::cairo_surface_t. But negative impls are not stable yet: rust-lang/rust#13231.

All of the above is not obvious, as shown by gtk-rs/cairo#192. It would be good to have high-level documentation that explains it. (By the way, I’ve found https://github.com/gtk-rs/lgpl-docs but it’s not clear how it relates to this repo. Does the release script use whatever is the latest docs commit at the time? Are new docs written for Rust bindings also under LGPL?)

More flexibility in cairo-rs?

There’s desire to do more with threads: gtk-rs/cairo#175, gtk-rs/cairo#226. If we can get answers on what is considered correct use of cairo’s C API or not (and ideally have them documented upstream), maybe we can relax these !Send and !Sync negative impls to some extent?

Or, one might imagine a Send wrapper that checks if the reference count is 1. However some object might internally own references to other objects, and the latter could end up being incorrectly shared across threads. For example, the existence of cairo_get_target shows that a cairo_t context owns a reference to a cairo_surface_t.

Boxed arrays ToGlibContainerFromSlice don't support GList and GSList

Boxed types has build-in implementation for ToGlibContainerFromSlice<'a, *const/*mut*/ *const $ffi_name>,
and standard implementation ToGlibContainerFromSlice<'a, *mut glib_sys::GSList> for &'a T don't works with boxed types too because they not define ToGlibPtr<'a, *mut $ffi_name> and define only ToGlibPtrMut<'a, *mut $ffi_name> instead.
Found on pub fn gtk_source_file_loader_set_candidate_encodings(loader: *mut GtkSourceFileLoader, candidate_encodings: *mut glib::GSList);

cc @GuillaumeGomez, @sdroege

Define naming convention for type variants construction

Define and apply an organization-wide general naming convention for builders of the variants of a type, so that the building function doesn't conflict with a getter. E.g. (existing:)

  • pango::Attribute::overline.
  • glib::ParamSpec::flags (conflicts with get_flags to be renamed as flags to follow Rust getter naming style).

Discussion started here: gtk-rs/gtk3-rs#212 (review)

Provide a builder pattern to create actions

Similar to the builder pattern we have for creating signals, it would be nice to have something similar for gio::SimpleAction. We should probably do that as part of a new trait, the same way we can register signals as part of ObjectImpl trait.

This might be useful later for gtk-rs/gtk3-rs#240

Implement Downcast trait for Option<T>

A lot of the time I do something like this:

widget.get_child().unwrap().downcast::<SomeWidget>().unwrap();

This gets to be really tedious and ugly. I propose gtk-rs should add a function equivalent to the above, something like:

widget.get_child_as::<SomeWidget>();

glib::Date API is unsound and/or asserts

For example

  • All the constructors assert if invalid arguments are provided
  • Add/subtract asserts if overflows happen
  • Various functions assert if an invalid date is passed in (as can be constructed by setting e.g. to February 31`)
  • clear() overwrites memory with zeroes without any checks that the memory is actually accessible

i18n

This guide indicates the procedure to initialize the text domain for translations, however I can't find the functions setlocale, bindtextdomain & textdomain in gtk-rs/glib even though the dgettext variants are available. As a matter of fact, I couldn't find them in glib-sys neither, so I used gettext-rs as a workaround, which does the job.

Is this the way to go or am I missing something?

Prevent all the copies in FFI translation by having Rust types for GLib arrays, strings, hash table, lists, etc

See above. Those could implement all kinds of conversions to the actual Rust types, e.g. via Iterator::collect() for arrays, but use the GLib allocator for memory management.

These could be used for the "transfer full" return values (and out parameters) everywhere at least.

For "transfer none" we could at least automatically support 'static references. Non-static borrowing requires a lot of knowledge of the API and is better implemented manually.

How to get ownership of data back from ImageSurface

Summary

You can quickly create an ImageSurface from some byte array using ImageSurface::create_for_data. However, I don't see a way to get ownership of that byte array back from the ImageSurface without performing a copy. I would like to figure out a way to avoid copying my image data.

More context

I am working on an application that uses a background thread to render an image and uses double buffering to quickly update the main display. My approach is inspired by this tutorial, but updated for compatibility with GTK+ 3 and obviously using the Rust APIs (and ideally just safe Rust). I am using a Vec<u8> as a pixel map which I can pass between threads, and from it construct an ImageSurface using ImageSurface::create_for_data. The problem is, after drawing on the ImageSurface, I'd like to be able to take back ownership of my pixel map without cloning the data into a new Vec from the ImageSurfaceData returned by ImageSurface::get_data. Right now, it seems my options are to either to clone the data or drop into unsafe.

Possible approaches

I see from the code that the byte array is stored as user data on the created surface. However, this user data key is not accessible publicly. If it were, one could presumably get the Rc handle from the user data, drop the ImageSurface and use Rc::try_unwrap and Box::downcast to recover the byte array. That's kind of gross though. An idea that's only slightly better at best would be to return the Rc<Box<dyn AsMut<u8>>> from create_for_data along with the ImageSurface, which at least doesn't expose the user data key.

Probably the cleanest API I can think of would be a new generic struct like ImageSurfaceWithData<D: AsMut<u8>> which is Deref<Target = ImageSurface>. But that starts to deviate even more from the C API. That's basically the API that I will likely implement myself with unsafe if there is no upstream solution.

Another idea would be to add a method ImageSurface::finish_output_data(&self) -> Result<Box<dyn AsMut<u8>>, Error> which mirrors the functionality of Surface::finish_output_stream. That seems like the most consistent option, if not the safest.

Any thoughts on if there already exists an approach that I missed or whether this is worth addressing?

Add derive macro for structs representing GObject properties

Kind of related to https://github.com/gtk-rs/glib/issues/637 and I would do them together in a few days.

I'll write out the whole plan here once I'm at a computer again, but the basic idea would be a derive macro and corresponding infrastructure that

  • registers a GObject property per struct field, incl default, min, max values etc
  • provides a set/get property function that directly does the translation
  • provides a notify function for notifying changes

The struct itself would then be stored inside the instance data in a refcell or mutex.

This should allow to bring down the boilerplate for GObject subclasses with properties considerably.

AsyncRead + AsyncWrite for IOStream?

Would it be possible to implement futures::io::AsyncRead and AsyncWrite for gio::IOStream like e.g. async_std::net::TcpStream does it?

In short I would like to create a rust crate that is generic over AsyncRead + AsyncWrite for general use. I would then like to create glib bindings for said library and use a MainContext as a future executor. It would be great if I could let the user construct streams on the C side.

I don't know if this is a feasible approach though.

https://docs.rs/futures/0.2.1/futures/io/trait.AsyncWrite.html
https://docs.rs/async-std/0.99.10/async_std/net/struct.TcpStream.html

Provide a proc macro to register actions

One very cool things about GTK is the usage of GAction. You can either easily add an action to a widget that implements the necessary interfaces to be an GActionGroup (gio::ActionMap & gio::ActionGroup) or you have to add a SimpleActionGroup to your widget yourself. While the creation part of the actions is very verbose already with all the casting from GAction to GSimpleAction, it's currently not easy nor nice to write.

I have written in the past few macros that did nothing but wrap the procedure of creating an action, adding to the action group along with all the casting stuff and it looks currently more or less like this

fn setup_gactions(&self) {
        // Quit
        action!(
            self,
            "quit",
            clone!(@weak self as app => move |_, _| {
                app.quit();
            })
        );

        // About
        action!(
            self,
            "about",
            clone!(@weak self as app => move |_, _| app.display_about_dialog())
        );

        let win = self.get_main_window();
        action!(
            win,
            "fullscreen",
            clone!(@weak self as app => move |_, _| {
                app.get_main_window().toggle_fullscreen();
            })
        );
    }

Note that more complex apps can have a ton of actions, so having to define them "twice" is not great.

I suggest we provide a proc macro based on the future work in gtk-rs/gtk3-rs#128 to automatically create an action and use the annotated function as the activate callback.

So that the example above would look more or less like this

#[gaction(name="quit")]
fn on_quit(&self, action: gio::SimpleAction, target: Option<glib::Value>) {
    self.quit();
}
#[gaction]
fn about(&self, action: gio::SimpleAction, target: Option<glib::Value>) {
    let dialog = gtk::AboutDialog::new();
    ...
    dialog.show();
}

#[gaction]
fn fullscreen(&self, action: gio::SimpleAction, target: Option<glib::Value>) {
    self. app.get_main_window().toggle_fullscreen();
}

This will require having some kind of register_actions methods to call later on to register all those actions in a specific action group (or something else? not sure how that could work)

Enforce in glib_wrapper! that the subclass actually implements the required traits for super classes / interfaces

When using the glib_wrapper! macro for subclasses there is currently no compile-time check for the interfaces/classes that are listed. At runtime it would nonetheless panic in (I hope) all cases when misusing it, but a compile-time check would be possible here and useful.

We'd need something to map from the type name to the corresponding impl trait, i.e. some other trait with an associated type. And then use the static_assertions crate, for example.

@ids1024 What do you think?

Create tests for glib/src/translate.rs

It would be good to have tests for the different translations from/to C in translate.rs, especially the container and pointer translations.

This would be a good newcomer task. I'd start by writing tests for String <-> gchar*, then GList (containing strings) by creating one in unsafe code via the C API and checking if the translations give proper results in either direction.

Creating fonts from backends

I'm not sure if I'm just looking in the wrong place, but I can't find support for using font backends other than the "toy" backend that comes with cairo. The documentation says:

Font faces are created using font-backend-specific constructors, typically of the form Context::backend_font_face_create()

and

For "real" font selection, see the font-backend-specific font_face_create functions for the font backend you are using. (For example, if you are using the freetype-based cairo-ft font backend, see Font::create_for_ft_face() or Font::create_for_pattern().) The resulting font face could then be used with Context::scaled_font_create() and Context::set_scaled_font().

But I can't find any of these functions. Are there other crates that I'm just missing, perhaps? The C functions for creating font faces from any of the backends also aren't in cairo::ffi or cairo-sys.

Documentation for the C API is here.

ToGlibPtrMove trait and "move" function parameter configuration

It would be good to have a ToGlibPtrMove, that consumes the Rust wrapper struct and just returns the C pointer. Without any copying or change of reference count (if possible: e.g. for strings it is not).

In addition to that, a function parameter configuration to declare that parameter as "move" (i.e. using ↑, taking the Rust wrapper per value instead of as a reference) would be useful.

Add Value trait impls for ValueArray

Mean problem here is that it allows circumventing the exclusivity of &mut references as it is actually reference counted in GValues. Needs some thinking!

Not catching panics across FFI boundaries

gtk-rs/cairo#257 added bindings for “user data” owned by cairo objects. Each user data entry has a destructor function pointer that cairo calls when the object is destroyed. This helps solve life time issues, since with reference counting it can be hard to predict when an object will be destroyed exactly.

The bindings are generic and accept user data of any type. They forward destructor function pointer calls to Drop, which potentially panic and unwind. However, until rust-lang/rust#58794 is resolved, unwinding into C is undefined behavior.

A possible fix is using std::panic::catch_unwind in the destructor function. However even if we stash the panic payload somewhere at that point, there is no good place in the code to call resume_unwind. So the best we can do might be to abort the process.

add FreeType fonts support

Currently, cairo lacks those functions

  • cairo_ft_font_face_create_for_ft_face ()
  • cairo_ft_font_face_create_for_pattern ()
  • cairo_ft_font_options_substitute ()
  • cairo_ft_scaled_font_lock_face ()
  • cairo_ft_scaled_font_unlock_face ()
  • cairo_ft_font_face_get_synthesize ()
  • cairo_ft_font_face_set_synthesize ()
  • cairo_ft_font_face_unset_synthesize ()

Documentation: https://www.cairographics.org/manual/cairo-FreeType-Fonts.html

Those allow using an external font with Cairo. There's also Win32 fonts & other missing stuff, see https://www.cairographics.org/manual/cairo-fonts.html.

Need to improve documentation around glib wrapper types

Or more generally, "How gtk memory management works."

The most relevant write up as of now is: glib_wrapper! docs

The most important parts that are missing:

  1. What are the semantics of Boxed, Shared and Object wrappers
    • Which are the traits implemented by each wrapper.
  2. How is "inheritance" implemented using glib_wrapper!
    • Is it possible to derive a widget such as DrawingArea so as to add custom fields which can be accessed during event callbacks.
  3. Motivation behind creating *GlibPtr* traits, and their behavior.
  4. Details about thread-safety.

Add OpenGLSurface support

It seems there is currently no possibility to use the cairo-opengl backend (cairo-gl-surface-backend) via cairo-rs.

  • Is there a fundamental technical reason why it is difficult or not reasonable to implement support for OpenGL surfaces in cairo-rs?
  • If possible, what would be the steps needed to achieve this?

I have a strong requirement to render SVGs in a high-performance fashion (above 60 fps) for further processing in an OpenGL environment, so using the cairo OpenGL backend is the obvious choice. Since I want to load existing SVG files and not only draw programmatically, I plan to use librsvg or resvg (probably the latter) to achieve this. Both libraries make use of cairo-rs, so support here would be a prerequisite to achieve my goals. I would consider to invest some time to contribute this myself, but would need some guidance by more experienced devs involved in this project.

Use a different type to indicate Pango Units

After looking at the gir file, an automated way to generate this seems not possible. So, I would like to suggest two possible alternatives:

  • Don't use gir! (How often does gir specs change?)
  • Create a Pango-1.0.gir.patch file which would add special attributes to Pango-1.0.gir to handle cases like this and gtk-rs/pango#62. This will also involve adding pango-specific code-generation rules to gir.

Update: Below is an example implementation of pango units which would make working with them a lot more convinient and less error prone:

#[macro_use]
extern crate derive_more;

#[derive(Add, Sub, Mul, Div,
         AddAssign, SubAssign, MulAssign, DivAssign)]
struct Units(pub i32);

impl From<f64> for Units {
    fn from(val: f64) -> Units {
        Units((val * pango::SCALE as f64).round() as i32)
        // or use ffi::pango_units_from_double
    }
}

impl From<Units> for f64 {
    fn from(val: Units) -> f64 {
        val.0 as f64 / pango::SCALE as f64
        // or use ffi::pango_units_to_double
    }
}

Bindings for GVariantBuilder

We'll have a way to create and convert to/from Variants after gtk-rs/glib#651 is merged. However, since Variant is supposed to be non-mutable, bindings for GVariantBuilder will be very useful to have.

IsA<_> can't be used for trait objects

Reason for this is that the associated types of all super-traits have to be specified, i.e. GlibType of Wrapper, Storage of ToGlibPtr. By specifying those, using trait objects becomes useless as you already specified one specific type.

We should try to solve this, either by making those associated types generic types in one way or another, or otherwise untangling the traits. Not being able to use IsA<_> as a trait object is a big problem :)

Example compiler error when trying to use it as trait object:

error[E0191]: the value of the associated type `GlibType` (from the trait `glib::wrapper::Wrapper`) must be specified
  --> src/bin.rs:24:37
   |
24 |     fn add_many(&self, elements: &[&IsA<Element>]) -> Result<(), glib::BoolError> {
   |                                     ^^^^^^^^^^^^ missing associated type `GlibType` value

error[E0191]: the value of the associated type `Storage` (from the trait `glib::translate::ToGlibPtr`) must be specified
  --> src/bin.rs:24:37
   |
24 |     fn add_many(&self, elements: &[&IsA<Element>]) -> Result<(), glib::BoolError> {
   |                                     ^^^^^^^^^^^^ missing associated type `Storage` value

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.