Test bed for gtk-rs-core experiments

Related tags

GUI gobject
Overview

Rust GObject Experiments

class macro

#[gobject::class(final)]
mod obj {
    #[derive(Default)]
    pub struct MyObj {
        #[property(get, set)]
        my_prop: std::cell::Cell<u64>,
    }
    impl MyObj {
        #[signal]
        fn abc(&self) {}
    }
}

fn main() {
    let obj: MyObj = glib::Object::new(&[]).unwrap();
    obj.set_my_prop(52);
    obj.emit_abc();
}

clone_block macro

#[gobject::clone_block]
fn main() {
    use glib::prelude::ObjectExt;

    let get_cell = {
        let cell = std::rc::Rc::new(std::cell::Cell::new(50u32));

        // equivalent to glib_clone!(@weak-allow-none cell => ...)
        let get_cell = move |#[weak] cell| cell.map(|c| c.get()).unwrap_or(0);
        cell.set(100);

        // arguments marked with #[weak] or #[strong] are passed implicitly
        assert_eq!(get_cell(), 100u32);
        get_cell
    };
    assert_eq!(get_cell(), 0u32);

    let concat = {
        let refcell = std::rc::Rc::new(std::cell::RefCell::new(String::from("Hello")));
        let obj: glib::Object = glib::Object::new(&[]).unwrap();
        let concat = move |#[strong] refcell, #[strong] obj, extra: &str| {
            format!("{} {} {}", refcell.borrow(), obj.type_().name(), extra)
        };
        assert_eq!(concat("World"), "Hello GObject World");
        refcell.replace(String::from("Goodbye"));
        concat
    };
    assert_eq!(concat("World"), "Goodbye GObject World");

    // other supported options

    // renaming:
    //     move |#[weak(self)] this| {}
    //     move |#[strong(self.mydata)] this| {}
    //
    // default panic:
    //     move |#[weak(or_panic)] value| {}
    //     move |#[weak(self or_panic)] this| {}
    //     #[default_panic] move |#[weak(self)] this| {}
    //
    // default return:
    //     move |#[weak(or_return)] value| {}
    //     move |#[weak(or_return 123)] value| {}
    //     move |#[weak(self or_return)] this| {}
    //     move |#[weak(self or_return 123)] this| {}
    //     #[default_return] move |#[weak(self)] this| {}
    //     #[default_return 123] move |#[weak(self)] this| {}
    //
    // default alternative:
    //     move |#[weak(or 123)] value| {}
    //     move |#[weak(self.myvalue or 123)] value| {}
    //
    // forcing an Option when another default is present:
    //     #[default_panic] move |#[weak(self)] this, #[weak(allow_none)] value| {}
    //     #[default_panic] move |#[weak(self)] this, #[weak(self.myvalue allow_none)] value| {}

    // equivalent to glib::closure!
    let add = #[closure] |a: i32, b: i32| a + b;
    assert_eq!(add.invoke::<i32>(&[&3i32, &7i32]), 10);

    let obj: glib::Object = glib::Object::new(&[]).unwrap();

    // equivalent to glib::closure_local!
    let closure = move |#[watch] obj| obj.type_().name().to_owned();
    assert_eq!(closure.invoke::<String>(&[]), "GObject");

    // strong and weak references work with closures too
    let get_cell = {
        let cell = std::rc::Rc::new(std::cell::Cell::new(50u32));
        let get_cell = #[closure(local)] move |#[weak] cell| cell.map(|c| c.get()).unwrap_or(0);
        cell.set(100);
        assert_eq!(get_cell.invoke::<u32>(&[]), 100);
        get_cell
    };
    assert_eq!(get_cell.invoke::<u32>(&[]), 0);

    // rest parameters are supported as the last argument of closures
    let sum = #[closure] |x: i32, #[rest] rest: &[glib::Value]| -> i32 {
        x + rest.iter().map(|v| v.get::<i32>().unwrap()).sum::<i32>()
    };
    assert_eq!(sum.invoke::<i32>(&[&10i32, &100i32, &1000i32]), 1110i32);
}

