@jitsi/electron-sdk
Version:
Utilities for jitsi-meet-electron project
247 lines (215 loc) • 7.42 kB
JavaScript
const Store = require('electron-store');
const electron = require('electron');
const os = require('os');
const log = require('@jitsi/logger');
const { SIZE, ASPECT_RATIO, STORAGE } = require('../constants');
/**
* Stores the current size of the AOT during the conference
* @type {{width: number, height: number}}
*/
let size = Object.assign({}, SIZE);
/**
* Keeps the old size of the window between resize handler calls
*/
let oldSize;
/**
* The logger instance
*/
let logger;
/**
* The electron-store instance to store last position of the aot window.
*/
const store = new Store();
/**
* Changes the window resize functionality to respect the passed aspect ratio.
*
* @param {BrowserWindow} win - The target window.
* @param {number} aspectRatio - The aspect ratio to be set.
* @returns {void}
*/
const setAspectRatioToResizeableWindow = (win, aspectRatio = ASPECT_RATIO) => {
//for macOS we use the built-in setAspectRatio on resize, for other we use custom implementation
if (os.type() === 'Darwin') {
win.setAspectRatio(aspectRatio);
win.on('resize', () => {
const [ width, height ] = win.getSize();
size.width = width;
size.height = height;
});
} else {
win.on('will-resize', (e, newBounds) => {
oldSize = win.getSize();
const mousePos = electron.screen.getCursorScreenPoint();
const windowBottomRightPos = {
x: newBounds.x + newBounds.width - 16,
y: newBounds.y + newBounds.height - 16,
};
//prevent resize from bottom right corner as it is buggy.
if (mousePos.x >= windowBottomRightPos.x && mousePos.y >= windowBottomRightPos.y) {
e.preventDefault();
}
});
win.on('resize', () => {
if (!Array.isArray(oldSize) || oldSize.length !== 2) {
// Adding this check because of reports for JS errors that oldSize is undefined.
return;
}
let [ width, height ] = win.getSize();
//we scale either width or height according to the other by checking which of the 2
//changed the most since last resize.
if (Math.abs(oldSize[0] - width) >= Math.abs(oldSize[1] - height)) {
height = Math.round(width / aspectRatio);
} else {
width = Math.round(height * aspectRatio);
}
win.setSize(width, height);
size.width = width;
size.height = height;
});
}
};
/**
* Calculates the coordinates for a window (based on its current coordinates and
* size) to place it in the boundaries of a given screen.
*
* @param {Rectangle} windowRectangle - The current position and dimensions of
* the window.
* @param {Rectangle} screenRectangle - The position and dimensions of the
* screen.
* @returns {Point} - The new coordinates for the window.
*
* NOTE: All x and y coordinates are representing the top-left corner of the
* window or screen.
*/
const positionWindowWithinScreenBoundaries = (windowRectangle, screenRectangle) => {
// The min value for y coordinate of the window in order to place it within
// the boundaries of the screen. This will be the use case where the top
// edge of the window is exactly on the top boundary of the screen.
const minY = screenRectangle.y;
// The min value for x coordinate of the window in order to place it within
// the boundaries of the screen. This will be the use case where the left
// edge of the window is exactly on the left boundary of the screen.
const minX = screenRectangle.x;
// The max value for y coordinate of the window in order to place it within
// the boundaries of the screen. This will be the use case where the bottom
// edge of the window is exactly on the bottom boundary of the screen.
const maxY
= screenRectangle.y + screenRectangle.height - windowRectangle.height;
// The max value for x coordinate of the window in order to place it within
// the boundaries of the screen. This will be the use case where the right
// edge of the window is exactly on the right boundary of the screen.
const maxX
= screenRectangle.x + screenRectangle.width - windowRectangle.width;
return {
x: Math.min(Math.max(windowRectangle.x, minX), maxX),
y: Math.min(Math.max(windowRectangle.y, minY), maxY)
};
};
const setLogger = loggerTransports => {
logger = log.getLogger('AOT', loggerTransports || []);
};
/**
* Wrapper over the loger's info
*
* @param {string} info - The info text
*/
const logInfo = info => {
if (!logger) {
return;
}
logger.info(`[MAIN] ${info}`);
};
/**
* Wrapper over the loger's error
*
* @param {Object} err - the error object
*/
const logError = err => {
if (!logger) {
return;
}
logger.error({ err }, '[MAIN ERROR]');
};
/**
* Returns the stored coordinates for the always on top window of its previous
* location or if the last location is unknown returns coordinates to display
* the window in the top right corner of the screen.
*
* @returns {{x: number, y: number}}
*/
const getPosition = () => {
const Screen = electron.screen;
const position = {
x: store.get(STORAGE.AOT_X),
y: store.get(STORAGE.AOT_Y)
};
if (typeof position.x === 'number' && typeof position.y === 'number') {
// Position the window within the screen boundaries. This is needed
// only for windows. On Mac and Linux it is working as expected without
// changing the coordinates.
if (os.platform() === 'win32') {
const windowRectangle = Object.assign({}, position, size);
const matchingScreen = Screen.getDisplayMatching(windowRectangle);
if (matchingScreen) {
return positionWindowWithinScreenBoundaries(
windowRectangle,
matchingScreen.workArea);
}
}
return position;
}
const {
x,
y,
width
} = Screen.getDisplayNearestPoint(Screen.getCursorScreenPoint()).workArea;
return {
x: x + width - size.width,
y
};
};
/**
* Saves window position
* @param {BrowserWindow} browserWindow - the aot window
*/
const savePosition = aotWindow => {
if (!windowExists(aotWindow)) {
return;
}
const [x, y] = aotWindow.getPosition();
store.set(STORAGE.AOT_X, x);
store.set(STORAGE.AOT_Y, y);
};
/**
* Gets the size to be set to the new AOT window.
* This is used in order to preserve the size on close and open of AOT during the same meeting
* @returns {{width: number, height: number}}
*/
const getSize = () => {
if (typeof size.width === 'number' && typeof size.height === 'number') {
return size;
}
return SIZE;
};
const resetSize = () => {
size = Object.assign({}, SIZE);
};
/**
* Checks whether the window exists
* @param {BrowserWindow} win
* @returns
*/
const windowExists = browserWindow => {
return browserWindow && !browserWindow.isDestroyed();
};
module.exports = {
getPosition,
getSize,
logError,
logInfo,
resetSize,
savePosition,
setAspectRatioToResizeableWindow,
setLogger,
windowExists,
};