0

I'm trying to implement key bindings inside a Cinnamon Applet. Basically, a click on a St.Button and a ENTER keypress on the same should call a specific method, and the signal should be consumed:

let button = new St.Button({ can_focus: true });

button.connect('button-release-event', Lang.bind(this, function(_, event) {
    const button = event.get_button();
    if (button !== 3) {
        this._onDayActivated();
        return Clutter.EVENT_STOP;
    }

    return Clutter.EVENT_PROPAGATE;
}));

button.connect('key-press-event', Lang.bind(this, function(_, event) {
    const symbol = event.get_key_symbol();
    const relevantKeys = [Clutter.KEY_space, Clutter.KEY_KP_Enter, Clutter.KEY_Return];
    if (relevantKeys.includes(symbol)) {
        this._onDayActivated();
        return Clutter.EVENT_STOP;
    }

    return Clutter.EVENT_PROPAGATE;
}));

This works so far, the method is executed as it should. But the applet is implemented as a Cinnamon TextApplet with a PopupMenu. These menus, as a default, close on clicks and ENTER keypresses. In class PopupBaseMenuItem, the wrapper container has these signal handlers:

_onButtonReleaseEvent(actor, event) {
    this.activate(event, false);
    return true;
}

_onKeyPressEvent(actor, event) {
    let symbol = event.get_key_symbol();

    if (symbol === Clutter.KEY_space ||
        symbol === Clutter.KEY_Return ||
        symbol === Clutter.KEY_KP_Enter) {
        this.activate(event);
        return true;
    }
    return false;
}

activate(event, keepMenu) {
    this.emit('activate', event, keepMenu); // basically closes the menu for keepMenu == false
}

If I click the button, the menu remains open. If I set the focus on the button and press ENTER (or SPACE), the menu closes.

What am I missing? Is it relevant that the button is destroyed before the signal handler returns with Clutter.EVENT_STOP?

ccprog
  • 20,308
  • 4
  • 27
  • 44

1 Answers1

0

This had nothing to do with the signal propagating. I was able to confirm the menu level signal callback was not called, but the PopupMenu.close() method was, for resons I could not find.

The real problem was destroying an element that still held the focus. As soon as I moved the focus elsewhere before destroying the button, everything worked as expected.

// Remove everything but the topBox and the weekday labels
let children = this.actor.get_children();
// move focus to go_home_button
this.actor.get_parent().get_first_child().grab_key_focus();
for (let i = this._firstDayIndex; i < children.length; i++) {
    children[i].destroy();
}
ccprog
  • 20,308
  • 4
  • 27
  • 44