How to disable fullscreen on electron window (linux) - electron

These are the only four attributes mentioned in docs.
(1) minimizable
(2) maximizable
(3) fullscreen
(4) fullscreenable
While former two specify that these aren't implemented on Linux, the latter two are for mac only.
So, how do I prevent user from making the window occupy full screen on Linux? And what's the point of having max height and max width properties then (I can't drag and resize beyond those but I can still maximize the window)?
Code:
const { app, BrowserWindow,Menu } = require('electron');
const path = require('path');
require('electron-reload')(__dirname, {
electron: path.join(__dirname,'..', 'node_modules', '.bin', 'electron')
});
// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
app.quit();
}
let mainWindow;
const createWindow = () => {
mainWindow = new BrowserWindow({
width: 550,
height: 500,
skipTaskbar: true,
maxWidth:1000,
maxHeight:800,
show:false,
fullscreenable:false,
fullscreen: false,
maximizable: false
});
mainWindow.loadURL({url});
mainWindow.once('ready-to-show', () => {
mainWindow.show()
})
mainWindow.on('closed', () => {
mainWindow = null;
});
};
app.on('ready', createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (mainWindow === null) {
createWindow();
}
});

Indeed, as said in the docs, maximizable has not been implemented in Linux.
I have not found a "proper" solution, but a work-around.
You should be able to listen to the maximize event, and then call the unmaximize method (I don't see any warning about this event or method about Linux so they should be available). So essentially you would "cancel" the maximizing.
mainWindow.on('maximize', () => {
mainWindow.unmaximize()
});

set resizable key to false:
mainWindow = new BrowserWindow({
resizable: false
});
This should disable the fullscreen button on the m

Related

How to make a splash screen on Electron?

I'm new to Electron and I joined an existing project. I'm trying to add an image before the main screen of the app that will last 5 seconds. At first, I tried it with useState and setTimeone but I've realized I'm in the wrong place of the code.
After reading all kinds of solutions, and running the app - I now need your help.
This is some of the code in my main.ts file:
mainWindow = new BrowserWindow({
show: false,
width: 521,
height: 712,
icon: getAssetPath('icon.png'),
webPreferences: {
nodeIntegration: true,
contextIsolation: true,
preload: app.isPackaged
? path.join(__dirname, 'preload.+212 662-122618 js')
: path.join(__dirname, '../../.erb/dll/preload.js'),
},
});
mainWindow.loadURL(resolveHtmlPath('index.html'));
mainWindow.on('ready-to-show', () => {
if (!mainWindow) {
throw new Error('"mainWindow" is not defined');
}
if (process.env.START_MINIMIZED) {
mainWindow.minimize();
} else {
mainWindow.show();
}
});
mainWindow.on('closed', () => {
mainWindow = null;
});
const menuBuilder = new MenuBuilder(mainWindow);
menuBuilder.buildMenu();
// Open urls in the user's browser
mainWindow.webContents.setWindowOpenHandler((edata) => {
shell.openExternal(edata.url);
return { action: 'deny' };
});
// Remove this if your app does not use auto updates
// eslint-disable-next-line
new AppUpdater();
};
/**
* Add event listeners...
*/
app.on('window-all-closed', () => {
// Respect the OSX convention of having the application in memory even
// after all windows have been closed
if (process.platform !== 'darwin') {
app.quit();
}
});
app
.whenReady()
.then(() => {
createWindow();
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) createWindow();
});
})
.catch(console.log);

Puppeteer in Electron: Error: Passed function is not well-serializable

