Skip to content

Some menu items from Astal-tray.TrayItem are unusable #405

@Lengyue57

Description

@Lengyue57

Have you read through the documentation?

Describe what have you tried so far

  • used tray_item.menu_model with Gtk.PopoverMenu directly.
  • built an intermediate Gio.Menu to Gtk.PopoverMenu.
  • forwarded actions in tray_item.action_group and created missing actions.

Describe your question

versions:

Some menu items are unusable in my tray app menu. and they work normally in Waybar.

Image

The "A" submenu is gray

Initially, I built the Menu in the following way:

// in my widget
this.popover = new Gtk.PopoverMenu();
this.popover.set_parent(this);
// menu model
this.tray_item.bind_property("menu-model", this.popover, "menu-model", GObject.BindingFlags.SYNC_CREATE);
// action group
this.popover.insert_action_group("dbusmenu", this.tray_item.action_group);
this.tray_item.connect("notify::action-group", (tray_item) => {
  this.popover.insert_action_group("dbusmenu", tray_item.action_group);
});

Later, I tried to recursive traversal tray_item.menu_model and build an intermediate Gio.Menu:

function updateMenuFromModel(menu: Gio.Menu, model: Gio.MenuModel) {
  // ... recursive traversal `tray_item.menu_model` and update menu
}

// in my widget
const menu = new Gio.Menu();
updateMenuFromModel(menu, this.tray_item.menu_model);
this.tray_item.connect("notify::menu-model", (tray_item) => {
  updateMenuFromModel(menu, tray_item.menu_model);
});

this.popover = new Gtk.PopoverMenu({ menu_model: menu });
this.popover.set_parent(this);
// action group
this.popover.insert_action_group("dbusmenu", this.tray_item.action_group);
this.tray_item.connect("notify::action-group", (tray_item) => {
  this.popover.insert_action_group("dbusmenu", tray_item.action_group);
});

The problem remains, but during my investigation, I discovered:
The menu_model has action dbusmenu.id-305 and dbusmenu.submenu-305, but
action_group only contains dbusmenu.submenu-305.

I am not sure if this is expected, so I tried to create the missing action:

// find all action in model that are missing in action_group and create Gio.Action
function menuMissingActions(action_group: Gio.ActionGroup, model: Gio.MenuModel): Gio.Action[] {
  const actions: Gio.Action[] = [];
  for (let i = 0, items_count = model.get_n_items(); i < items_count; ++i) {
    const action_name = model.get_item_attribute_value(i, Gio.MENU_ATTRIBUTE_ACTION, new GLib.VariantType("s"))?.get_string()[0]?.replace(/^dbusmenu./, "") ?? null;
    if (action_name && !action_group.has_action(action_name)) {
      const props: Partial<Gio.SimpleAction.ConstructorProps> = {};
      const parameter_type = model.get_item_attribute_value(i, Gio.MENU_ATTRIBUTE_TARGET, null)?.get_type() ?? null;

      props.name = action_name;
      if (parameter_type)
        props.parameter_type = parameter_type;

      actions.push(new Gio.SimpleAction(props));
    }

    // recursive
    const link = model.get_item_link(i, Gio.MENU_LINK_SUBMENU) ?? model.get_item_link(i, Gio.MENU_LINK_SECTION);
    if (link) {
      actions.push(...menuMissingActions(action_group, link));
    }
  }
  return actions;
}

function fixedTrayItemActionGroup(tray_item: AstalTray.TrayItem) {
  const action_group = new Gio.SimpleActionGroup();

  for (const action_name of tray_item.action_group.list_actions()) {
    const action_info = tray_item.action_group.query_action(action_name);
    const action = new Gio.SimpleAction({ /* ... */ });
    action.connect("activate", (action, parameter) => tray_item.action_group.activate_action(action_name, parameter));

    action_group.add_action(action);
  }

  const menu_missing_actions = menuMissingActions(tray_item.action_group, tray_item.menu_model);
  for (const action of menu_missing_actions) {
    action_group.add_action(action);
  }

  return action_group;
}

// in my widget
this.popover = new Gtk.PopoverMenu();
this.popover.set_parent(this);
this.tray_item.bind_property("menu-model", this.popover, "menu-model", GObject.BindingFlags.SYNC_CREATE);
this.popover.insert_action_group("dbusmenu", fixedTrayItemActionGroup(this.tray_item));
this.tray_item.connect("notify::action-group", (tray_item) => {
  this.popover.insert_action_group("dbusmenu", fixedTrayItemActionGroup(tray_item));
});

The menu item became usable after this, but program always crashes shortly after.

Is this a bug in Astal?
What should I do to make it work normally?

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions