Creating a custom titlebar with Electron and Vue: How to accurately determine the window's maximized or restored state from within a component

Currently, I am working on a frameless application that incorporates a custom titlebar (Electron + Vue + Vuex, with the electron-vue boilerplate). I have successfully implemented functionality to toggle the maximize/restore buttons upon click.

The issue arises when window state changes are triggered by other events, such as double-clicking the title bar for maximize or interacting with the taskbar icon (Windows) for minimize/restore.

I am seeking advice on how to incorporate an event listener within the component (.vue) to respond to window state changes and display the appropriate maximize/restore button. Is this possible?

Answer №1

After some trial and error, I finally figured out a way to handle window events in Electron:

In electron-main.js

    mainWindow.on("move", () => {
        //_ console.log("electron move");
        mainWindow.webContents.send("winState", "normal");
    });
    mainWindow.on("minimize", () => {
        //_ console.log("electron minimize");
        mainWindow.webContents.send("winState", "minimized");
    });
    mainWindow.on("maximize", () => {
        //_ console.log("electron maximize");
        mainWindow.webContents.send("winState", "maximized");
    });
    mainWindow.on("unmaximize", () => {
        //_ console.log("electron unmaximize");
        mainWindow.webContents.send("winState", "normal");
    });
    mainWindow.on("restore", () => {
        //_ console.log("electron restore");
        mainWindow.webContents.send("winState", "normal");
    });

In electron-preload.js

import { contextBridge, ipcRenderer } from "electron";
import { BrowserWindow } from "@electron/remote";

contextBridge.exposeInMainWorld("csxAPI", {
    envMode: process.env.MODE,
    minimize() {
        BrowserWindow.getFocusedWindow().minimize();
    },
    maximize() {
        BrowserWindow.getFocusedWindow().maximize();
    },
    restore() {
        BrowserWindow.getFocusedWindow().unmaximize();
    },
    close() {
        BrowserWindow.getFocusedWindow().close();
        BrowserWindow.getFocusedWindow().destroy();
    },
});

const validChannels = ["winState"];
contextBridge.exposeInMainWorld("ipc", {
    send: (channel, data) => {
        if (validChannels.includes(channel)) {
            ipcRenderer.send(channel, data);
        }
    },
    on: (channel, func) => {
        if (validChannels.includes(channel)) {
            // Strip event as it includes `sender` and is a security risk
            //_ ipcRenderer.on(channel, (event, ...args) => func(...args));
            ipcRenderer.on(channel, (...args) => func(...args));
        }
    },
});

In TitleBar.vue

//...
data: function () {
        return {
            status: "normal",
        };
    },

