Electron: Close w X vs right click dock and quit - javascript

In my Electron app, I would like to do something that is done very often in other OSX apps. That is... I would like to NOT close the app of the red X is clicked in the top right. But, if they right click the app icon in the dock, and say Quit, then I would like to quit the app. How do I do this?
I have tried using the onbeforeunload event from the rendererProcess, as well as the browserWindow.on("close", fn) event to try and prevent this. The problem is that they both file the onbeforeunload event. And I can't tell the different between the red X being clicked and the dock icon being right clicked and told to quit. Any help would be nice. Has anyone else done this in Electron for OSX?

try this
if (process.platform === 'darwin') {
var forceQuit = false;
app.on('before-quit', function() {
forceQuit = true;
});
mainWindow.on('close', function(event) {
if (!forceQuit) {
event.preventDefault();
/*
* your process here
*/
}
});
}

This is the only answer that worked for me:
const electron = require('electron');
const app = electron.app;
let willQuitApp = false;
let window;
app.on('ready', () => {
window = new electron.BrowserWindow();
window.on('close', (e) => {
if (willQuitApp) {
/* the user tried to quit the app */
window = null;
} else {
/* the user only tried to close the window */
e.preventDefault();
window.hide();
}
});
window.loadURL('foobar'); /* load your page */
});
/* 'activate' is emitted when the user clicks the Dock icon (OS X) */
app.on('activate', () => window.show());
/* 'before-quit' is emitted when Electron receives
* the signal to exit and wants to start closing windows */
app.on('before-quit', () => willQuitApp = true);
via https://discuss.atom.io/t/how-to-catch-the-event-of-clicking-the-app-windows-close-button-in-electron-app/21425/8

After much looking, I found the following solution. When you right click on the dock and select Quit, before that fires the onbeforeunload in the rendererProcess, it will first fire the close event on the app itself. So, in the rendererProcess you have an onbeforeunload listener. And you tell that to return false always. Returning false from that event will prevent the window from unloading/closing ever. Then in your mainProcess you add app.on('close',fn) listener. That listener can send an event to the rendererProcess telling it to allow the close. Perhaps you can set a global allowClose = true or something. Then in your onbeforeunload, you add the logic to not return true if allowClose is true.

Take a look at the window-all-closed event of app in the main process. This event is typically used to quit the app on Linux and Windows but not on OS X (for an example, see Electron's Quick Start Tutorial). On OS X you should then probably also handle the activate event to open a new window if there is currently no window open.

Have a look at the electron quick start guide
Please notice the two below solutions needs to be implemented in main.js, and not on the JS executed on your html page.
Specific window close
If you want to execute code when a specific BrowserWindow is closed:
mainWindow.on('closed', function() {
// Your code to be executed before "really" stopping the app
});
All window close
If you want execute code when ALL the windows are closed (app API):
app.on('window-all-closed', function() {
// do stuff here
});

You need to handle this from your main.js file, by checking if it's a darwin platform, on window-all-closed event and re-create the window on activate event.
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', function () {
// On OS X 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();
}
});
More info/Example: https://github.com/atom/electron-quick-start/blob/master/main.js

This is how i solved it and this works perfectly.
import { app } from "electron";
let window: any;
let forceQuit = false;
app.on("ready", () => {
window = //YOUR BROWSER WINDOW
window.on("close", e => {
if (process.platform === "darwin" && forceQuit) {
window = null;
} else {
e.preventDefault();
app.hide();
}
});
app.on("activate", function() {
app.show();
});
app.on("before-quit", function(event) {
if (!forceQuit) {
event.preventDefault();
forceQuit = true;
app.quit();
}
});

Related

BeforeinstallPromt event fired still Add to home screen Prompt not working after setting any value in window.location

Add to Home Screen feature of google is not working after setting any value in window.location.
What has been done so far?
Refer : web-fundamentals-app-install-banners
During this implementation I am capturing the 'beforeInstallPromptEvent' of window and using it later whenever required.
PFB the Code Snippet for the same:
window.addEventListener('beforeinstallprompt', (e) => {
deferredPrompt = e;
// Update UI notify the user they can add to home screen
showInstallPromotion();
});
btnAdd.addEventListener('click', (e) => {
// hide our user interface that shows our A2HS button
btnAdd.style.display = 'none';
// Show the prompt
deferredPrompt.prompt();
// Wait for the user to respond to the prompt
deferredPrompt.userChoice
.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('User accepted the A2HS prompt');
} else {
console.log('User dismissed the A2HS prompt');
}
deferredPrompt = null;
});
});
This above code works perfectly in normal journey but it stopworking as soon as I include something in window.location to go to some app which in install in the device,
When the below code for Truecaller functionality is added in tandem with Add to Home Screen, it stops working:
window.location='xxxxxsdk://some-url/';
I have also tried with other options to redirect to app like location.assign() but still same issue.
Hi) try to put it after the app is installed:
window.addEventListener('appinstalled', function() {
// window.location = ...
});
Here is the doc: https://developer.mozilla.org/en-US/docs/Web/API/Window/appinstalled_event