This repo also has a clone-blockify tool that attempts to convert Rust source files from glib::clone! and glib::closure! into the clone_block format.

Comments
  • Can't create a non-final subclass

    Can't create a non-final subclass

    When I try to create a non-final subclass, like #[gobject::class(extends(ObjAbstract))], it errors out: the trait 'ObjAbstractImpl' is not implemented for '____Object'. Am I missing something?

    opened by melix99 7
  • Allow having gobject's inner structs with limited visibility

    Allow having gobject's inner structs with limited visibility

    Currently it seems that the gobject structs need to be public, otherwise you get a crate-private type 'object::imp:Object' in public interface error. Is it possible to allow at least a pub(crate) visibility?

    opened by melix99 7
  • Can't disable widget action via

    Can't disable widget action via "action_set_enabled"

    Apparently the action_set_enabled method doesn't do anything for some reason. This can be tested by putting widget.action_set_enabled("my-widget.set-label", false); in this line of this test. The test will not fail, so the action is still enabled.

    Version: de4e5e90f0ea817e83cd7d2bd212d44302286d45.

    opened by melix99 5
  • Support non-optional getters for weak refs

    Support non-optional getters for weak refs

    I know that weak refs should return an Option ideally, but I have cases where I have e.g. an object A that has a strong ref of B, and the B object that has a weak ref of A, and since I know that B will exist as long as A exists, I just unwrap the A weak reference in B's getter.

    opened by melix99 4
  • Can't create a widget subclass with a virtual method

    Can't create a widget subclass with a virtual method

    use gtk4::subclass::prelude::WidgetImpl;
    #[gobject::class(abstract, extends(gtk4::Widget), parent_trait = "WidgetImpl")]
    mod obj {
        use super::WidgetImpl;
        #[derive(Default)]
        pub(crate) struct CustomWidget {}
        impl CustomWidget {
            #[virt]
            fn virtual_method(&self) {}
        }
        impl WidgetImpl for CustomWidget {}
    }
    
    error[E0277]: the trait bound `gtk4::Widget: ObjectSubclassIs` is not satisfied
     --> tests/gtk4_widget.rs:4:1
      |
    4 | #[gobject::class(abstract, extends(gtk4::Widget), parent_trait = "WidgetImpl")]
      | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ObjectSubclassIs` is not implemented for `gtk4::Widget`
    

    Removing the virtual method makes the above code compile just fine.

    opened by melix99 2
  • clone-blockify: Replace expressions based on LineColumn

    clone-blockify: Replace expressions based on LineColumn

    Currently the formatting and comments are messed up. Instead of rewriting the whole file, it needs to replace only the region in between .span().start() and .span().end()

    enhancement 
    opened by jf2048 2
  • Let the user specify if they want a nullable object property or not

    Let the user specify if they want a nullable object property or not

    Currently it seems that if I use a RefCell<Option<glib::Object>> as a property, the macro will generate the relative getter and setter of the type Option<glib::Object> instead of what I wanted (just a glib::Object). Setting a custom getter and setter does not work because the macro still expects an Option. My suggestion is to add a sort of "nullable" macro attribute to let the user decide whether to have a nullable property or not.

    opened by melix99 2
  • Add a private method macro

    Add a private method macro

    Currently it doesn't seem possible to create a method that is only visible inside the gobject impl. This is needed to e.g. implement private methods that accesses the properties without needing to make them public.

    opened by melix99 2
  • `clone-blockify` macro: Preserve default

    `clone-blockify` macro: Preserve default

    clone-blockify currently modifies files like that.

    -        clone!(@weak button => @default-return Continue(false),
    -                    move |enable_button| {
    +        move |# [weak (or_return Continue (false))] button, enable_button| {
    

    I would have expected to preserve the default like this:

    -        clone!(@weak button => @default-return Continue(false),
    -                    move |enable_button| {
    +        #[default_return Continue (false)] move |# [weak] button, enable_button| {
    
    opened by Hofer-Julian 2
  • `clone_block` macro: Motivate different order in macro

    `clone_block` macro: Motivate different order in macro

    Currently this is the suggested order of arguments for closures with clone_block attributes:

    1. Cloned values
    2. Actual parameters of the final closure
    move |#[strong] refcell, #[strong] obj, extra: &str| {
    

    I suggest to reverse this:

    1. Actual parameters of the final closure
    2. Cloned values
    move |extra: &str, #[strong] refcell, #[strong] obj| {
    

    I like it more since these cloned values are the extra, that will be stripped away afterwards. People will have to take care that the original parameters fit the expected closure, so that's where there should be their focus

    enhancement 
    opened by Hofer-Julian 2
  • `clone-blockify` removes comments

    `clone-blockify` removes comments

    clone-blockify removes comments. See for example here:

    diff --git a/book/listings/gobject_memory_management/3/main.rs b/book/listings/gobject_memory_management/3/main.rs
    index 712537c7705..bdcaff9338c 100644
    --- a/book/listings/gobject_memory_management/3/main.rs
    +++ b/book/listings/gobject_memory_management/3/main.rs
    @@ -1,25 +1,17 @@
    -use std::{cell::Cell, rc::Rc};
    -
     use glib::clone;
     use gtk::prelude::*;
     use gtk::{self, ApplicationWindow, Button, Orientation};
     use gtk::{glib, Application};
    -
    +use std::{cell::Cell, rc::Rc};
     fn main() {
    -    // Create a new application
         let app = Application::builder()
             .application_id("org.gtk-rs.example")
             .build();
    -
    -    // Connect to "activate" signal of `app`
         app.connect_activate(build_ui);
    -
    -    // Run the application
         app.run();
     }
    -
    +#[gobject::clone_block]
     fn build_ui(app: &Application) {
    -    // Create two buttons
         let button_increase = Button::builder()
             .label("Increase")
             .margin_top(12)
    @@ -34,38 +26,26 @@ fn build_ui(app: &Application) {
             .margin_start(12)
             .margin_end(12)
             .build();
    -
         let number = Rc::new(Cell::new(0));
    -
    -    // ANCHOR: callback
    -    // Connect callbacks
    -    // When a button is clicked, `number` and label of the other button will be changed
    -    button_increase.connect_clicked(clone!(@weak number, @strong button_decrease =>
    -        move |_| {
    +    button_increase.connect_clicked(
    +        move |#[weak(or_return)] number, #[strong] button_decrease, _| {
                 number.set(number.get() + 1);
                 button_decrease.set_label(&number.get().to_string());
    -    }));
    -    button_decrease.connect_clicked(clone!(@strong button_increase =>
    -        move |_| {
    -            number.set(number.get() - 1);
    -            button_increase.set_label(&number.get().to_string());
    -    }));
    -    // ANCHOR_END: callback
    -
    -    // Add buttons to `gtk_box`
    +        },
    +    );
    +    button_decrease.connect_clicked(move |#[strong] button_increase, _| {
    +        number.set(number.get() - 1);
    +        button_increase.set_label(&number.get().to_string());
    +    });
         let gtk_box = gtk::Box::builder()
             .orientation(Orientation::Vertical)
             .build();
         gtk_box.append(&button_increase);
         gtk_box.append(&button_decrease);
    -
    -    // Create a window
         let window = ApplicationWindow::builder()
             .application(app)
             .title("My GTK App")
             .child(&gtk_box)
             .build();
    -
    -    // Present the window
         window.present();
     }
    
    opened by Hofer-Julian 2
  • Get rid of the magic trait methods

    Get rid of the magic trait methods

    The class macro detects things like class_init and constructed by name and expects them to have the signature that matches ObjectSubclass, ObjectImpl, so it can copy them into the trait implementation. If you get the signature wrong you get some strange errors and rust-analyzer can't help you with autocomplete because it's not technically filling in a trait. Maybe there should just be a new trait that includes these methods that the macro can detect.

    enhancement 
    opened by jf2048 0
  • Add a way to remap user property flags in users gobject_core

    Add a way to remap user property flags in users gobject_core

    For example in GStreamer we have specified some flags: https://gstreamer.freedesktop.org/documentation/gstreamer/gstparamspec.html?gi-language=c#constants

    Now in the gst::element proc macro we should be able to specify those flags directly like:

    #[gst::element(....)]
    mod impl {
         struct MyElement {
            #[property(get, set, mutable_ready, controllable)]
            uri: Mutex<String>,
        }
    }
    

    but I haven't been able to figure out how to do that cleanly.

    opened by thiblahute 1
  • Fix having several

    Fix having several "hand written" properties

    We were overflowing when calculating the "generated_prop_id", let it be negative when setting/getting a manually added property:

    thread 'object_inner_methods' panicked at 'attempt to subtract with overflow', /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/ops/arith.rs:240:1
    stack backtrace:
       0: rust_begin_unwind
                 at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/std/src/panicking.rs:584:5
       1: core::panicking::panic_fmt
                 at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/panicking.rs:142:14
       2: core::panicking::panic
                 at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/panicking.rs:48:5
       3: <usize as core::ops::arith::Sub>::sub
                 at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/ops/arith.rs:233:45
       4: <usize as core::ops::arith::Sub<&usize>>::sub
                 at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/internal_macros.rs:61:17
       5: <object::obj_inner::ObjInner as glib::subclass::object::ObjectImpl>::property
                 at ./tests/object.rs:56:1
       6: glib::subclass::object::property
                 at /var/home/thiblahute/devel/misc/gtk-rs-core/glib/src/subclass/object.rs:80:13
       7: g_object_get_property
       8: <T as glib::object::ObjectExt>::try_property_value
                 at /var/home/thiblahute/devel/misc/gtk-rs-core/glib/src/object.rs:2515:13
       9: <T as glib::object::ObjectExt>::try_property
                 at /var/home/thiblahute/devel/misc/gtk-rs-core/glib/src/object.rs:2485:20
      10: <T as glib::object::ObjectExt>::property
                 at /var/home/thiblahute/devel/misc/gtk-rs-core/glib/src/object.rs:2493:9
      11: object::object_inner_methods
                 at ./tests/object.rs:134:16
      12: object::object_inner_methods::{{closure}}
                 at ./tests/object.rs:125:1
      13: core::ops::function::FnOnce::call_once
                 at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/ops/function.rs:248:5
      14: core::ops::function::FnOnce::call_once
                 at /rustc/a8314ef7d0ec7b75c336af2c9857bfaf43002bfc/library/core/src/ops/function.rs:248:5
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    
    opened by thiblahute 1
Owner
Jason Francis
Jason Francis
Idiomatic, GTK+-based, GUI library, inspired by Elm, written in Rust

Relm Asynchronous, GTK+-based, GUI library, inspired by Elm, written in Rust. This library is in beta stage: it has not been thoroughly tested and its

null 2.2k Dec 31, 2022
Provides Rust bindings for GTK libraries

The gtk-rs organization aims to provide safe Rust binding over GObject-based libraries

null 431 Dec 30, 2022
Highly customizable finder with high performance. Written in Rust and uses GTK

Findex Highly customizable finder with high performance. Written in Rust and uses GTK Installation Automatic Binary Clone from https://aur.archlinux.o

MD Gaziur Rahman Noor 442 Jan 1, 2023
An example of searching iBeacon using gtk-rs and btleplug.

Beacon Searcher Screenshot Compile & Run Install GTK 3 dev packages: macOS: $ brew install gtk+3 $ brew install gnome-icon-theme Debian / Ubuntu: $ s

Ling, Wei-Cheng 0 Dec 21, 2021
Rust bindings and wrappers for GLib, GDK 3, GTK+ 3 and Cairo.

THIS REPOSITORY IS DEPRECATED SEE: https://github.com/rust-gnome rgtk Rust bindings and wrappers for GLib, GDK 3, GTK+ 3 and Cairo. Building rgtk expe

Jeremy Letang 124 Jul 10, 2022
A GUI for NordVPN on Linux that maintains feature parity with the official clients, written with Rust and GTK.

Viking for NordVPN This project aims to provide a fully usable and feature-complete graphical interface for NordVPN on Linux. While it attempts to clo

Jacob Birkett 2 Oct 23, 2022
Provides Rust bindings for GTK libraries

gtk3-rs 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

null 431 Dec 30, 2022
Graphical font editor (GTK + Rust)

gerb *gerb ʰ-: reconstructed Proto-Indo-European root, meaning to carve gerb: a WIP font editor in gtk3 and rust Introduction gerb is an experimental,

Manos Pitsidianakis 40 Jan 1, 2023
A Rust library to parse Blueprint files and convert them into GTK UI files

?? gtk-ui-builder A Rust library to parse Blueprint files and convert them into GTK UI files Inspired by the Blueprint project Example 1 - blueprints

Observer KRypt0n_ 5 Oct 22, 2022
A powerful color picker and formatter, built with GTK and Rust

Eyedropper A powerful color picker and formatter. More screenshots Features Pick a Color Enter a color in Hex-Format Parse RGBA/ARGB Hex-Colors View c

Jonathan 108 Dec 24, 2022
GTK 4 front-end to ChatGPT completions written in Rust

ChatGPT GUI Building git clone [email protected]:teunissenstefan/chatgpt-gui.git cd chatgpt-gui cargo build --release Todo Connect insert_text to only al

Stefan Teunissen 6 Mar 12, 2023
Reactive components in rust, designed to make GTK more manageable

gflux gflux is a tiny experimental reactive component system for rust, designed to make GTK more manageable. gflux: is about 300 lines of code contain

Brian Vincent 3 Aug 20, 2023
Rust bindings to Core Foundation and other low level libraries on Mac OS X and iOS

core-foundation-rs Compatibility Targets macOS 10.7 by default. To enable features added in macOS 10.8, set Cargo feature mac_os_10_8_features. To hav

Servo 685 Jan 2, 2023
An Anime Game Launcher variant written on Rust, GTK4 and libadwaita, using Anime Game Core library

An Anime Game Launcher GTK The launcher variant written on Rust, GTK4 and libadwaita, using Anime Game Core library You could also try the main branch

An Anime Team 77 Jan 9, 2023
Honkers Launcher variant written on Rust, GTK4 and libadwaita, using Anime Game Core library

You could also try the main branch Development Folder Description ui Blueprint UI files ui/.dist UI files compiled by the blueprint src Rust source co

An Anime Team 9 Nov 2, 2022
Provides core language-agnostic functionality for LiveView Native across platforms

LiveView Native Core This repository contains an implementation of the LiveView Native core library, which is intended to handle all the details which

LiveView Native 35 Dec 27, 2022
autogen website (with Deno Core)

Kurit Static website generator ?? Warning WIP: It is still under development, so some of the features may not be developed. Project Structures graph T

null 11 Oct 16, 2023
Simple GTK Rust Fuzzer which aims to test all available classes and functions in GTK.

Gtk Rust Fuzzer Simple GTK Rust Fuzzer which aims to test all available classes and functions in GTK. It finds bugs inside GTK functions, GTK exported

Rafał Mikrut 8 Nov 19, 2022
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
ABQ is a universal test runner that runs test suites in parallel. It’s the best tool for splitting test suites into parallel jobs locally or on CI

?? abq.build   ?? @rwx_research   ?? discord   ?? documentation ABQ is a universal test runner that runs test suites in parallel. It’s the best tool f

RWX 13 Apr 7, 2023