//...
mounted() {
        window.ipc.on("winState", (event, msg) => {
            this.status = msg;
        });

//...
methods: {
        winMinimize() {
            if (window.csxAPI.envMode === "electron") {
                window.csxAPI.minimize();
            }
        },
        winMaximize() {
            if (window.csxAPI.envMode === "electron") {
                window.csxAPI.maximize();
            }
        },
        winRestore() {
            if (window.csxAPI.envMode === "electron") {
                window.csxAPI.restore();
            }
        },
        winClose() {
            if (window.csxAPI.envMode === "electron") {
                window.csxAPI.close();
            }
        },
    },

This approach may not be the most optimized or conventional, but it did the job for me. Grateful for all the support received.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the reason for the vertex shader failing to compile?

Recently diving into the world of WebGl, I decided to experiment with a simple example. Here is how I set up my script: Here's my setup script import testVertexShader from './shaders/test/vertex.glsl' import testFragmentShader from './ ...

Creating an Application using npm - Issue with unhandled rejection: Element at index 9 not found

Currently, I am developing a vue application using tailwind, postcss, and several other packages. Executing the command npm run serve triggers vue-cli-service serve, which runs smoothly without any issues. However, running 'npm run build' invok ...

What is the best way to enable visitors to share the current page on blogger, similar to the functionality of Facebook's

I'm looking to integrate a button on my website similar to Facebook's like button that allows users to share my site on Blogger. However, after checking Blogger's developer site, it appears that there is no equivalent JavaScript code availab ...

I need to remove the command "npm config set cache "C:/Users/ASIMIM/AppData/Roaming/npm-cache" --global"

I was having trouble with npx create-react-app my-app, it showed an error https://i.sstatic.net/OcnR0.png. So I checked on Stack Overflow and followed the suggestion to run "npm config set cache 'C:/Users/ASIMIM/AppData/Roaming/npm-cache' --globa ...

Warning: An unexpected issue occurred due to an invalid integer being entered as Not a Number (NaN

I've encountered an issue trying to pass data into the "amount" parameter. From the client, I'm sending the "price" to the server successfully. Upon checking the console output, I see the correct information is being received. The typeof check ...

Creating SVG Lines with Google Maps JavaScript API v3

I have a project that requires a dashed line between two points on Google Maps using JavaScript v3. The specification states that each dash should be 100px long. I have attempted to achieve this using SVG, but the dashes are not displaying correctly. Here ...

Increase the value of a number using jQuery

When using jquery to animate a random number increment from 0001 to 1000, the issue arises when reaching the number 0077. The final number displayed is 77 instead of 0077. Is there a solution to ensure the format remains as 0077? Your help is appreciated. ...

Reduce the size of the profile picture in the Facebook like box

I have a Facebook like box on my site but in some resolutions the profile pictures goes to next line after 2 pictures instead of 3 so I want to make the profile pictures width and height 49 instead of 50 because that would fix the problem. Here's how ...

combine blank cells in table generated with vuejs

I am attempting to display a table of students where each column represents a subject, and underneath each column are the names of the students who failed in that particular subject. The challenge I am facing is that my data is structured in rows instead o ...

Is there a way to retrieve JSON data from a different domain and incorporate it into my own website?

I am attempting to utilize JSON data from "" and display the data on my website. My goal is to extract the JSON field name "Stats" and retrieve the sub-field name '\"v\"'. You can refer to the documentation provided by purpleair here: h ...

What could be the reason for the Express function Router() returning a value of undefined?

Currently, I am working with TypeScript and Express to develop an API that adheres to the principles of Clean Architecture. To organize my application, I have structured each route in separate folders and then imported them all into an index.ts file where ...

Choose information based on the prior choice made

Using the Material UI Stepper, I have a task that involves setting conditions based on the selection of checkboxes. In step one, there are two checkboxes - Individual and Bulk. In step two, there are also two checkboxes - First Screening and Second Screeni ...

Creating dynamic elements in JavaScript utilizing Bootstrap cards

Looking for help in integrating Bootstrap cards while dynamically generating elements using JavaScript? I am working on a project where I need to generate a list of restaurant recommendations based on user preferences entered through a form, utilizing the ...

When working with Firebase, I am required to extract data from two different tables simultaneously

When working with Firebase, I have the need to extract data from tables/nodes. Specifically, I am dealing with two tables - one called jobs and the other called organisations. The outcome I am looking for: I want to retrieve all companies that do not hav ...

What is the best way to enlarge text size with jquery?

I am attempting to: $('a[data-text="size-bigger"]').click(function () { a=$('span'); b=$('span').css('font-size'); a.css('font-size', b+1); } ); Initially, I ha ...

Struggling to comprehend the node.js walker concept

I am struggling to grasp the concept of how the signature/header of the node.js walker functions. I understand that a walker can go through a directory and apply filters, but I'm unsure about how the signature of the .on function works. For example: ...

Adding a query parameter from the controller using UI router

Within my application, I have a parent state along with child states that belong to the parent. The parent state contains an optional parameter called reviewId. Currently, everything is functioning correctly - when I send the parameter in $state.go, the st ...

Is it possible to automate the process of constructing a dependency in the package.json file?

Currently, I am using firebaseui and require building it with French localization because the localized versions are not available on npm. In my current package.json file, the dependencies section looks like this: "dependencies": { "firebaseui": "^3.5 ...

Selection determines the value of two fields

This form has predefined values that are used to create a link, but the issue is that these values vary depending on the location. Can you assist me with this problem? <input type="radio" id="iconapp1" name="department" value="1250"/><label for ...

Utilize Index Within Computed Functions

Can someone assist with referencing the index in a computed function? <div class="inputArea mt-2" v-for="(id, index) in inputs" :key="index"> <div class="row"> <div class="col-md-6 m-1" ...