How to detect system idle in Electron app and do something - javascript

I developed app and I want to make it if the user do nothing in 30 minutes close the app.
So I search it on google to solve this problem and I found that there is 'powerMonitor' API in electron but the problem is my app is old version (Electron 3.1.14) so it doesn't support various methods.
Electron powerMonitor API Docs
I think I should use powerMonitor.querySystemIdleTime() method and I tried to test 'pwoerMonitor' API so I paste code but
console.log(powerMonitor.querySystemIdleTime()) it returns this error message.
How can I detect system idle and do something in electron? Should I use another package?
import { app, dialog, Menu, Notification, Tray, ipcMain, powerMonitor } from 'electron'
import windowManager from 'electron-window-manager'
import schedule from 'node-schedule'
let mainWindow = null
let tray = null
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}
app.setAppUserModelId('Geomec Cloud Manager')
windowManager.init({
appBase: process.env.NODE_ENV === 'production'
? `file://${__dirname}`
: 'http://localhost:9080'
})
if (isSecondInstance) {
app.quit()
} else {
app.on('second-instance', () => {
if (mainWindow) {
mainWindow.object.show()
mainWindow.object.focus()
}
})
/* Main Window */
app.on('ready', () => {
mainWindow = windowManager.createNew('main-window', '', '/index.html', null, {
title: 'Geomec Cloud Manager',
height: 500,
width: 500,
useContentSize: true,
frame: false,
maximizable: false,
minimizable: false,
resizable: false
}).create()
console.log(powerMonitor.querySystemIdleTime()) // I thought it returns idle time
if (!process.argv.includes('--systray')) {
mainWindow.object.once('ready-to-show', () => {
mainWindow.object.show()
})
}
tray = new Tray(__static + '/tray-icon.ico')
const trayMenu = Menu.buildFromTemplate([{
label: '프로그램 정보',
click () {
const window = windowManager.createNew('about-window', '', '/index.html#about', null, {
height: 380,
width: 550,
useContentSize: true,
frame: false,
maximizable: false,
minimizable: false,
resizable: false,
modal: true,
parent: windowManager.get('main-window').object
}).create()
window.object.once('ready-to-show', () => {
window.object.show()
})
}
},
{
/* Tray 내부 프로그램 종료 함수 */
label: '프로그램 종료',
click () {
const notification = {
icon: __static + '/' + 'app-icon.png',
title: '네트워크 드라이브 연결이 해제되었습니다',
body: '프로그램을 종료합니다'
}
new Notification(notification).show()
mainWindow.object.webContents.send('terminate-child-processes')
ipcMain.on('child-processes-terminated', () => {
setTimeout(function () {
app.quit()
}, 5000)
})
}
}
])
tray.setToolTip('Geomec Cloud Manager')
tray.setContextMenu(trayMenu)
tray.on('click', () => {
mainWindow.object.show()
})
})
}

According to the docs the call is: powerMonitor.querySystemIdleTime(callback) and as the error message says, you are not giving the required argument.
Try changing:
console.log(powerMonitor.querySystemIdleTime())
to:
powerMonitor.querySystemIdleTime((idleSecs)=>{
console.log(`The system has been idle for ${idleSecs} seconds.`)
})
Based on your use case, it is actually powerMonitor.querySystemIdleState(idleThreshold, callback) you will want to be using, with idleThreshold set to 30 * 60.

Related

How to clean the heap memory used by Web Worker new operator when closing Electron child window?

