How to implement background service using electron.
i'm having a trouble can anyone tell me how to start a background
service using electron which runs even after closing the app. i have
tried many solutions but all of them stop the service after closing
the app.
You can use tray. here is an example (source):
"use strict";
// [run the app]
// $ npm install electron
// $ ./node_modules/.bin/electron .
const {app, nativeImage, Tray, Menu, BrowserWindow} = require("electron");
let top = {}; // prevent gc to keep windows
app.once("ready", ev => {
top.win = new BrowserWindow({
width: 800, height: 600, center: true, minimizable: false, show: false,
webPreferences: {
nodeIntegration: false,
webSecurity: true,
sandbox: true,
},
});
top.win.loadURL("https://google.com/");
top.win.on("close", ev => {
//console.log(ev);
ev.sender.hide();
ev.preventDefault(); // prevent quit process
});
// empty image as transparent icon: it can click
// see: https://electron.atom.io/docs/api/tray/
top.tray = new Tray(nativeImage.createEmpty());
const menu = Menu.buildFromTemplate([
{label: "Actions", submenu: [
{label: "Open Google", click: (item, window, event) => {
//console.log(item, event);
top.win.show();
}},
]},
{type: "separator"},
{role: "quit"}, // "role": system prepared action menu
]);
top.tray.setToolTip("hello electrol");
//top.tray.setTitle("Tray Example"); // macOS only
top.tray.setContextMenu(menu);
// Option: some animated web site to tray icon image
// see: https://electron.atom.io/docs/tutorial/offscreen-rendering/
top.icons = new BrowserWindow({
show: false, webPreferences: {offscreen: true}});
top.icons.loadURL("https://trends.google.com/trends/hottrends/visualize");
top.icons.webContents.on("paint", (event, dirty, image) => {
if (top.tray) top.tray.setImage(image.resize({width: 16, height: 16}));
});
});
app.on("before-quit", ev => {
// BrowserWindow "close" event spawn after quit operation,
// it requires to clean up listeners for "close" event
top.win.removeAllListeners("close");
// release windows
top = null;
});
Yes, it is possible by using electron-process npm library.
ref :- https://www.npmjs.com/package/electron-process
First you will have to register the module which you want to run in background, just create simple background.html,
--background.html--
add below lines in script tag,
const background = require('electron-process').background;
background.registerModule(require('../main/snippets/SnippetsManager'));
In main process just create one browser window in which your background.html will run and keep it as hidden window,
--main.js--
app.once("ready", ev => {
service = new BrowserWindow({
width: 80, height: 60, center: true, minimizable: false, show: false,
webPreferences: {
nodeIntegration: false,
webSecurity: true,
sandbox: true,
},
});
service.loadURL("file://' + __dirname + '/background.html");
service.on("close", ev => {
ev.sender.hide();
ev.preventDefault(); // prevent quit process
});
});
Hope it helped,
Regards.
Electron is not designed to run in background. If you are closing
application then it will terminate all processes related with it.
Electron is only used to provide GUI layer. After all it is hybrid application and it doesn't interact with core OS services to live
itself like background service.
Apart from this there are two options:
If you write a service with something else, say a node or .net application, then you probably could use Electron to interact with that service (via bundled Node accessing Windows APIs).
Create feature like system tray. Minimise application to system tray.
Ref Link
Related
I'm trying to test drag and drop functionality on a React application using Cypress.
I monitored the dev tools event listener during my manual testing and can see 3 drag events: dragenter, dragover and drop.
DragOver contains the DataTransfer info of items and types. If I don't mock DT these values are missing when running my test, so I used Object.defineProperty to add them.
const dataTransfer = new DataTransfer();
Object.defineProperty(dataTransfer, 'items', {
value: [{
kind: 'string',
type: 'pinnable_chart',
}],
});
Object.defineProperty(dataTransfer, 'types', {
value: ['pinnable_chart'],
});
cy.wrap(subject.get(0))
.trigger('dragstart', 'center', {
force: true,
dataTransfer,
})
cy.wrap(target.get(0))
.trigger('dragenter', 'topRight', {
dataTransfer,
})
.trigger('dragover', 'topRight', {
dataTransfer,
})
.trigger('drop', 'topRight', {
force: true,
});
cy.wrap(subject.get(0)).trigger('dragend', 'center', {
dataTransfer,
force: true,
});
No dragging or dropping is happening with my code. In the screenshot you'll see the difference between manual test (on the left) and running via Cypress (on the right).
What am I missing to get these drag events to work?
I have a menu in my application that when you click on document properties another window pops up, but the application menu is also being inherited by this window, so you can open the document properties window from the document properties window. I just want to disable the menu for the document properties window,the only way I've been able to achieve this was by making the window frameless, but I still want the title bar to show, so that's not the solution I'm looking for.
I've tried using docProps.removeMenu(), docProps.setMenu(null), and even docProps.setApplicationMenu(null). I've moved it around, tried making docProps a global variable, nothing has worked.
This is my code:
//Create references for modules that require electron
const { app, BrowserWindow, Menu } = require('electron')
//Create a global reference for the main window
let mainWindow
function createWindow () {
//Create the browser window
mainWindow = new BrowserWindow({
minWidth: 300,
minHeight: 300,
backgroundColor: '#888888'
})
//Load the index.html file
mainWindow.loadFile('index.html')
//Reload the main window on resize
mainWindow.on('resize', function () {
mainWindow.reload()
})
}
function createAppMenu () {
//Create application menu template
const template = [
{
label: 'File',
submenu: [
{
label: 'Document Properties...',
click: function () {
docProps = new BrowserWindow({
width: 250,
height: 300,
resizable: false,
title: 'Document Properties'
})
//This isn't working and I'm not sure why
docProps.removeMenu()
}
}
]
},
{
label: 'Edit'
},
{
label: 'View'
},
{
label: 'Window'
},
{
label: 'Help'
}
]
//Build app menu from template
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
}
//Call the createWindow function once electron has finished initializing
app.on('ready', function () {
createWindow()
mainWindow.maximize()
createAppMenu()
})
You can see the entire project at https://github.com/Leglaine/ElectroText
The only error message I get is when I try to call docProps.setApplicationMenu(null), it says that setApplicationMenu cannot be called on docProps, but I didn't really expect that to work anyway. Thanks in advance for your help!
win.removeMenu() and win.setMenu(null) seem to be currently broken in Electron when you have already set an application menu via Menu.setApplicationMenu()
Try setting an empty menu like this
docProps.setMenu(Menu.buildFromTemplate([]))
I have a NWJS app that should run in system tray and only show main window if user requests it. So far I have this code to make it happen:
package.json:
{
"name": "helloworld",
"bg-script": "bg.js",
"main": "index.html"
}
in my index.html:
var win = nw.Window.get();
win.hide();
bg.js:
var tray = new nw.Tray({ icon: 'icon.png' });
var gui = require('nw.gui');
var menu = new nw.Menu();
menu.append(new nw.MenuItem({
label: 'Quit',
click() {
gui.App.closeAllWindows();
}
}));
tray.menu = menu;
The only issue is that a window flashes momentarily before disappearing. Is it possible to ensure it starts in hidden state instead of hiding it manually as I am doing?
Found the answer. Had to add to my package.json:
"window": {
"show": false
}
Ive searched everywhere on how to make the corners rounded of my browserWindow.
How can I achieve rounded corners?
I've tried making it transparent. But nothing works.
Hers my code:
/**
* we need to keep a global reference of the window object. If we don't, the
* window will be closed automatically when the js object is garbage collected
*/
let win
function createWindow () {
// Create the browser window.
win = new BrowserWindow({
width: 1800,
height: 1000,
frame: false,
transparent: true,
icon: __dirname + 'icon.png'
})
// and load the index.html of the app.
win.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
slashes: true
}))
// Open the DevTools.
win.webContents.openDevTools()
// Emitted when the window is closed.
win.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.
*/
win = null
})
}
For transparency try using the opacity property. The range is from 0 to 1
function createWindow () {
// Create the browser window.
win = new BrowserWindow({
width: 1800,
height: 1000,
frame: false,
radii: [5,5,5,5],
transparent: true,
icon: __dirname + 'icon.png'
})
I have the following problem. I've written a server and client scripts for node js that work as live collaboration code editing. 2 or more people can code in the same instance of CodeMirror editor. Until i have enabled autocomplete feature and auto closing brackets it was working perfect, but after i did it messed up the work. When you use autocomplete list or when bracket or tag will be closed by module not by you manually it will not be recognized as change. I have inspected an object that CodeMirror instance is returning and it doesnt contain change that have been done automatically. its not even strictly problem for node js beacuse if you want lets say, send changes to server via ajax and save in a file, it wont happen beacuse its not present in change object. Anyone had similiar problem and can help?
client code:
var appCM = CodeMirror.fromTextArea(document.getElementById('app-cm'), {
mode: 'text/html',
theme: "monokai",
styleActiveLine: true,
lineNumbers: true,
matchBrackets: true,
indentUnit: 4,
indentWithTabs: true,
autoCloseTags: true,
autoCloseBrackets: true,
matchTags: false,
extraKeys: {
"Ctrl-Space": "autocomplete",
"Ctrl-Q": function(appCM) {
appCM.foldCode(appCM.getCursor());
}
},
foldGutter: true,
gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
readOnly: access
});
appCM.on('change', function(i, op) {
socket.emit('change', op);
});
socket.on('change', function(data) {
appCM.replaceRange(data.text, data.from, data.to);
});
server code:
socket.on('change', function(op) {
if(op.origin === '+input' || op.origin === 'paste' || op.origin === '+delete') {
clients.forEach(function(client) {
if(client !== socket)
client.emit('change', op);
});
};
});
You are explicitly filtering out changes whose origin isn't one of input/paste/delete. Why are you doing that? You'll need to propagate all changes if you want peers to stay in sync.