New Window Positioning in Electron - position

I need to know how to open new windows which is offset a little by the current window position (first window will be opened in the center)
My codes are as follows:
// index.js
const {app,BrowserWindow,Menu,MenuItem,dialog}=require('electron');
function window_open(path){
win = new BrowserWindow({show: false})
win.loadURL(path);
win.once('ready-to-show', () => {win.show()})
}
let win
app.on('ready',event=>{
'use strict';
window_open(`file://${__dirname}/index.html`)
});
This opens the initial window in the center. I am also passing this function in the new window command (cmd+n)
{
label: 'File',
submenu: [
{label: 'New Window', accelerator: 'CmdOrCtrl+N', click: () => (
window_open(`file://${__dirname}/index.html`))
},
The code works fine, except that every window is positioned the same, in the center. I would like each new windows to be offset a little.
What's the best way to achieve this?

I learned that I need these two things:
BrowserWindow.getFocusedWindow()
win.getPosition()
Combining with #pergy's response, I got the following code which finds the focused window if there is any and offsets a new window from its position, otherwise creates a new window in the center:
let win = null;
function window_open(path) {
const opts = { show: false };
if (BrowserWindow.getFocusedWindow()) {
current_win = BrowserWindow.getFocusedWindow();
const pos = current_win.getPosition();
Object.assign(opts, {
x: pos[0] + 22,
y: pos[1] + 22,
});
};
win = new BrowserWindow(opts);
win.loadURL(path);
win.once('ready-to-show', () => { win.show() });
};
app.once('ready', event => {
window_open(`file://${__dirname}/index.html`);
});
This does what I asked for in my original question, so I have decided to post this. However, I do feel that it is slow in spawning the new windows, so I won't mark this as an answer to see if there are faster approaches to this.
Update:
I have found out that waiting on 'ready-to-show' is what makes it slow, as it waits for the ready state. I have accepted this as the answer as I feel that the speed issue is dependent to the content and not the browser. Feel free to add comments on this as I am still open ears.

You can define the window's position in constructor option x and y. The currently active window's position can be retrieved with getPosition(), so you can define offset for the new window from that.
See this dummy app for example:
const { app, BrowserWindow } = require('electron')
let win = null
app.once('ready', () => {
const openWindow = () => {
const opts = {
show: false
}
if (win) {
const pos = win.getPosition()
Object.assign(opts, {
x: pos[0] + 10,
y: pos[1] + 10
})
}
win = new BrowserWindow(opts)
win.loadURL('http://google.com')
let thisWin = win
win.once('ready-to-show', () => {
thisWin.show()
})
}
setInterval(openWindow, 5000)
})

Related

nodejs readline's cursor behavior and position

I have the following code
const readline = require('readline');
const {stdin, stderr} = process;
const rl = readline.createInterface({
output: stderr,
input: stdin
})
console.log(rl.getCursorPos());
let i = 5;
while (i > 0) {
console.log('fill up with logs');
i--
}
console.log(rl.getCursorPos())
and its output
{ cols: 2, rows: 0 }
fill up with logs
fill up with logs
fill up with logs
fill up with logs
{ cols: 2, rows: 0 }
as from above the last 'getCursorPos()' should return a new position since the stderr output has been filled up with logs, instead, it returns its default value, did I misunderstand the way it works?
or is there anyway I can get cursor position and save it multiple times using readline? I've looked through using asni escape, but it seems like it can only store one cursor position at a time.
The position returned by readline is relative to the current cursor location, not absolute on the screen.
I was able to create a promise to get this information using the answer below containing the escape sequence for requesting terminal cursor position:
How can I get position of cursor in terminal?
const getCursorPos = () => new Promise((resolve) => {
const termcodes = { cursorGetPosition: '\u001b[6n' };
process.stdin.setEncoding('utf8');
process.stdin.setRawMode(true);
const readfx = function () {
const buf = process.stdin.read();
const str = JSON.stringify(buf); // "\u001b[9;1R"
const regex = /\[(.*)/g;
const xy = regex.exec(str)[0].replace(/\[|R"/g, '').split(';');
const pos = { rows: xy[0], cols: xy[1] };
process.stdin.setRawMode(false);
resolve(pos);
}
process.stdin.once('readable', readfx);
process.stdout.write(termcodes.cursorGetPosition);
})
const AppMain = async function () {
process.stdout.write('HELLO');
const pos = await getCursorPos();
process.stdout.write("\n");
console.log({ pos });
}
AppMain();

How do you get the current terminal cursor position?

I can determine the terminal window size with process.stdout.columns, process.stdout.rows, and can recalculate my positioning with the resize event.
I am struggling to find out how to get my current cursor position for doing something like updating a specific location on my terminal, then returning to the previous location.
Does Node offer something like process.stdeout.x, process.stdeout.y to tell me where I currently am?
I realise I there are some Linux specific work arounds, but is there something offered by Node that allows for this functionality in a cross platform way?
The position returned by readline is relative to the current cursor location, not absolute on the screen.
I was able to create a promise to get this information using the answer below containing the escape sequence for requesting terminal cursor position:
How can I get position of cursor in terminal?
const getCursorPos = () => new Promise((resolve) => {
const termcodes = { cursorGetPosition: '\u001b[6n' };
process.stdin.setEncoding('utf8');
process.stdin.setRawMode(true);
const readfx = function () {
const buf = process.stdin.read();
const str = JSON.stringify(buf); // "\u001b[9;1R"
const regex = /\[(.*)/g;
const xy = regex.exec(str)[0].replace(/\[|R"/g, '').split(';');
const pos = { rows: xy[0], cols: xy[1] };
process.stdin.setRawMode(false);
resolve(pos);
}
process.stdin.once('readable', readfx);
process.stdout.write(termcodes.cursorGetPosition);
})
const AppMain = async function () {
process.stdout.write('HELLO');
const pos = await getCursorPos();
process.stdout.write("\n");
console.log({ pos });
}
AppMain();

gjs/gnome-shell-extension: Updating button text every 60 seconds

I want to write a simple gnome extension that prints some text on my top bar from a text file. I managed to print the text but i'm having trouble with updating it every 60 seconds. Is it even possible with gjs?
this is what i came up with:
const {St, Clutter} = imports.gi;
const Main = imports.ui.main;
const GLib = imports.gi.GLib;
let panelButton;
function init () {
// Create a Button with "Hello World" text
panelButton = new St.Bin({
style_class : "panel-button",
});
let fileContents = String(GLib.file_get_contents("path/to/myfile.txt")[1]);
let panelButtonText = new St.Label({
text : fileContents,
y_align: Clutter.ActorAlign.CENTER,
});
panelButton.set_child(panelButtonText);
}
function enable () {
// Add the button to the panel
Main.panel._centerBox.insert_child_at_index(panelButton, 2);
}
function disable () {
// Remove the added button from panel
Main.panel._centerBox.remove_child(panelButton);
}
You'll need to use GLib.timeout_add_seconds():
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 60, () => {
updateLabel(newText);
return GLib.SOURCE_CONTINUE;
});
By the way, you should probably use ByteArray.toString() to convert the Uint8Array that you get from the file into a string.
If you want to have your extension approved by ego you'd possibly want to do it more like this (destroy in disable what you create in enable):
in extension.js:
let timeout = null;
in function enable():
timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, (60 * 1000), () => {
// ...do the right thing...
return GLib.SOURCE_CONTINUE;
});
in function disable():
if (timeout) {
GLib.Source.remove(timeout);
timeout = null;
}

Why is the variable undefined? - Node - ElectronJs

I am creating an Electron app and I am trying to split my code in different scripts to make it more manageable; however, for some reason one of the variables in my script keeps returning undefined and I can't figure out why. I already checked similar questions here on SO, but did not find an answer.
I have a file called windowManipulation.js and this is part of it:
let signInWindow;
module.exports.createSignInWindow = () => {
signInWindow = new BrowserWindow({
show: false,
width: 1500,
height: 800,
webPreferences: {
nodeIntegration: true
}
});
signInWindow.loadFile(`views/logIn.html`)
signInWindow.once("ready-to-show", () => {
signInWindow.show();
});
signInWindow.on("close", () => {
signInWindow = null;
});
signInWindow.on('crashed', () => {
app.relaunch();
app.exit(0);
})
}
module.exports.closeSignInWindow = () => {
signInWindow.close();
signInWindow = null;
}
Now, when I call the function to create the window it creates it without a problem. But when I call the function to close it, it says that signInWindow is undefined.
Why is it undefined if it was supposed to be set when the signInWindow was created? What am I doing wrong?
It sounds like createSignInWindow and closeSignInWindow are being called from different processes. Being different processes, they each their own memory, and each would execute this file independently. So if you create the window in the main process, and close it from the window process, the window process will not think the variable exists.
So it sounds like you need to use ipcRenderer to communicate from the render to the main process so that it can close the window for you.
It'd be something like:
// renderer
const { ipcRenderer } = require('electron')
ipcRenderer.send('close-signin')
// main
const { ipcMain } = require('electron')
ipcMain.on('close-signin', closeSignInWindow)

best way to change on input fields?

Am trying to create an extension that fill each input field(text,search,...) in any webpage with an icon when I click on it a drop down menu appears,
Just like Lazarus from recovery icon or the google search by voice icon,
I tried so many ways lately but nothing worked will :(
Am trying to find a way that is suitable for all fields whatever their shape or size
document.addEventListener('DOMContentLoaded', function () {
$(document).ready(function () {
var elements = $('input[type=text], input[type=search], input[type=textarea]');
for (var i = 0; i < elements.length; i++) {
var input = elements[i];
input.className = 'inputWithImge';
var oImg = document.createElement('img');
oImg.src = chrome.extension.getURL("list.png");
oImg.className = 'img';
}
$(document).ready(function () {
$(".inputWithImge").after(oImg);
$(".inputWithImge").each(function () {
$(this).add($(this).next()).wrapAll('<divclass="imageInputWrapper"></div>');
});
});
});
});

Resources