I have created a createParentWindow that can invoke a createChildWindow and loads a separate html file. This createChildWindow loads my renderer.js and the renderer loads my webworker.js using Web Worker new operator for processing. Now, if I want to close the createChildWindow using close('X') button,
Does this introduce a memory leak?
Will the object created on the heap be cleaned automatically?
If there is a memory leak, how can I call my worker.terminate() to terminate my worker when the createChildWindow close('X') button is clicked?
Preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('windowExec', {
ExecFunct: () => ipcRenderer.send('asynchronous-message', 'OpenChildWindow')
})
Renderer.js
var worker = new Worker('./worker.js');
worker.addEventListener('message', function(e)
{
//..... code here
}, false);
// Stop the web worker.
function stop() {
console.log('Worker Terminated.');
worker.terminate();
worker = undefined;
}
Worker.js
const {datadecider,getosname} = require("./DatabaseWalker.node");
self.addEventListener('message', function(e)
{
var data = e.data;
switch (data.cmd)
{
case 'datadecider':
self.postMessage(datadecider(data.firstParam, data.secondParam));
break;
case 'getosname':
self.postMessage( "getosname," + getosname());
break;
case 'stop':
self.postMessage('WORKER STOPPED: ' + data.msg +
'. (buttons will no longer work)');
self.close(); // Terminates our worker.
break;
default:
self.postMessage('Unknown command: ' + data.msg);
};
}, false);
Main.js
// Create the browser child window.
function createChildWindow ()
{
singleTon = true;
datatableWindow = new BrowserWindow({
width: 1400,
height: 900,
title: 'Database',
icon: path.join(__dirname, './images/doc.ico'),
parent: parentWindow,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
nodeIntegrationInWorker: true,
enableRemoteModule: true,
contextIsolation: true
}
})
datatableWindow.loadFile('datatable.html')
datatableWindow.on('closed', function(){ // When the child windows is closed, set this to false.
singleTon = false;
datatableWindow = null;
//datatableWindow.webContents.send('destroy_childwindow', 'closed.');
console.log("Deleted datatableWindow.");
})
}
app.whenReady().then(() => {
createParentWindow()
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)
{
createParentWindow()
}
});
// Call the child windows when button was clicked from main renderer.
ipcMain.on('asynchronous-message', function (evt, message) {
console.log(message + " - " + singleTon);
if (message == 'OpenChildWindow' && singleTon == false)
{
createChildWindow();
}
else{
console.log("Child window is already running.");
}
})
})
// Create the browser parent window.
function createParentWindow ()
{
RunShellCommand(); // Get the OS distro name.
const parentWindow = new BrowserWindow({
width: 800,
height: 500,
title: 'Database Utility Launcher',
icon: path.join(__dirname, './images/doc.ico'),
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
nodeIntegrationInWorker: true,
enableRemoteModule: true,
contextIsolation: true
},
resizable: false
})
parentWindow.loadFile('parent.html') // Load the parent.html of the app.
parentWindow.on('closed', function(){ // Close all the window when the parent windows is closed.
app.quit();
})
}

Opening a file and clicking to a button from Touch Bar in electron.js

