Quantcast
Viewing latest article 1
Browse Latest Browse All 2

Answer by midnight-coding for Electron, how can I make the title buttons work?

Similar to your other SO Question, you will need to become familiar with the below Electron Browser Window - Instance Methodsfor more information.

On window creation, we tell the window what state it is in. EG: Maximised or restored. This 'state' is sent via IPC (via our preload.js script) to the render side Javascript to either display or hide the correct maximise / restore buttons.

Following this, we just listen for any render side title bar button clicks. Once 'clicked', send a message via IPC to the main process to control the state of the window. Depending on the request ('maximise' or 'restore'), send a message back (via IPC) to the render process to either 'show' or 'hide' (via the CSS display attribute) the correct maximise / restore button.


Here, we set the window frame state to false, load the index.html file, tell the render process (via IPC) the state of our window (restored in this case) and then finally show the window.

main.js (main process)

// Import required electron modulesconst electronApp = require('electron').app;const electronBrowserWindow = require('electron').BrowserWindow;const electronIpcMain = require('electron').ipcMain;// Import required Node modulesconst nodePath = require('path');// Prevent garbage collectionlet window;function createWindow() {    const window = new electronBrowserWindow({        x: 0,        y: 0,        width: 800,        height: 600,        frame: false,        show: false,        webPreferences: {            nodeIntegration: false,            contextIsolation: true,            sandbox: true,            preload: nodePath.join(__dirname, 'preload.js')        }    });    window.loadFile(nodePath.join(__dirname, 'index.html'))        // Below boolean value could be retrieved from saved application setting (json file) on start-up        .then(() => { window.webContents.send('maximised', false); })        .then(() => { window.show(); });    return window;}electronApp.on('ready', () => {    window = createWindow();});electronApp.on('window-all-closed', () => {    if (process.platform !== 'darwin') {        electronApp.quit();    }});electronApp.on('activate', () => {    if (electronBrowserWindow.getAllWindows().length === 0) {        createWindow();    }});// ---electronIpcMain.on('minimise', (event) => {    window.minimize();})electronIpcMain.on('maximise', (event) => {    window.maximize();    window.webContents.send('maximised', true);})electronIpcMain.on('restore', (event) => {    window.restore();    window.webContents.send('maximised', false);})electronIpcMain.on('close', (event) => {    window.close();})

Set our channel names used to manage the window state.

preload.js (main process)

// Import the necessary Electron modulesconst contextBridge = require('electron').contextBridge;const ipcRenderer = require('electron').ipcRenderer;// White-listed channelsconst ipc = {'channels': {        // From render to main'send': ['minimise','maximise','restore','close'        ],        // From main to render'receive': ['maximised'        ],        // From main to render (once)'receiveOnce': [],        // From render to main and back again'sendReceive': []    }};// Exposed protected methods in the render processcontextBridge.exposeInMainWorld(    // Allowed 'ipcRenderer' methods'ipcRenderer', {        // From render to main        send: (channel, args) => {            if (ipc.channels.send.includes(channel)) {                ipcRenderer.send(channel, args);            }        },        // From main to render        receive: (channel, listener) => {            if (ipc.channels.receive.includes(channel)) {                // Deliberately strip event as it includes `sender`.                ipcRenderer.on(channel, (event, ...args) => listener(...args));            }        },        // From main to render (once)        receiveOnce: (channel, listener) => {            if (ipc.channels.receiveOnce.includes(channel)) {                // Deliberately strip event as it includes `sender`.                ipcRenderer.once(channel, (event, ...args) => listener(...args));            }        },        // From render to main and back again        invoke: (channel, args) => {            if (ipc.channels.sendReceive.includes(channel)) {                return ipcRenderer.invoke(channel, args);            }        }    });

Use of this preload.js script is as follows.

/** * * Main --> Render * --------------- * Main:    window.webContents.send('channel', data); // Data is optional. * Render:  window.ipcRenderer.receive('channel', (data) => { methodName(data); }); * * Main --> Render (Once) * ---------------------- * Main:    window.webContents.send('channel', data); // Data is optional. * Render:  window.ipcRenderer.receiveOnce('channel', (data) => { methodName(data); }); * * Render --> Main * --------------- * Render:  window.ipcRenderer.send('channel', data); // Data is optional. * Main:    electronIpcMain.on('channel', (event, data) => { methodName(data); }) * * Render --> Main (Once) * ---------------------- * Render:  window.ipcRenderer.send('channel', data); // Data is optional. * Main:    electronIpcMain.once('channel', (event, data) => { methodName(data); }) * * Render --> Main (Value) --> Render * ---------------------------------- * Render:  window.ipcRenderer.invoke('channel', data).then((result) => { methodName(result); }); * Main:    electronIpcMain.handle('channel', (event, data) => { return someMethod(data); }); * * Render --> Main (Promise) --> Render * ------------------------------------ * Render:  window.ipcRenderer.invoke('channel', data).then((result) => { methodName(result); }); * Main:    electronIpcMain.handle('channel', async (event, data) => { *              return await myPromise(data) *                  .then((result) => { return result; }) *          }); * * Main:    function myPromise(data) { return new Promise((resolve, reject) => { ... }); } * */

Finally, let's listen for and send messages to the main process (via our preload.js script) to manage the window state.

index.html (render process)

<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>my app</title><meta http-equiv="Content-Security-Policy" content="script-src 'self''unsafe-inline';"/></head><body style="margin: 0; padding: 0;"><!-- Simple use of flexbox styling + prevent user from selecting title bar contents --><div style="display: flex; justify-content: space-between; padding: 0.25em; background-color: grey; -webkit-user-select: none;"><!-- Add title bar drag functionality by using "-webkit-app-region: drag;" --><span style="flex: 1 0 auto; -webkit-app-region: drag;"><img src="" alt="logo" style="width: 22px; height: 22px;"><span class="title-text">My App - Some Page</span></span><!-- Prevent title bar dragging by buttons by using "-webkit-app-region: no-drag;" --><span style="flex: 0 1 auto; -webkit-app-region: no-drag;"><input type="button" id="minimise_button" value="-"><input type="button" id="maximise_button" value="◻"><input type="button" id="restore_button" value="R"><input type="button" id="close_button" value="×"></span></div><div class="application-container">...</div></body><script>        // Declare these elements as we use them more than once        let maximise_button = document.getElementById('maximise_button');        let restore_button = document.getElementById('restore_button');        // Minimise button functionality        document.getElementById('minimise_button').addEventListener('click', () => {            window.ipcRenderer.send('minimise');        });        // Maximise button functionality        maximise_button.addEventListener('click', () => {            window.ipcRenderer.send('maximise');        });        // Restore button functionality        restore_button.addEventListener('click', () => {            window.ipcRenderer.send('restore');        });        // Close button functionality        document.getElementById('close_button').addEventListener('click', () => {            window.ipcRenderer.send('close');        });        // Toggle css "display" attribute of maximise & restore buttons depending on state of window        window.ipcRenderer.receive('maximised', (state) => {            maximise_button.style.display = (state) ? 'none' : 'inline-block';            restore_button.style.display = (state) ? 'inline-block' : 'none';        });</script></html>

Viewing latest article 1
Browse Latest Browse All 2

Trending Articles