Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stacking of Context Menus in Electron

I am building an Electron based application that contains a grid containing unique rows. I would like a context-menu that is specific to each row. Here is an example:

Image of GUI with context menu

Although this screen shot is cropped, you can see there are multiple rows and each row contains separate data. Since I'd like to right-click on a row and get a unique context menu, I have implemented electron-context-menu, which does work on the first right click, but then subsequent right-clicks causes a stacking effect of context menus.

Specifically, here is what happens:

  1. I right click on Row-1 and the proper context menu shows up
  2. I right click on Row-2 and a repeat of the context menu for Row-1 shows up then Row-2's context menu shows up. (Notice in the screen shot the context menu showing does not correspond to the row my mouse is over)
  3. This repeats itself.

In React.JS, here is my listener, which collects the contextmenu object as needed by the electron-context-menu module:

  handleContextMenu() {
    this.props.contextMenu({
      window: electron.remote.BrowserWindow.getFocusedWindow(),
      prepend: (params, browserWindow) => [{
        label: `Library Compare ${this.state.msn}`,
        click: () => this.runLibCompare()
      }],
      append: (params, browserWindow) => [{
        label: '---',
      }]
    })
  };

Where this.props.contextMenu(...) perculates up the React.JS components to be fed into:

const contextMenu = eRequire('electron-context-menu');

I have done some massive debugging and I don't think the issue is the module. The module I am using essentially organizes the information about the context menu and then uses electron.remote functions and a menu.popup function which comes from electron internals. Here is a link to the specific line in github.

const menu = (electron.Menu || electron.remote.Menu).buildFromTemplate(menuTpl);
menu.popup(electron.remote ? electron.remote.getCurrentWindow() : win);

This call to menu.popup leads to this line in electron.

  const remoteMemberFunction = function (...args) {
    if (this && this.constructor === remoteMemberFunction) {
      // Constructor call.
      let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(args))
      return metaToValue(ret)
    } else {
      // Call member function.
      let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(args))
      return metaToValue(ret)
    }

}

So I see a call to ipcRender.sendSync -- however when I add debugging statements in ipcMain's receiver of those calls, I don't see any output!

ipcMain.on('ELECTRON_BROWSER_MEMBER_CALL', function (event, id, method, args) {
  try {
    args = unwrapArgs(event.sender, args)
    let obj = objectsRegistry.get(id)

    if (obj == null) {
      throwRPCError(`Cannot call function '${method}' on missing remote object ${id}`)
    }

    callFunction(event, obj[method], obj, args)
  } catch (error) {
    event.returnValue = exceptionToMeta(error)
  }
})

When I added debug statements to the above function, I didn't see any output. And that is where my search his a wall.

I am using electron 1.4.15. I know this issue should be resolvable, after-all the Atom IDE (which is electron based) does not have this issue even though it has multiple context menus.

I think there is some memory I need to clear somewhere, I just can't figure out how to clear the stack of previous context menus!

like image 859
E.S. Avatar asked Feb 09 '17 22:02

E.S.


People also ask

How do you hide an Electron menu?

The only workaround is to use Menu. setApplicationMenu(null) , however, this will disable all the menu shortcuts like F11 for toggling fullscreen etc. In new versions of Electron, you can set autoHideMenuBar: true while creating browserWindow, pressing Alt will show the menu bar again.

Which actions displays the Windows context menu?

In Microsoft Windows, pressing the Application key or Shift+F10 opens a context menu for the region that has focus.

How do you create an Electron menu?

We imported the Menu and MenuItem modules using the remote module; then, we created a menu and appended our menuitems to it one by one. Further, we prevented the default action of right-click in chromium and replaced it with our menu. The creation of menus in Electron is a very simple task.


1 Answers

I solve this by first getting the target of the click using e.target. Then, depending on that, I call the corresponding contextmenu. If target hit is not in the list of targets for my app, I use a default contextmenu.

window.addEventListener(
    "contextmenu",
    e => {
        e.preventDefault();
        if (e.target.id === 'fullscr'){

        console.log(e && e.target);

       // e.preventDefault();
        mymenu.popup(remote.getCurrentWindow());
        }else{
            editmenu.popup(remote.getCurrentWindow());
        }
        console.log(e.which);
    },
    false
);  
like image 78
dedalus Avatar answered Oct 18 '22 20:10

dedalus