1 year ago

#129979

test-img

itzjackyscode

How do I monkey-patch GObjects in a GNOME extension?

Versions

  • GNOME 40.4.0
  • Ubuntu 21.10 (Wayland)

Description

I'm writing an extension that provides fixed input method ordering in GNOME, as opposed to its usual MRU ordering. I have patched the InputSourceManager class to not reorder the sources when switching inputs.

I still need to patch InputSourcePopup, so that the popup starts from the correct location. However, when I try to do this, the popup menu will then refuse to show up.

Things I've tried

  • Replacing a single method
    function _patch2() {
      if (backward)
        this._select(mod(getInputSourceManager().currentSource.index - 1, this._items.length))
      else if (this._items.length == 1)
        this._select(0);
      else
        this._select(mod(getInputSourceManager().currentSource.index + 1, this._items.length));
    }
    InputSourcePopup.prototype._initialSelection = _patch2;
  • Replacing InputSourcePopup with a custom class
var StaticInputSourcePopup = GObject.registerClass(
  class StaticInputSourcePopup extends SwitcherPopup {
    _init(items, action, actionBackward) {
      super._init(items);

      this._action = action;
      this._actionBackward = actionBackward;

      this._switcherList = new InputSourceSwitcher(this._items);
    }

    _keyPressHandler(keysym, action) {
      log(`Acting on keypress`)
      if (action == this._action)
        this._select(this._next());
      else if (action == this._actionBackward)
        this._select(this._previous());
      else if (keysym == Clutter.KEY_Left)
        this._select(this._previous());
      else if (keysym == Clutter.KEY_Right)
        this._select(this._next());
      else
        return Clutter.EVENT_PROPAGATE;

      return Clutter.EVENT_STOP;
    }

    _initialSelection(backward, _binding) {
      if (backward) {
        let index = mod(getInputSourceManager().currentSource.index - 1, this._items.length);
        this._select(index);
        log(`Selecting index ${index}`);
      }
      else if (this._items.length == 1) {
        this._select(0);
        log(`Selecting index 0`);
      }
      else {
        let index = mod(getInputSourceManager().currentSource.index + 1, this._items.length);
        this._select(index);
        log(`Selecting index ${index}`);
      }
    }

    _finish() {
      super._finish();

      this._items[this._selectedIndex].activate(true);
    }
  });
// later, in the enable() method
    function _patchSwitchInputSource(display, window, binding) {
      if (this._mruSources.length < 2)
        return;

      // HACK: Fall back on simple input source switching since we
      // can't show a popup switcher while a GrabHelper grab is in
      // effect without considerable work to consolidate the usage
      // of pushModal/popModal and grabHelper. See
      // https://bugzilla.gnome.org/show_bug.cgi?id=695143 .
      if (Main.actionMode == Shell.ActionMode.POPUP) {
        this._modifiersSwitcher();
        return;
      }

      let popup = new StaticInputSourcePopup(this._mruSources, this._keybindingAction, this._keybindingActionBackward);
      if (!popup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
        popup.fadeAndDestroy();
    }
    InputSourceManager.prototype._switchInputSource = _patchSwitchInputSource;

Neither of these work— the first method causes the switching to go wonky, while the second one does nothing at all.

I have reason to assume that patching that class will not be easy because it is a GObject class. How should I approach this?

gnome-shell-extensions

0 Answers

Your Answer

Accepted video resources