Trying to come up with a GUI for Puppeteer project.
I thought about using Electron, but run into error:
Error: Passed function is not well-serializable!
when running Puppeteer functions like:
await page.waitForSelector('.modal', { visible: true });
I found a proper way to serialize when dealing with page.evaluate() but how to proceed in case of page.waitForSelector()?
Is there a work around for Puppeter's API functions to be properly serialized when required?
EDIT
I decided to rewrite
await page.waitForSelector('.modal', { visible: true });
using page.evaluate, here is the code:
// first recreate waitForSelector
const awaitSelector = async (selector) => {
return await new Promise(resolve => {
const selectorInterval = setInterval(() => {
if ($(selector).is(':visible')) {
console.log(`${selector} visible`);
resolve();
clearInterval(selectorInterval);
};
}, 1000);
});
}
and later call that function using page.evaluate():
// remember to pass over selector's name, in this case it is ".modal"
await page.evaluate('(' + awaitSelector.toString() + ')(".modal");');
Firstly context:
Generally you can not run puppeteer from browser environment, it works solely in nodejs. Electron provides 2 processes renderer and main. Whenever you want to use node you have to do it in main one.
About communication between both procesess you can read in docs, there are many ways of handling it. From what I know the best practice is to declare it in preload and use ipc bridge. Other solutions violate contextIsolation rule.
I was w wandering aound from one problem to another: like not serializable function, require not defined and many others.
Finally I rewrote everything from scratch and it works here's my solution:
main.js
const { app, BrowserWindow } = require('electron')
const path = require('path')
const { ipcMain } = require('electron');
const puppeteer = require("puppeteer");
function createWindow() {
// Create the browser window.
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: true,
},
})
ipcMain.handle('ping', async () => {
await checkPup()
})
async function checkPup() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://example.com');
page
.waitForSelector('h1', { visible: true })
.then(() => {
console.log('got it')
});
const [button] = await page.$x("//button[contains(., 'Create account')]");
if (button) {
console.log('button: ', button)
await button.click();
await page.screenshot({ path: 'tinder.png' });
const [button] = await page.$x("//button[contains(., 'Create account')]");
if (button) {
console.log('button: ', button)
await button.click();
await page.screenshot({ path: 'tinder.png' });
}
}
await browser.close();
}
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
}
// 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.whenReady().then(() => {
createWindow()
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
// Attach listener in the main process with the given ID
ipcMain.on('request-mainprocess-action', (event, arg) => {
// Displays the object sent from the renderer process:
//{
// message: "Hi",
// someData: "Let's go"
//}
console.log(
arg
);
});
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
preload.js
// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
const { contextBridge, ipcRenderer } = require('electron')
window.addEventListener('DOMContentLoaded', () => {
const replaceText = (selector, text) => {
const element = document.getElementById(selector)
if (element) element.innerText = text
}
for (const type of ['chrome', 'node', 'electron']) {
replaceText(`${type}-version`, process.versions[type])
}
})
contextBridge.exposeInMainWorld('versions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
ping: () => ipcRenderer.invoke('ping'),
// we can also expose variables, not just functions
})
renderer.js
const information = document.getElementById('info')
const btn = document.getElementById('btn')
information.innerText = `This app is using Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), and Electron (v${versions.electron()})`
btn.addEventListener('click', () => {
console.log('habad!!!!!')
func()
})
const func = async () => {
const response = await window.versions.ping()
information.innerText = response;
console.log(response) // prints out 'pong'
}
Sorry for a little bit of a mess I hope it will help someone maybe finding solutions to some other problems

How to make a dialog to block the BrowserWindow when open?

I call dialog.showOpenDialog() to find the path to the folder. But the problem is that this does not block the mainWindow. It is necessary that when the standard path selection GUI appears, the program continues to work only after the path selection is completed. Googled and realized that you need to use remote. But nothing happens.
I get:
Cannot destructure property dialog of 'undefined' or 'null'.
if from electron.remote take dialog.
I tried a lot of different things (and these are not all attempts, just what I remembered):
const { dialog } = require ('electron').remote;
var remote = electron.remote;
var dialog = remote.dialog;
const dialog = require ('electron').remote.dialog;
I tried to connect a lot and yet.
My main.js:
const url = require('url');
const path = require('path');
const {dialog} = electron.remote;
const {app, BrowserWindow, Menu} = electron;
app.on('ready', function () {
const {start_width, start_height} = electron.screen.getPrimaryDisplay().workAreaSize;
mainWindow = new BrowserWindow({
minWidth: 1250,
minHeight: 800,
height: start_height,
width: start_width,
center: true,
show: false,
});
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'templates/mainWindow.html'),
protocol: 'file:',
slashes: true
}));
mainWindow.on('closed', function () {
app.quit();
});
// mainWindow.webContents.openDevTools();
const mainMenu = Menu.buildFromTemplate(mainMenuTemplate);
Menu.setApplicationMenu(mainMenu);
mainWindow.maximize();
mainWindow.show();
});
function createAddWindow() {
addWindow = new BrowserWindow({
width: 300,
height: 200,
title: 'Add item'
});
addWindow.loadURL(url.format({
pathname: path.join(__dirname, 'templates/addWindow.html'),
protocol: 'file:',
slashes: true
}));
addWindow.on('close', function () {
addWindow = null;
})
}
const mainMenuTemplate = [
{
label: 'Analysis',
submenu: [{
label: 'Global search',
accelerator: 'Ctrl+O',
click() {
var path = createAddWindow();
console.log(path);
}
},
{
label: 'Search for a year',
accelerator: 'Ctrl+Alt+O',
click() {
console.log(folderSelect());//i need console.log (like the whole program) to continue to work after folderSelect returns some value.
}
},
{
label: 'Quit',
accelerator: process.platform == 'darwin' ? 'Command+Q' : 'Ctrl+Q',
click() {
app.quit();
}
},
]
}
];
function folderSelect() {
dialog.showOpenDialog({properties: ['openDirectory']}, function (path) {
console.log(path[0]);
if (path === undefined) {
return 'error';
}
else{
return path[0];
}
});
}
I need console.log (like the whole program) to continue to work after folderSelect returns some value.
For example, if I called the folderSelect function, you cannot interact with the program until the folder after selection window closes.
I saw a lot of similar questions on SO, but whatever I did nothing works.
In order to block the main window, you need to pass a BrowserWindow object to the dialog.showOpenDialog method as the first optional argument, the one you would like to attach the dialog to (mainWindow in your case I guess).
Quote from the docs:
dialog.showOpenDialog([browserWindow, ]options)
The browserWindow argument allows the dialog to attach itself to a
parent window, making it modal.
Now, how you make it happen is the whole different matter. It can be done in multiple ways, but if you are looking to invoke the dialog from renderer process the simplest one would be something like this:
import { remote } from 'electron'
remote.dialog.showOpenDialog(
remote.getCurrentWindow(), // <- notice this one
{ properties: ['openDirectory'] }
).then(result => {
// prefer promised API
})
The crucial part for whole thing to work properly is to have nodeIntegration enabled in your BrowserWindow options, which depending on a version of Electron you are using, you might or might not have (they've switched defaults from true to false in version 4). In any case it's better to have it set explicitly from now on. So that's how you would typically initiate your mainwindow now:
mainWindow = new BrowserWindow({
// ...
show: false,
webPreferences: {
nodeIntegration: true // <- this one
}
});

Opening new Window - Electron

I'm currently trying to implement a new Window on my Electron App.
So I want to include a button, and when you click on this Button, a new Window should be opened.
I didn't find anything in the Electron documentation, maybe one of you can help me.
Perhaps something like this:
const button = document.getElementById('<your_button_id>');
button.addEventListener('click', () => {
createBrowserWindow();
});
function createBrowserWindow() {
const remote = require('electron').remote;
const BrowserWindow = remote.BrowserWindow;
const win = new BrowserWindow({
height: 600,
width: 800
});
win.loadURL('<url>');
}
I believe the answer that has been taken as correct is outdated.
I have managed to do it with the ipc module and with the solution given by Nishkal.
Please, read the ipc module, I'm new to electron and not very experienced with programming. I'm sure you can come with better solutions.
Code I added in order for it to work:
my main.js
const {app, BrowserWindow} = require('electron');
const path = require('path');
//ipc
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
createWindow();
})
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
},
});
win.loadFile('index.html');
}
app.whenReady().then(() => {
createWindow();
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit();
})
my preload.js
window.addEventListener('DOMContentLoaded', () => {
const { ipcRenderer } = require('electron')
ipcRenderer.on('asynchronous-reply', (event, arg) => {
console.log(arg) // prints "pong"
})
//button and its event listener
const b1 = document.getElementById('b1');
b1.addEventListener('click', () => {
ipcRenderer.send('asynchronous-message', 'ping')
})
})
To open a window from the renderer:
window.open("https://github.com", "_blank", "top=500,left=200,frame=false,nodeIntegration=no");
https://www.electronjs.org/docs/latest/api/window-open

