After participating in the activities in August, I felt empty. I had planned to have a good rest, but the activity of digging gold peripheral gifts was approved. This is really “people sitting at home, happy from heaven”.

I am honored to be one of the first batch of students and thank you for your community support!

In this activity, the author can get two gold digging badges, which will be sent to the friends who actively participate in the interaction through a lucky draw in the comments section, which is also a gift of flowers (~ ▽ ~)~*.

So, don’t forget to leave your insights in the comments section after reading this article, and you could be the winner!

preface

My generation code ape, is not doing demand is in the demand, let a person have to sigh: demand complex demand, demand how much!

However, the previously developed Electron client can basically meet the needs of the project, and I thought I could relax for a while. However, the client came up with another problem — the expansion screen needs to be supported.

Demand analysis

The so-called expanded screen is equivalent to copying a window from the main screen window and displaying it on other monitors besides the main screen. Besides some control functions (login, logout, split screen, switching services, etc.), the other functions are the same as the main screen window.

Since the role of our Electron client is to provide a shell that loads pages provided by other services, the only thing we need to consider here is window control, which is relatively simple.

The main points of the enumeration

Get all screen information

As soon as the program is started, the number of screens and their attributes should be obtained first:

const { screen } = require("electron");
// Store information about all connected monitors
let displaysMap = new Map(a);function getAllDisplays() {
    const allDisplays = screen.getAllDisplays();
    for (let i = 0; i < allDisplays.length; i++) {
        constdisplay = allDisplays[i]; displaysMap.set(display.id, display); }}function getBrowserOptsByDisplay(display) {
    const { bounds, workAreaSize } = display;
    const { x, y } = bounds;
    const { width, height } = workAreaSize;
    let isPrimary = false;
    if (display.id === screen.getPrimaryDisplay().id) {
        isPrimary = true;
    }
    return { x, y, width, height, isPrimary };
}

function getBrowserOpts() {
    let opts = [];
    const displays = displaysMap.values();
    for (const display of displays) {
        opts.push(getBrowserOptsByDisplay(display));
    }
    return opts;
}

screen.on("display-added".(event, newDisplay) = > {
    displaysMap.set(newDisplay.id, newDisplay);
    // Create window logic etc
});

screen.on("display-removed".(event, oldDisplay) = > {
    displaysMap.delete(oldDisplay.id);
    // Remove window logic
});
Copy the code

It’s important to note that the home screen is generally the first allDisplays by default, but there are exceptions, depending on how the display is plugged in. We can get the main screen object with screen.getPrimaryDisplay().

Create Windows based on the screen

Create corresponding Windows according to screen properties (mainly location and size), we set the window’s default setting to occupy the whole screen:

const { BrowserWindow } = require("electron");
const path = require("path");
let windowsMap = new Map(a);// Record the id of the main window
let masterWindowId = 0;

function createWindowByOpts(opts) {
    const customOpts = Object.assign(
        {
            title: "Window title".show: false.icon: path.join(process.cwd(), "./static/icon/icon.png"),
            webPreferences: {
                preload: path.join(__dirname, "./src/preload.js"),
                nodeIntegration: true.webSecurity: false
            }
        },
        opts
    );
    let win = new BrowserWindow(customOpts);
    if (opts.isMaster) {
        masterWindowId = win.id;
        win.once("ready-to-show".() = > {
            win.show();
        });
    }
    windowsMap.set(win.id, win);
}

function createWindows() {
    const allOpts = getBrowserOpts();
    for (const opts ofallOpts) { createWindowByOpts(opts); }}Copy the code

You might wonder, why do you have to size the window? If you do not set the size, when the window exits the full screen, the default size is 800 x 800, resulting in poor user experience.

Pass screen information to the renderer process

Because you split screens by clicking, the rendering process needs to know how many screens there are. Here we pass all screen information to the render process:

function sendAllScreensInfoToRender() {
    const masterWindow = windowsMap.get(masterWindowId);
    if(! masterWindow) {return false;
    }
    masterWindow.webContents.send("all-screens-info", displaysMap.values);
}
Copy the code

Since split-screen operations can only be performed on the home screen window, you only need to send a message to the corresponding render process on the home screen.

Sends window information to the renderer

We can send some key information about the window to its corresponding rendering process to reduce communication times:

function sendKeyInfoToRender(win) {
    const windowId = win.id;
    const isMaster = win.id === masterWindowId;
    const webContentsId = win.webContents.id;
    win.webContents.send("window-key-info", {windowId, isMaster, webContentsId});
}
Copy the code

Split screen Free login

The premise of split-screen execution is that you have logged in to the home screen successfully. For the convenience of users, you need to do not need to log in to the window that is separated from the home screen.

To implement the login-free function, the main window needs to send its login name and password to the split screen window when performing operations. The split screen performs a silent login based on the user name and password.

Separate the split screen from the main screen

Due to the limitation of authorized quota, one main window occupies one authorized quota, but the split screen does not occupy the authorized quota. Therefore, it is necessary to distinguish the main screen from the split screen.

Add an attribute is_master to the login and logout parameters, with a value of type bool indicating whether it is a request from the home screen window. After receiving the login request, the background determines:

  • If is_master is true, an authorization is assigned
  • Otherwise, no authorized occupation operation will be performed

The same is true for logout requests.

If the screen is hidden, the connection is disconnected

Because the data on the page is pushed up through a WS connection, each window needs to establish a WS connection.

In the beginning, I loaded the page when I created the window, whether the window was displayed or not, which was a bit of a waste of performance.

Now the solution is:

  • If the split screen operation is performed, a page is loaded and displayed in the corresponding window
  • If the split-screen window is closed, load it with a blank page file to disconnect the WS connection and render consumption

Send a logout request when uninstalling form content

Logout is performed when the page is refreshed or closed:

window.on("beforeunload".function () {
    const data = {username, userhandle, is_master};
    const path = "https://localhost:9001";
    window.navigator.sendBeacon(path, JSON.stringify(data));
})
Copy the code

Loading a blank page to a form can also trigger a form unload event.

TODO

The initial function of split screen has been achieved, and the following aspects of optimization are still needed.

Split screen display after service switchover

The current implementation is that all split screen Windows are hidden after each service switch, and you need to manually click the split screen again to load the display. The subsequent optimization scheme is as follows:

  • Records the id of the window being displayed
  • Hide all split screen Windows when switching services
  • After the service switchover is successful, the previously displayed window is reloaded and displayed according to the record

Processing after the main screen is off or removed

At present, there is no processing for closing or removing the main screen. In the future, it is planned to move the main screen window to a separate screen after closing or removing the main screen.

Optimization of inter-window communication

The current approach is to use the main process as a message relay, with future plans to use the poseMessage API to communicate directly between Windows.

conclusion

The above is the Electron client expansion screen implementation ideas and solutions, if you have a better way to achieve, welcome to discuss in the comments section!

A lottery

The lucky draw of this activity will be selected randomly to ensure fairness, so everyone has a chance!

Draw time: 22:00, September 12 (after the comments will not be able to participate in the draw)

Lucky draw: Random drawing (code execution)

Please feel free to get a chance in the comments section.

~

Thanks for reading!

~

Learn interesting knowledge, meet interesting friends, shape interesting soul!

Hello everyone, I am the author of “programming Samadhi”, I am king Yi, my public account is “programming Samadhi”, welcome to pay attention, I hope you can give me more advice!

You come, with expectations, I have ink to welcome! You return, no matter gain or loss, only to yu Yun give each other!

Knowledge and skills should be paid equal attention to, internal force and external power should be repaired simultaneously, theory and practice should grasp both hands, both hands should be hard!