Kerem Cavusoglu
Kerem Cavusoglu

Reputation: 65

Electron event emitter error while app.quit with closing all open renderer processes

I have one main window listing all available servers with a status button which has the id of the server. An info window is opened after pressing the related status button - passing the id to the copy of info window, making the status button disabled. If the info window is closed, the info window passes back the id to the main window so it makes the status button enabled again. To do that, I'm using main.js as a proxy, listening to the renderer processes and exchange information between main window and info window.

The thing that I'm trying to do is to list servers. If they are online, get some information from multiple servers at once on different renderer processes (instance of info window).

The problem is I want all info windows to be closed if the main window is closed.

// App ready
app.on('ready', ()=>{
    mainWindow = new BrowserWindow({x : 0, y : 0 , width : 500, height: 600});

    mainWindow.loadURL(url.format({
        pathname : path.join(__dirname, 'windows', 'mainWindow.html'),
        protocol : 'file',
        slashes : true
    }));

    // Close the app if main window closed
    mainWindow.on('close', (e) => {
        let openedOnes = BrowserWindow.getAllWindows();
        openedOnes.forEach(wind => {
            if(wind.hasOwnProperty('custom')){
                wind.close();
            };
        });

        app.quit();
    });
});

While creating info window, I add a custom field to the BrowserWindow object:

BrowserWindow {
  _events:
   { blur: [Function],
     focus: [Function],
     show: [Function: visibilityChanged],
     hide: [Function: visibilityChanged],
     minimize: [Function: visibilityChanged],
     maximize: [Function: visibilityChanged],
     restore: [Function: visibilityChanged],
     close: [Function: callIntoRenderer] },
  _eventsCount: 8,
  devToolsWebContents: [Getter],
  custom: { server_id: '3' } }

So with the help of the custom field, I can get all opened server info instances.

But when I click close, the following part is failing at main.js;

ipcMain.on('window_closed', (e, item)=>{
    mainWindow.webContents.send('button_enable', item);
});

It raises the following error.

enter image description here

main.js:53 is the line ipcMain.on('window_closed'.... By the way, if I omit this line everything works perfectly.

Upvotes: 0

Views: 1937

Answers (3)

pushkin
pushkin

Reputation: 10199

It looks like what's happening is your mainWindow close handler gets triggered which tells other windows to close, which then fires off the window_closed event (I guess that's a custom event that you added?), and by the timemainWindow.webContents.send is called, the mainWindow's close handler finished and the window closed.

Simply add an isDestroyed check before sending the message like so:

ipcMain.on('window_closed', (e, item)=>{
    if (mainWindow && !mainWindow.isDestroyed())
        mainWindow.webContents.send('button_enable', item);
});

Your other options (though arguably less optimal) are:

  1. Set a flag when the main window is closing and have the window_closed handler return out if it sees the flag (surely there's no reason to send a button_enable message if we're about to shut everything down):

 

let mainWindowIsClosing = false;
mainWindow.on('close', (e)=>{
    mainWindowIsClosing = true;
    ...
    wind.close();
    ...
});

ipcMain.on('window_closed', (e, item)=>{
    if (mainWindowIsClosing) return;
    mainWindow.webContents.send('button_enable', item);
});
  1. You can call the destroy method instead of close to avoid firing the close event for child windows. (though window_closed isn't an Electron event I believe, so it depends on how you've hooked everything up):

 

mainWindow.on('close', (e)=>{
    ...
    wind.destroy();
});

Upvotes: 1

Toinane
Toinane

Reputation: 51

You should use Child/Parent BrowserWindows like here: https://electronjs.org/docs/api/browser-window#parent-and-child-windows

You will get more easier all child windows with:

win.getChildWindows()

https://electronjs.org/docs/api/browser-window#wingetchildwindows

Upvotes: 0

Kerem Cavusoglu
Kerem Cavusoglu

Reputation: 65

Found a solution as follows;

mainWindow.on('close', (e)=>{
    mainWindow = null;
    try{
        let openedOnes = BrowserWindow.getAllWindows();
        openedOnes.forEach(wind=>{
            if(wind.hasOwnProperty('custom')){
                wind.close();
            };
        });

        app.quit();

    }catch(e){
        console.log(e);
    }
});

Before closing the main window, i set the mainwindow to null. When an info window is closed, check if its not set to null, send the mainwindow an info window is closed and its status button should be enabled;

ipcMain.on('window_closed', (e, item)=>{
    try {
        if(mainWindow !== null){
            mainWindow.webContents.send('button_enable', item);
        }
    } catch (error) {
        console.log(error);
    }
});

Upvotes: 0

Related Questions