Lets look at IPCMain and IPCRenderer in Electron. We can use it to send messages between main and renderer processes.
Over at the forums there was a developer who needed to open a second app window from the main process when the user had done something in the renderer process. So I thought we could look at a real world example. So in this tutorial we’ll wait for the user to click a button. Then we’ll send a message to the main process which in turn opens a new window.
1. Setting up a new window in main.js
Fire up the Electron tutorial app or your own app, and open main.js. The additions are highlighted in bold.
const electron = require('electron')
var path = require('path')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow
//Adds the main Menu to our app
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
let secondWindow
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({titleBarStyle: 'hidden',
width: 1281,
height: 800,
minWidth: 1281,
minHeight: 800,
backgroundColor: '#312450',
show: false,
icon: path.join(__dirname, 'assets/icons/png/64x64.png')
})
....
secondWindow = new BrowserWindow({frame:false,
width: 800,
height: 600,
minWidth: 800,
minHeight: 600,
backgroundColor: '#312450',
show: false,
icon: path.join(__dirname, 'assets/icons/png/64x64.png'),
parent: mainWindow
})
secondWindow.loadURL(`file://${__dirname}/windows/secondWindowcontent.html`)
require('./menu/mainmenu')
}
...
We create a new variable to hold our second window with let secondWindow and by now you know how to create a new BrowserWindow. But this time the size of the window has changed. And we also don’t show a frame, so we set that to frame:false. This is because we close the window from a button that we create ourselves instead of using the standard os-buttons. If the user closes the new window with the built in close button they wont be able to open it again because it’s not initialized anymore.
We also set mainWindow as parent so that secondWindow will stay on top of the parent window. There are some platform specific handling to the parent setting:
On macOS the child windows will keep the relative position to parent window when parent window moves, while on Windows and Linux child windows will not move.
On Windows it is not supported to change parent window dynamically.
On Linux the type of modal windows will be changed to dialog.
On Linux many desktop environments do not support hiding a modal window
The secondWindow also loads another .html file called ipcwindow.html that is located in a folder called windows. Lets look at that next.
2. IPCWindow content
Create a new folder called windows. In that folder you create ipcwindow.html. Add this content to the html file:
<!DOCTYPE HTML>
<!--
Hyperspace by HTML5 UP
html5up.net | @ajlkn
Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
<head>
<title>Electron tutorial app - ipc</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="../assets/css/main.css" />
</head>
<body>
<!-- Sidebar -->
<section id="sidebar">
<div class="inner">
<nav>
<ul>
</ul>
</nav>
</div>
</section>
<!-- Wrapper -->
<div>
<section id="welcome" class="wrapper style1 fullscreen intro">
<div class="inner">
<h1>Yes this is the second window!</h1>
<ul class="actions">
<li><a href="#one" id="close-me-button" class="button scrolly">Close me</a></li>
</ul>
</div>
</section>
</div>
<!-- Footer -->
<footer id="footer" class="wrapper style1-alt">
<div class="inner">
<ul class="menu">
<li></li>
</ul>
</div>
</footer>
<!-- Scripts -->
<script>window.$ = window.jQuery = require('../assets/js/jquery.min.js');</script>
<script>window.i18n = new(require('../translations/i18n'));</script>
<script src="../assets/js/jquery.scrollex.min.js"></script>
<script src="../assets/js/jquery.scrolly.min.js"></script>
<script src="../assets/js/skel.min.js"></script>
<script src="../assets/js/util.js"></script>
<script src="../assets/js/main.js"></script>
<script>
require('../assets/js/translations')
</script>
</body>
</html>
3. Changes in navigation menu and who we are section
When this tutorial is being written the navigation menu and who we are section looks like this:
Change the name of the menu-item to IPC/Remote in the en.js and sv.js translations
{
....
"Who we are": "IPC/Remote"
....
}
Also rename sections/whoweare.html to ipcremote.html. Then update link=rel and the sidebar menu in index.html:
....
<link rel="import" href="sections/ipcremote.html">
....
<li><a id="welcome-menu" data-section="welcome" href="#">Welcome</a></li>
<li><a id="whoweare-menu" data-section="ipcremote" href="#">Who we are</a></li>
<li><a id="whatwedo-menu" data-section="whatwedo" href="#">What we do</a></li>
<li><a id="getintouch-menu" data-section="getintouch" href="#">Get in touch</a></li>
In ipcremote.html we also need to update the id of the section to ipcremote and adding some information about what will happen if we click the button:
<template class="section-template">
<section id="ipcremote" class="wrapper style2 spotlights">
<section>
<div class="content">
<div class="inner">
<h2>IPCRenderer and IPCMain</h2>
<p>Click the button below to send a message that is picked up in the main process and open a new window</p>
<ul class="actions">
<li><a href="#" id="open-secondwindow-button" class="button">Open Window</a></li>
</ul>
</div>
</div>
</section>
4. IPCRenderer
Now we’ve got our app set up and it’s finally time to move on to sending and receiving messages with IPC. This will be done asynchronous.
Create a file called ipc.js in assets/js/. To start with you can add this content to it:
const {ipcRenderer} = require('electron')
window.ipc = window.ipc || {},
function(n) {
ipc.messaging = {
sendOpenSecondWindowEvent: function() {
ipcRenderer.send('open-second-window', 'an-argument')
},
init: function() {
$('#open-secondwindow-button').click( function () {
ipc.messaging.sendOpenSecondWindowEvent()
})
}
};
n(function() {
ipc.messaging.init();
})
}(jQuery);
init() is called on documentready. That in turn hooks up an onclick event on the button in the ipc section with id #open-secondwindow-button. Now to the ipc stuff. When that button is clicked ipcRenderer.send is invoked like this: ipcRenderer.send(‘open-second-window’, ‘an-argument’) The first value sent as a parameter is the name of the event. The second one is an argument of your own choice.
and add a require statement to the file in index.html:
<script>
require('./assets/js/menu')
require('./assets/js/translations')
require('./assets/js/ipc')
</script>
5. IPCMain
Now it is time to listen for this event in main.js. Start by adding a require statement for ipcMain at the top of the file:
const electron = require('electron')
const {ipcMain} = require('electron')
....
And to listen to the event and showing the second window just add this code:
...
ipcMain.on('open-second-window', (event, arg)=> {
secondWindow.show()
})
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
And at this point the tutorial on ipc main and renderer is over. But we’ll do it once more just to be able to close the secondwindow again.
6. Closing a BrowserWindow
Open up ipc.js again and add another on click event that sends a closing message to main:
const {ipcRenderer} = require('electron')
window.ipc = window.ipc || {},
function(n) {
ipc.messaging = {
sendOpenSecondWindowEvent: function() {
ipcRenderer.send('open-second-window', 'an-argument')
},
sendCloseSecondWindowEvent: function() {
ipcRenderer.send('close-second-window', 'an-argument')
},
init: function() {
$('#open-secondwindow-button').click( function () {
ipc.messaging.sendOpenSecondWindowEvent()
})
$('#close-me-button').click( function () {
ipc.messaging.sendCloseSecondWindowEvent()
})
}
};
n(function() {
ipc.messaging.init();
})
}(jQuery);
And in main we add another event listener:
....
ipcMain.on('open-second-window', (event, arg)=> {
secondWindow.show()
})
ipcMain.on('close-second-window', (event, arg)=> {
secondWindow.hide()
})
....
Ipc also needs to be required from ipcwindow.html:
...
<script>
require('../assets/js/translations')
require('../assets/js/ipc')
</script>
</body>
</html>
That’s it for this tutorial. Check out the official documentation on IPCMain and IPCRenderer
In the next tutorial we look at electron asar