Electron pass BrowserWindow to external main function (not IPC) - node.js

I understand and can implement both IPC and .remote() from main <--> renderers.
This question is about an external function still in the main thread and sharing the instantiated BowerserWindow.
For example, main.js:
...
let mainWindow = null;
...
mainWindow = new BrowserWindow({
show: false,
width: 1024,
height: 728
});
...
I'm trying to access mainWindow from foo.js and can't seem to get there.
Psuedocode:
export default () => {
let win = mainWindow // from main.js;
win.webContents.send('toast', 'woohoo'); // Arbitrary Render side listener
}

This works, although it seems like additional overhead as a lookup:
On main.js
foo(mainWindow.id)
On foo.js(id: number)
const win = BrowserWindow.fromId(id);
win.webContents.send('toast', 'woohoo');
I welcome any more efficient method.

Related

Why is the variable undefined? - Node - ElectronJs

I am creating an Electron app and I am trying to split my code in different scripts to make it more manageable; however, for some reason one of the variables in my script keeps returning undefined and I can't figure out why. I already checked similar questions here on SO, but did not find an answer.
I have a file called windowManipulation.js and this is part of it:
let signInWindow;
module.exports.createSignInWindow = () => {
signInWindow = new BrowserWindow({
show: false,
width: 1500,
height: 800,
webPreferences: {
nodeIntegration: true
}
});
signInWindow.loadFile(`views/logIn.html`)
signInWindow.once("ready-to-show", () => {
signInWindow.show();
});
signInWindow.on("close", () => {
signInWindow = null;
});
signInWindow.on('crashed', () => {
app.relaunch();
app.exit(0);
})
}
module.exports.closeSignInWindow = () => {
signInWindow.close();
signInWindow = null;
}
Now, when I call the function to create the window it creates it without a problem. But when I call the function to close it, it says that signInWindow is undefined.
Why is it undefined if it was supposed to be set when the signInWindow was created? What am I doing wrong?
It sounds like createSignInWindow and closeSignInWindow are being called from different processes. Being different processes, they each their own memory, and each would execute this file independently. So if you create the window in the main process, and close it from the window process, the window process will not think the variable exists.
So it sounds like you need to use ipcRenderer to communicate from the render to the main process so that it can close the window for you.
It'd be something like:
// renderer
const { ipcRenderer } = require('electron')
ipcRenderer.send('close-signin')
// main
const { ipcMain } = require('electron')
ipcMain.on('close-signin', closeSignInWindow)

How to stop Electron windows sharing cookies?

I am creating multiple browser windows in an electron app however I do not want them to share cookies. This is how I am currently creating the windows,
function createWindow() {
// Create the browser window.
let mainWindow = new BrowserWindow({ minWidth: 660, minHeight: 400, width: 1208, height: 680 })
// setInterval(() => sendStatus(0, 'FAIL'), 5000);
// Emitted when the window is closed.
return mainWindow;
}
However when multiple windows are open they share cookies between them.
You can define a session (or partition) for BrowserWindow instances
Browser windows in different sessions don't share cookies, so you just have to define different session for each of your windows. Like
let counter = 0
function createWindow() {
let mainWindow = new BrowserWindow({
webPreferences: {
session: session.fromPartition(`${counter++}`)
}
})
return mainWindow;
}
or any more sophisticated way.

Sending a message to the parent window in Electron

I have a rendering process open a modal window
import { remote } from 'electron';
let currentWindow = remote.getCurrentWindow();
let modalWindow = new BrowserWindow({width:800, heigh:500, parent:currentWindow});
modalWindow.loadURL('views/second.html');
How can I pass a message from the modalWindow back to its parent?
You have to use ipc communication.
In the Main process:
ipcMain.on('asynchronous-message', (event, arg) => {
//manage data
})
And in your modalWindow:
ipcRenderer.send('asynchronous-message', message)
ipcMain doc
ipcRenderer doc

New Window Positioning in Electron

I need to know how to open new windows which is offset a little by the current window position (first window will be opened in the center)
My codes are as follows:
// index.js
const {app,BrowserWindow,Menu,MenuItem,dialog}=require('electron');
function window_open(path){
win = new BrowserWindow({show: false})
win.loadURL(path);
win.once('ready-to-show', () => {win.show()})
}
let win
app.on('ready',event=>{
'use strict';
window_open(`file://${__dirname}/index.html`)
});
This opens the initial window in the center. I am also passing this function in the new window command (cmd+n)
{
label: 'File',
submenu: [
{label: 'New Window', accelerator: 'CmdOrCtrl+N', click: () => (
window_open(`file://${__dirname}/index.html`))
},
The code works fine, except that every window is positioned the same, in the center. I would like each new windows to be offset a little.
What's the best way to achieve this?
I learned that I need these two things:
BrowserWindow.getFocusedWindow()
win.getPosition()
Combining with #pergy's response, I got the following code which finds the focused window if there is any and offsets a new window from its position, otherwise creates a new window in the center:
let win = null;
function window_open(path) {
const opts = { show: false };
if (BrowserWindow.getFocusedWindow()) {
current_win = BrowserWindow.getFocusedWindow();
const pos = current_win.getPosition();
Object.assign(opts, {
x: pos[0] + 22,
y: pos[1] + 22,
});
};
win = new BrowserWindow(opts);
win.loadURL(path);
win.once('ready-to-show', () => { win.show() });
};
app.once('ready', event => {
window_open(`file://${__dirname}/index.html`);
});
This does what I asked for in my original question, so I have decided to post this. However, I do feel that it is slow in spawning the new windows, so I won't mark this as an answer to see if there are faster approaches to this.
Update:
I have found out that waiting on 'ready-to-show' is what makes it slow, as it waits for the ready state. I have accepted this as the answer as I feel that the speed issue is dependent to the content and not the browser. Feel free to add comments on this as I am still open ears.
You can define the window's position in constructor option x and y. The currently active window's position can be retrieved with getPosition(), so you can define offset for the new window from that.
See this dummy app for example:
const { app, BrowserWindow } = require('electron')
let win = null
app.once('ready', () => {
const openWindow = () => {
const opts = {
show: false
}
if (win) {
const pos = win.getPosition()
Object.assign(opts, {
x: pos[0] + 10,
y: pos[1] + 10
})
}
win = new BrowserWindow(opts)
win.loadURL('http://google.com')
let thisWin = win
win.once('ready-to-show', () => {
thisWin.show()
})
}
setInterval(openWindow, 5000)
})

Define a global ready function for every page in WinJS

My WinJS app uses the single navigation model. There is some common code that I would like to apply to every page in the app. Instead of placing the code in each page's ready function, I would like to be able to able to define a "global" ready function that will be executed when a page's ready event is fired. Any ideas?
you can define a Mixin object with utility function used for all pages.
utils.js:
PageMixin = {
ready: function ready(element, options)
{
this.element = element;
this.options = options;
this.initialize();
this.onready();
},
initialize: function initialize()
{
// write common initialize code here
}
};
page.js:
var Page = WinJS.UI.Pages.define('/pages/mypage/page.html',
{
onready: function onready()
{
// page specific initialization code here
}
});
// this will make all PageMixin util methods available on Page.
WinJS.Class.mix(Page, PageMixin);
refer WinJS.Class.mixin for details.

Resources