Question about adding actions scoped to a widget instead of window or application

I’m developing an application in gtk4 using Rust, which has a gemini browser widget subclassed from the TextView widget. There will be links added dynamically while the program runs, and I have added “Open in new tab” and “Open in new window” items to the context menus for the links. Since the browser widget is in a separate crate, it does not have a reference to the window in which it will run at the time it is created, thus I wanted to scope my actions to the widget rather than the window.

As of now, I’m able to create my actions and a new action group, add the actions to the group and the group to the window. However, the menu items are still greyed out, leading me to think that I do not have the detailed action names quite right.

Here’s the function where the actions are being created and added.

fn add_actions(&self) {                                                                                   
    let request_new_tab = SimpleAction::new(                                                              
        "request-new-tab",                                                                                
        Some(glib::VariantTy::STRING),                                                                    
    );                                                                                                    
    let request_new_window = SimpleAction::new(                                                           
        "request-new-window",                                                                             
        Some(glib::VariantTy::STRING),                                                                    
    );                                                                                                    
    let group = SimpleActionGroup::new();                                                                 
    group.add_action(&request_new_tab);                                                                   
    group.add_action(&request_new_window);                                                                
    let viewer = self.clone();                                                                            
    request_new_tab.connect_activate(move |_,url| {                                                       
        viewer.emit_by_name::<()>("request-new-tab", &[&url]);                                            
    });                                                                                                   
    let viewer = self.clone();                                                                            
    request_new_window.connect_activate(move |_,url| {                                                    
        viewer.emit_by_name::<()>("request-new-window", &[&url]);                                         
    });                                                                                                   
    self.insert_action_group("viewer", Some(&group));                                                     
}

And here is where I’m adding the context menu items:

    // 'label' is a label with a link added via pango markup
    // 'link' is the url of the link in question
   // The format string returns "request-new-tab('gemini://example.com/some-page.gmi')"
    let open_menu = Menu::new();                                                              
    let action_name = format!("request-new-tab('{}')", &link);                                
    let in_tab = MenuItem::new(Some("Open link in new tab"), Some(&action_name));             
    let action_name = format!("request-new-window('{}')", &link);                             
    let in_window = MenuItem::new(Some("Open link in new window"), Some(&action_name));       
    open_menu.append_item(&in_tab);                                                           
    open_menu.append_item(&in_window);                                                        
    label.set_extra_menu(Some(&open_menu));

Not sure where it’s going wrong. Everything compiles, runs without errors. It behaves exactly as if there were no action associated with those menu items, which is why I don’t think I have the detailed names right.

The action name needs to be prefixed with the group, so it should be something like:

    let action_name = format!("viewer.request-new-tab('{}')", &link);                                

That fixed that issue, thanks. Now, I’m getting an error trying to connect to the signal being emitted by that action.

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: BoolError { message: "Incompatible argument type in argument 0 for signal 'request-new-tab' of type 'GemView' (expected gchararray, got GVariant)", <--snip -->

I’m guessing this is because what is passed into the closure for the request_new_tab action is a GVariant and not a string, so I need to extract the value from it before attempting to send my signal. I think I can figure the rest out, just thinking as I type.

Thanks for your time! That looks obvious now, but I couldn’t find any examples and the documentation wasn’t clicking for me.

I’ll make sure to add an example of a custom scope to the actions tutorial on developer.gnome.org.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.