I implemented a touch bar button to my program which loads a file. My question is: How can I click to a specific button on the website after that page has loaded when I press the touch bar button? Here is my main.js file:
const { app, BrowserWindow, TouchBar } = require('electron')
const { TouchBarButton } = TouchBar
const path = require('path')
let window
function createWindow() {
const win = new BrowserWindow({
width: 1366,
height: 758,
minWidth: 1300,
minHeight: 700,
icon: __dirname + 'logoSquare.icns',
webPreferences: {
//preload: path.join(__dirname, 'preload.js')
}
})
win.loadFile('login.html')
win.maximize()
return win
}
app.whenReady().then(() => {
window = createWindow()
const button = new TouchBarButton({
label: `🛫 Add Flight`,
accessibilityLabel: 'Add Flight',
backgroundColor: '#a20021',
click: () => {
window.loadFile('./flights.html')
},
});
const touchBar = new TouchBar({
items: [
button,
],
})
window.setTouchBar(touchBar);
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
I have just started learning electron.js and couldn't find a solution yet.
I found an alternate way to solve this issue. I sent a query and got that information with JavaScript. This is the main.js file that is responsible for sending the query:
const button = new TouchBarButton({
label: `🛫 Add Flight`,
accessibilityLabel: 'Add Flight',
backgroundColor: '#3a2e39',
click: () => {
//window.loadFile('./flights.html?addflight=1')
window.loadURL('file://'+__dirname+'/flights.html?addflight=1')
},
})
And this is the code that is responsible for receiving data in the flights.html file with JavaScript:
function addFlightRedir() {
if (location.search == '?addflight=1') {
addNewFlight(); // This is the code that I wanted to execute
}
}
addFlightRedir();
And since it is reusable with standard JS, now I can implement it to the other areas of my program as well (independent from the Touch Bar buttons).

win.reload showing showing blank white window in electron

I need to reload my site/app after network re-connect. So, I'm using win.reload after reconnect but after reloading it shows me a blank white screen
I have tried to re-create the window but it gives me the same output. Another question reported here by me.
I found window.location.href is set to "chrome-error://chromewebdata/" after reload
This sample code from is main.js
let mainWindow = null;
let offlineWindow = null;
let loadingwindow = null;
let mainWindowWidth = 1100;
let mainWindowHeight = 650;
var nativeApp = {
appUrl: "https://google.com",
connected: false
}
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
webPreferences: {
nodeIntegration: false,
preload: path.join(app.getAppPath(), 'preload.js')
},
minWidth: mainWindowWidth,
width: mainWindowWidth,
minHeight: mainWindowHeight,
height: mainWindowHeight,
show: false
});
createLoadingWindow();
mainWindow.once('ready-to-show', () => {
closeLoadingWindow();
mainWindow.show();
});
mainWindow.setMenu(null);
mainWindow.loadURL(nativeApp.appUrl);
mainWindow.webContents.openDevTools();
}
function createLoadingWindow(){
// codes to create the loading window
// .....
}
function createOfflineWindow(){
// codes to create the offline window
//....
}
function checkAndConnect() {
checkInternet(function (connected) {
if (!connected) {
if (!offlineWindow) { createOfflineWindow(); }
} else {
if (offlineWindow) {
offlineWindow.close();
mainWindow.reload();
}
}
nativeApp.connected = connected;
});
}
function checkInternet(callback) {
if(navigator.onLine){
return callback(true);
}
return callback(false);
}
I need to reload my site/app after re-connection. Is there anything wrong in my code? or is it a bug by the electron?
It's an old thread, but if someone comes across the same problem, you can fix it by adding the following in the main js file:
function createMainWindow () {
mainWindow = new BrowserWindow({
width: 1280,
height: 720,
...
})
// This code block is not related to the issue
// I included it to demostrate how my app loads the index page
if (process.env.WEBPACK_DEV_SERVER_URL) {
if (!process.env.IS_TEST) {
mainWindow.webContents.openDevTools()
}
}
else {
createProtocol('app')
mainWindow.loadURL('app://./index.html')
}
// Create listener that will handle the white screen issue
mainWindow.webContents.on('did-fail-load', () => {
if (process.env.NODE_ENV === 'production') {
// Load the index URL the same way you load it above
mainWindow.loadURL('app://./index.html')
}
})
...

how to set windows thumbnail toolbar in electron application

I am trying to add thumbnail toolbar with specified buttons in a taskbar layout of an application from it's doc. But it's showing some problem.
The main.js:
// Modules to control application life and create native browser window
const {app, BrowserWindow, ipcMain, dialog} = require('electron')
const path = require('path')
// 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;
const isSecondInstance = app.makeSingleInstance((commandLine, workingDirectory) => {
if (mainWindow) {
if (mainWindow.isMinimized()) mainWindow.restore()
mainWindow.focus()
}
})
if (isSecondInstance) {
app.quit();
}
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
show: false,
width: 500,
height: 200,
minWidth: 500,
minHeight: 200,
transparent: true,
frame: false,
})
mainWindow.setResizable(false)
// and load the index.html of the app.
mainWindow.loadFile('index.html')
// Open the DevTools.
// mainWindow.webContents.openDevTools()
mainWindow.once('ready-to-show', () => {
mainWindow.show()
mainWindow.focus()
})
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// 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)
// 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()
}
})
// 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.
ipcMain.on('open-information-dialog', (event) => {
if (mainWindow) {
const options = {
type: 'info',
title: 'I am abled',
buttons: ['Ok'],
message: 'This is the way.'
}
dialog.showMessageBox(mainWindow, options, function () {})
}
})
ipcMain.on('close', (event) => {
app.quit()
})
ipcMain.on('minimize', (event) => {
mainWindow.minimize()
})
ipcMain.on('progress', (event, per) => {
mainWindow.setProgressBar(per)
})
mainWindow.setThumbarButtons([
{
tooltip: 'button1',
icon: path.join(__dirname, 'button1.png'),
click () { console.log('button1 clicked') }
}, {
tooltip: 'button2',
icon: path.join(__dirname, 'button2.png'),
flags: ['enabled', 'dismissonclick'],
click () { console.log('button2 clicked.') }
}
])
The error:
All of my mainWindow reference working fine but when I am trying to set thumbar buttons with setThumbarButtons() it's getting the problem. I just try this one and I don't get any error but it's not showing any buttons on taskber window,
The Code:
app.on('ready', function(){
console.log(mainWindow)
mainWindow.setThumbarButtons([
{
tooltip: 'button1',
icon: path.join(__dirname, 'start.png'),
click () { console.log('button1 clicked') }
}
])
})
I can't make any sense with this problem.
The problem is that when you run mainWindow.setThumbarButtons your window hasn't been created. Therefor mainWindow is undefined. Which is the error you are running into, and what it says in the error screenshot you posted.
Currently you are creating and setting your window in the createWindow function.
If you move your setThumbarButtons code into the createWindow function it should work.
Something like the following:
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
show: false,
width: 500,
height: 200,
minWidth: 500,
minHeight: 200,
transparent: true,
frame: false,
})
mainWindow.setResizable(false)
// and load the index.html of the app.
mainWindow.loadFile('index.html')
mainWindow.setThumbarButtons([
{
tooltip: 'button1',
icon: path.join(__dirname, 'start.png'),
click () { console.log('button1 clicked') }
}
])
// Open the DevTools.
// mainWindow.webContents.openDevTools()
mainWindow.once('ready-to-show', () => {
mainWindow.show()
mainWindow.focus()
})
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
That way you are creating the mainWindow first and defining it before calling that function. Otherwise mainWindow will be undefined which is what you were experiencing.