Change Windows Size in Electron

i'm very new to electron, but loving it. However, i am stuck on one thing, so after some guidance if possible.
i have a small test app, that i will be using for users to login in to a page.
in my main.js file i set the mainWindow properties as below:
function createWindow() {
mainWindow = new BrowserWindow({frame:false,
width: 1024,
height: 565,
minWidth: 1024,
minHeight: 565,
frame: false,
resizable: false,
show: false,
center: true,
backgroundColor: '#312450',
icon: path.join(__dirname, 'assets/icons/png/64x64.png')
})
mainWindow.loadURL(`file://${__dirname}/login.html`)
mainWindow.once('ready-to-show', () => {
mainWindow.show()
})
//mainWindow.webContents.openDevTools({detach: true})
mainWindow.on('closed', function() {
mainWindow = null
})
}
and then launch this in the app.on event.
This is all good so far.
I also add an eventlistener to a button in the login.html page as follows:
btnSignIn.addEventListener('click', function(){
const email = txtEmail.value;
const pass = txtPassword.value;
firebase.auth().signInWithEmailAndPassword(email, pass).then(function(){
document.location.href = 'loggedin.html';
}).catch(function(error){
if(error != null){
alert(error.message);
return;
}
})
},false);
This is all working perfectly well. The only issue i have is that i'd like the second page (loggedin.html) to be a different size.
I presume i have to change the mainWindow options specified previously, but i am unable to acheive it.
any pointers are greatly appreciated.
Regards
J
In your renderer process (js script loaded from login.html) you should be able to load Electron and Node modules.
const {ipcRenderer} = require('electron');
// Right after the line where you changed the document.location
ipcRenderer.send('resize-me-please')
In main.js
const {ipcMain} = require('electron')
ipcMain.on('resize-me-please', (event, arg) => {
mainWindow.setSize(width,height)
})
To add to Leonardo's answer, if your application may have multiple windows, you can resolve the sender window by pulling that from the IPC event, like so:
main.js
const {ipcMain} = require('electron')
ipcMain.on('resize-window', (event, width, height) => {
let browserWindow = BrowserWindow.fromWebContents(event.sender)
browserWindow.setSize(width,height)
})
Renderer
const {ipcRenderer} = require('electron');
// ...
ipcRenderer.send('resize-window', 1280, 720)

Resources