I want the website inside the loadURL to go back when I press the backspace key

I'm writing an electron app. I used loadURL to show a website inside my app. I want the website inside the loadURL to go back when I press the backspace key. The Official documentary on loadURL was not helpful for me. How do I make the loadUrl content go back when the backspace is pressed,please?
You can use globalshortcuts and webContents.goBack( ) to do this.
For eg :
const { app, globalShortcut, BrowserWindow } = require('electron')
app.on('ready', () => {
let win = new BrowserWindow({ width: 800, height: 1500 })
win.loadURL('http://github.com')
let contents = win.webContents
// Register a 'backspace' shortcut listener.
const ret = globalShortcut.register('Backspace', () => {
console.log('Backspace is pressed');
contents.goBack();
})
if (!ret) {
console.log('registration failed')
}
// Check whether a shortcut is registered.
console.log(globalShortcut.isRegistered('Backspace'))
})
app.on('will-quit', () => {
// Unregister a shortcut.
globalShortcut.unregister('Backspace')
// Unregister all shortcuts.
globalShortcut.unregisterAll()
})

How to Disable keyboard shortcuts Alt + Tab in electron app on Windows 10?

I am working with Desktop Application, while I am working on Ubuntu server, I can block keyboard shortcuts: Alt+Tab fine, but when I'm moved to work on Windows OS and try to block Alt+Tab, it's not working. The most problems because of Alt keyboard, it's seriously didn't work on Windows 10 when I try to block it
Here is the code That I am using:
var shortcutsToCapture = ['Ctrl+Alt+Delete', 'Alt+F4','CommandOrControl+A','Super+Alt+Tab','CommandOrControl+Shift+I', 'CommandOrControl+R']
// this should be placed at top of main.js to handle setup events quickly
if (handleSquirrelEvent(app)) {
// squirrel event handled and app will exit in 1000ms, so don't do anything else
return;
}
app.on('ready', function () {
captureShortcuts(shortcutsToCapture)
})
function captureShortcuts(shortcuts) {
shortcuts.forEach(function (shortcut) {
registerShortcutCapturing(shortcut)
})
}
function registerShortcutCapturing(shortcut) {
var result = globalShortcut.register(shortcut, function () {
console.log('<' + shortcut + '> captured!')
})
if (!result) {
console.log('<' + shortcut + '> registration failed!')
}
}
app.on('will-quit', () => {
// Unregister a shortcut.
globalShortcut.unregister('CommandOrControl+X')
// Unregister all shortcuts.
globalShortcut.unregisterAll()
})
You can use the globalShortcut module to detect keyboard events even when the application does not have keyboard focus.
const { app, globalShortcut } = require('electron')
app.on('ready', () => {
globalShortcut.register('alt+tab', () => {
return false
})
})
hope this helps

Only hide the window when closing it [Electron]

I try to hide my main window so that I hasn't to load again later.
I got the following code:
function createWindow () {
// Create the browser window.
win = new BrowserWindow({width: 800, height: 600})
// Emitted when the window is closed.
win.on('closed', (event) => {
//win = null
console.log(event);
event.preventDefault();
win.hide();
})
}
So that's not working for me, when I close the window I get this error message:
Can somebody help me? Line 37 is the line with win.hide()
Thank you!
Use the close event instead of the closed event.
When the closed event is fired the window is already closed.
When the close event is fired the window is still open and you can prevent it from closing by using event.preventDefault(); like this:
win.on('close', function (evt) {
evt.preventDefault();
});
However on MacOS that'll stop you from quitting your app. To allow quitting your app and preventing windows from closing use this code:
// Set a variable when the app is quitting.
var isAppQuitting = false;
app.on('before-quit', function (evt) {
isAppQuitting = true;
});
win.on('close', function (evt) {
if (!isAppQuitting) {
evt.preventDefault();
}
});
That'll only stop the window from closing if the app isn't quitting.

Prompt to save / quit before closing window