How to print html/text file using electron webContents.print([options], [callback])?

Electron Version : 2.0.7
Operating System : Ubuntu 16.04
Node Version : 8.11.1
electron.js
let win = new BrowserWindow({width: 302, height: 793,show:false});
win.once('ready-to-show', () => win.hide());
fs.writeFile(path.join(__dirname,'/print.txt'), "Test Print From the app",function(){
win.loadURL(`file://${path.join(__dirname,'/print.txt')}`);
win.webContents.on('did-finish-load', () => {
let printersInfo = win.webContents.getPrinters();
let printer = printersInfo.filter(printer => printer.isDefault === true)[0];
win.webContents.print({silent: true, printBackground: true, deviceName : printer.name},() => {
win = null;
});
});
})
win.webContents.print(silent: true, printBackground: true, deviceName : "POS-1") yields unusual data like the below image:
win.webContents.print(silent: false, printBackground: true, deviceName : "POS-1") yields unusual data and overlapping the file text like the below image:
i also tried for html file but it also yields the same output.
if i write it with silent : true and without the deviceName then it's yields nothing..
let win = new BrowserWindow({show:false});
win.once('ready-to-show', () => win.hide());
win.loadURL(`file://${path.join(__dirname,'/hello.html')}`);
win.webContents.on('did-finish-load', () => {
win.webContents.print({silent: true});
});
if i write it with the deviceName then it's yields the same output
which i have shown in the picture above.
let win = new BrowserWindow({show:false});
win.once('ready-to-show', () => win.hide());
win.loadURL(`file://${path.join(__dirname,'/hello.html')}`);
win.webContents.on('did-finish-load', () => {
let printersInfo = win.webContents.getPrinters();
let printer = printersInfo.filter(printer => printer.isDefault === true)[0];
win.webContents.print({silent: true, deviceName : printer.name});
});
How to reproduce
silent = true
win.webContents.print({
silent: true,
printBackground: false,
deviceName: 'POS-1'
});
silent = false
win.webContents.print({
silent: false,
printBackground: false,
deviceName: 'POS-1'
});
Even in electron 11.0, I faced this issue while printing HTML template. And found the solution. The problem is margin of the page. I added margin-top for my header content and now its printing correctly without unusual data.
Main.js
ipcMain.on('print', (event, arg) => {
let win = new BrowserWindow({ width: 302, height: 793, show: false });
win.once('ready-to-show', () => win.hide());
fs.writeFile(path.join(__dirname, '/printme.html'), arg, function () {
win.loadURL(`file://${path.join(__dirname, '/printme.html')}`);
win.webContents.on('did-finish-load', () => {
// Finding Default Printer name
let printersInfo = win.webContents.getPrinters();
let printer = printersInfo.filter(printer => printer.isDefault === true)[0];
const options = {
silent: true,
deviceName: printer.name,
pageSize: { height: 301000, width: 50000 }
}
win.webContents.print(options, () => {
win = null;
});
});
})
event.returnValue = true;
});
printme.html
<style type="text/css">
#content {
margin-top: 15px;
}
</style>
<div id="page-wrap">
<div id="content">
my header content
</div>
</div>

Categories