rustgtk-rs

Gtk-rs pass window as value


New to Rust and I'm trying to build a simple Rust GUI using gtk-rs following the docs here. What I'm wondering is whether it's possible to pass around the window that gets built in the build_ui function, so that I can update it from other operations in my code. The following code lives inside of a function that does other stuff too, further down in the function I would like to access the window so that I can add a new child widget (or something like that). Is this possible? If so how can I go about it? Unfortunately none of the examples in the project cover something like this.

    fn main() {

       let app = Application::builder()
          .application_id("org.gtk-rs.example")
          .build();

       app.connect_activate(build_ui);

       let mut win: ApplicationWindow; <---- I want to store the window here to use later

       fn build_ui(app: &Application) {
           // Create a window and set the title
           let window = ApplicationWindow::builder()
               .application(app)
               .title("My GTK App")
               .build();
    
           win = window; <---- 
       }

      // do other UI bootstrapping stuff

      // when ready to mount the window
      window.present();

    }

Would appreciate any help, thanks


Solution

  • What I do for Gtk-rs is as follows:

        struct Context {
            wnd: Option<ApplicationWindow>,
            //... other values associated to that window
        }
        let ctx = Context {
            wnd: None,
            //...
        };
        let ctx: Rc<RefCell<Context>> = Rc::new(RefCell::new(ctx));
        app.connect_activate(clone!(
            @strong ctx =>
            move |app| {
                let mut ctx = ctx.borrow_mut();
                let window = ApplicationWindow::builder()
                   .application(app)
                   .title("My GTK App")
                   .build();
        
                ctx.wnd = Some(window);
            }
        ));
    

    And then most of the connected signals clone the ctx in a kind of clone-chain.

    The details vary depending on your type of application:

        struct Context {
           wnds: Vec<WindowContext>,
           //global state
        }
        struct WindowContext {
           wnd: ApplicationWindow,
           //local state
        }
    

    Just remember that calling borrow_mut in a RefCell gives you an exclusive borrow. If you try to borrow twice and one of them is exclusive it will panic. So if some function raises a signal that calls another callback that borrows your global ctx then you will have to do some dancing.

        my_thing.connect_signal(clone!(
            @strong ctx =>
            move |_| {
                let ctx_ = ctx.borrow_mut();
                ctx_.do_something_that_that_does_not_borrow();
                drop(ctx_); //<-- release the borrow!
                do_something_else_that_may_borrow();
                //or also:
                let w = ctx.borrow().wnd.clone();
                do_something_else_that_may_borrow_with_window(w);
            }
        ));