Electron.js How to minimize/close window to system tray and restore window back from tray?
Javascriptnode.jsElectronnw.jsJavascript Problem Overview
I want my Electron.js application to live on system tray and whenever the user wants to do something they can restore from the system tray do something and minimize/close it back to system tray. How do i do that?
I've seen the tray
section from the documentation but doesn't help much to achieve what i want.
Here is what i got so far on the main.js
file
var application = require('app'),
BrowserWindow = require('browser-window'),
Menu = require('menu'),
Tray = require('tray');
application.on('ready', function () {
var mainWindow = new BrowserWindow({
width: 650,
height: 450,
'min-width': 500,
'min-height': 200,
'accept-first-mouse': true,
// 'title-bar-style': 'hidden',
icon:'./icon.png'
});
mainWindow.loadUrl('file://' + __dirname + '/src/index.html');
mainWindow.on('closed', function () {
mainWindow = null;
});
mainWindow.setMenu(null);
var appIcon = null;
appIcon = new Tray('./icon-resized.png');
var contextMenu = Menu.buildFromTemplate([
{ label: 'Restore', type: 'radio' }
]);
appIcon.setToolTip('Electron.js App');
appIcon.setContextMenu(contextMenu);
});
UPDATE:
I found this menubar repo, but it won't work as expected on linux.
Javascript Solutions
Solution 1 - Javascript
I actually figured it out a long time ago but for folks who encounter the same problem here is one way you could achieve minimizing to tray
and restoring from tray
. The trick is to catch the close
and minimize
events.
var BrowserWindow = require('browser-window'),
var mainWindow = new BrowserWindow({
width: 850,
height: 450,
title: "TEST",
icon:'./icon.png'
});
mainWindow.on('minimize',function(event){
event.preventDefault();
mainWindow.hide();
});
mainWindow.on('close', function (event) {
if(!application.isQuiting){
event.preventDefault();
mainWindow.hide();
}
return false;
});
and restoring from Tray
var contextMenu = Menu.buildFromTemplate([
{ label: 'Show App', click: function(){
mainWindow.show();
} },
{ label: 'Quit', click: function(){
application.isQuiting = true;
application.quit();
} }
]);
Solution 2 - Javascript
Addition to above answers - isQuiting
flag is worth setting at app' before-quit
callback, too. This way the application will be closed properly if requested by the OS or user some other way, e.g. via Macos Dock taskbar' quit command. Complete Typescript-friendly snippet:
import {app, BrowserWindow, Tray, Menu} from 'electron';
import * as path from 'path';
let window;
let isQuiting;
let tray;
app.on('before-quit', function () {
isQuiting = true;
});
app.on('ready', () => {
tray = new Tray(path.join(__dirname, 'tray.png'));
tray.setContextMenu(Menu.buildFromTemplate([
{
label: 'Show App', click: function () {
window.show();
}
},
{
label: 'Quit', click: function () {
isQuiting = true;
app.quit();
}
}
]));
window = new BrowserWindow({
width: 850,
height: 450,
show: false,
});
window.on('close', function (event) {
if (!isQuiting) {
event.preventDefault();
window.hide();
event.returnValue = false;
}
});
});
Solution 3 - Javascript
I updated the code with a scenario if you want to show icon on your system tray all the time until you don't quit the application
var { app, BrowserWindow, Tray, Menu } = require('electron')
var path = require('path')
var url = require('url')
var iconpath = path.join(__dirname, 'user.ico') // path of y
var win
function createWindow() {
win = new BrowserWindow({ width: 600, height: 600, icon: iconpath })
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
}))
var appIcon = new Tray(iconpath)
var contextMenu = Menu.buildFromTemplate([
{
label: 'Show App', click: function () {
win.show()
}
},
{
label: 'Quit', click: function () {
app.isQuiting = true
app.quit()
}
}
])
appIcon.setContextMenu(contextMenu)
win.on('close', function (event) {
win = null
})
win.on('minimize', function (event) {
event.preventDefault()
win.hide()
})
win.on('show', function () {
appIcon.setHighlightMode('always')
})
}
app.on('ready', createWindow)
Solution 4 - Javascript
A better way than using flags and for those who do not want to change the minimize
behavior :
just normally hide the window on close
event using mainWindow.hide()
mainWindow.on('close', function (event) {
event.preventDefault();
mainWindow.hide();
});
then call mainWIndow.destroy()
to force close the window. It also guarantees to execute the closed
event handler.
From the documentation:
> Force closing the window, the unload and beforeunload event won't be emitted for the web page, and close event will also not be emitted for this window, but it guarantees the closed event will be emitted.
var contextMenu = Menu.buildFromTemplate([
{ label: 'Show App', click: function(){
mainWindow.show();
} },
{ label: 'Quit', click: function(){
mainWindow.destroy();
app.quit();
} }
]);
Solution 5 - Javascript
This was tagged with NW.js, and since all the other answers are for Electron I thought I'd show off how much easier everything always is in NW.js. There is a simple demo repo set up right here:
Just download that and run npm install && npm start
.
Solution 6 - Javascript
I share my Sketch, on minimize hide on taskbar icon, menu options rigth-click icon to restore/close. using websocket/http server..
//const {app, BrowserWindow} = require('electron');
const {app, BrowserWindow, Tray, Menu} = require('electron');
const myip = require('quick-local-ip');
const express = require('express');
const WebSocket = require('ws');
const bodyParser = require('body-parser');
const path = require('path')
// Config
const Config = {
http_port: '8080',
socket_port: '3030'
};
var iconpath = path.join(__dirname, 'rfid.png') // path of y
// Http server
const _app = express();
const server = require('http').Server(_app);
server.listen(Config.http_port);
// WSS server
const wss = new WebSocket.Server({port: Config.socket_port});
// Console print
console.log('[SERVER]: WebSocket on: ' + myip.getLocalIP4() + ':' + Config.socket_port); // print websocket ip address
console.log('[SERVER]: HTTP on: ' + myip.getLocalIP4() + ':' + Config.http_port); // print web server ip address
// 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 window;
let isQuiting;
let tray;
function createWindow() {
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
acceptFirstMouse: true,
autoHideMenuBar: false,
useContentSize: true,
});
var appIcon = new Tray(iconpath);
// mainWindow.loadURL('index.html')
mainWindow.loadURL('http://localhost:8080');
mainWindow.focus();
// mainWindow.setFullScreen(true);
// Open the DevTools.
mainWindow.webContents.openDevTools();
var contextMenu = Menu.buildFromTemplate([
{
label: 'Show App', click: function () {
mainWindow.show()
}
},
{
label: 'Quit', click: function () {
app.isQuiting = true
app.quit()
}
}
])
appIcon.setContextMenu(contextMenu)
// Emitted when the window is closed.
mainWindow.on('close', function (event) {
mainWindow = null
});
mainWindow.on('minimize', function (event) {
event.preventDefault()
mainWindow.hide()
});
mainWindow.on('show', function () {
appIcon.setHighlightMode('always')
})
}
app.on('ready', createWindow)
// 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()
}
})
/**
* EXPRESS
*/
_app.use(bodyParser.urlencoded({
extended: false
}));
_app.use('/assets', express.static(__dirname + '/www/assets'))
_app.get('/', function (req, res) {
res.sendFile(__dirname + '/www/index.html');
});
/**
* WEBSOCKET
*/
wss.getUniqueID = function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4();
};
wss.on('connection', function connection(ws, req) {
ws.id = wss.getUniqueID();
console.log('[SERVER]: Client Connected. ID=', ws.id);
ws.on('close', function close() {
console.log('[SERVER]: Client disconnected.');
});
ws.on('message', function incoming(recieveData) {
console.log('[SERVER] Message:', recieveData);
// Example use
// send(recieveData);
sendAll(recieveData);
});
// Send back to client
function send(data) {
data = JSON.stringify(data);
ws.send(data);
}
// Send to all clients
function sendAll(data) {
data = JSON.stringify(data);
wss.clients.forEach(function each(client) {
client.send(data);
});
}
});
Solution 7 - Javascript
Try minimize event instead of hide.
var BrowserWindow = require('browser-window'),
var mainWindow = new BrowserWindow({
width: 850,
height: 450,
title: "TEST",
icon:'./icon.png'
});
mainWindow.on('minimize',function(event){
event.preventDefault();
mainWindow.minimize();
});
mainWindow.on('close', function (event) {
event.preventDefault();
mainWindow.minimize();
return false;
});
This worked for me.
hide()
was closing the window.