I am making a writing application. Users can open the app, write some text, save their work, etc.
I am trying to make it so that clicking the window close button will prompt the user to (a) save their work (if necessary) or (b) just quit.
I am trying to use window.beforeunload to achieve this, but find I am getting stuck in a loop, where trying to "quit" makes the same prompt appear ad infinitum.
Here's some code:
windowCloseCheck() {
window.onbeforeunload = function(e) {
e.returnValue = false;
// window.alert('try to close me');
if(file.isUnsaved() || file.hasChanged()) {
// prompt - save or just quit?
file.fileWarning('You have unsaveeed work.', 'Save', 'Quit', function(){
// OPTION A - save
file.save();
}, function() {
// OPTION B: Quit.
ipcRenderer.send('quitter')
})
}
else {
// file is saved and no new work has been done:
ipcRenderer.send('quitter')
}
windowCloseCheck is invoked when the application is setup, initiating an event listener for closing the window. My conditional is checking if the file is unsaved or has changed from the original.
fileWarning is a function that just wraps the electron dialog box, making a pop up appear with two choices and respective functions to call for each choice.
The rest of the code is available if I'm (probably) leaving out necessary information. Would be happy to clarify if I'm not being very clear.
Please add following block inside the function where you have defined browser window(In my case it's createWindow() function declared in main.js)
// Create the browser window.
mainWindow = new BrowserWindow({width: 400, height: 400})
mainWindow.on('close', function(e){
var choice = require('electron').dialog.showMessageBox(this,
{
type: 'question',
buttons: ['Yes', 'No'],
title: 'Confirm',
message: 'Are you sure you want to quit?'
});
if(choice == 1){
e.preventDefault();
}
});
Answer for Electron 7+
The following is a working solution for latest Electron, based on awijeet's answer and Sergio Mazzoleni's comment.
At the bottom of createWindow(), below your win = new BrowserWindow(...), use:
win.on('close', function(e) {
const choice = require('electron').dialog.showMessageBoxSync(this,
{
type: 'question',
buttons: ['Yes', 'No'],
title: 'Confirm',
message: 'Are you sure you want to quit?'
});
if (choice === 1) {
e.preventDefault();
}
});
I ended up going with using window.destroy() to smash the render process to bits (from the main process):
ipcMain.on('quitter', (e) => {
mainWindow.destroy(); // necessary to bypass the repeat-quit-check in the render process.
app.quit()
})
Not really sure if this is recommended as there seem to be better ways to properly quit an electron app. Still happy to get any feedback if you know a better answer!
/shrug!
// Create the browser window.
mainWindow = new BrowserWindow({width: 400, height: 400})
mainWindow.on('close', function(e){
e.preventDefault();
var choice = require('electron').dialog.showMessageBox(mainWindow,
{
type: 'question',
buttons: ['Yes', 'No'],
title: 'Confirm',
message: 'Are you sure you want to quit?'
});
choice.then(function(res){
// 0 for Yes
if(res.response== 0){
// Your Code
}
// 1 for No
if(res.response== 1){
// Your Code
}
}
});
Notice that dialog.showMessageBox Returns Promise<Object> According to Electron Doc
And change this to mainWindow
This is modified answer for original answer to Awijeet
you can add a local variable to avoid mainWindow.destroy(), like:
let showExitPrompt = true;
// ask renderer process whether should close the app (mainWindow)
mainWindow.on('close', e => {
if (showExitPrompt) {
e.preventDefault(); // Prevents the window from closing
mainWindow.webContents.send('on-app-closing');
}
});
// renderer allows the app to close
ipcMain.on('quitter', (e) => {
showExitPrompt = false;
mainWindow.close();
})
Awijeet's solution is just perfect! Bth, thx Awijeet: it saved me hours! ;-)
In addition, if you need to go further, be aware e.preventDefault() is spreading everywhere in the code. Once you managed properly the preventDefault() you need to turn the variable e.defaultPrevented = false to get back to the natural behavior of your app.
Actually, it seems e.preventDefault() function is turnind the variable e.defaultPrevented to true until you change its value.
If the user would choose the save button, then we should save the data and close the window using window.close().
But, With this approach we will get an infinite loop that asks for saving the unsaved work because window.close() will emit window's close event again.
To solve this issue, we must declare a new boolean var forceQuit that initially set to false then we set it to true after saving the data or if the user decided to just close without saving the data.
import { app, BrowserWindow, dialog } from 'electron';
let win = null;
let forceQuit = false;
app.on('ready', () => {
win = new BrowserWindow({
// Your window options..
});
mainWindow.on('close', e => {
if (!forceQuit) {
const clickedButtonId = dialog.showMessageBox(mainWindow, {
type: 'warning',
buttons: ['Save', 'Cancel', `Don't save`],
cancelId: 1,
title: 'Confirm',
message: 'You have unsaved work!'
});
if (clickedButtonId === 0) {
e.preventDefault();
console.log('Saving...');
/** Here do your data saving logic */
forceQuit = true;
win.close();
} else if (clickedButtonId === 1) {
e.preventDefault();
} else if (clickedButtonId === 2) {
forceQuit = true;
win.close();
}
}
});
});

Categories

Resources