GithubHelp home page GithubHelp logo

mawie81 / electron-window-state Goto Github PK

View Code? Open in Web Editor NEW
644.0 5.0 65.0 320 KB

A library to store and restore window sizes and positions for your Electron app

License: MIT License

JavaScript 100.00%

electron-window-state's Introduction

electron-window-state Build Status

A library to store and restore window sizes and positions for your Electron app

Heavily influenced by the implementation in electron-boilerplate.

Install

$ npm install --save electron-window-state

Usage

const windowStateKeeper = require('electron-window-state');
let win;

app.on('ready', function () {
  // Load the previous state with fallback to defaults
  let mainWindowState = windowStateKeeper({
    defaultWidth: 1000,
    defaultHeight: 800
  });

  // Create the window using the state information
  win = new BrowserWindow({
    'x': mainWindowState.x,
    'y': mainWindowState.y,
    'width': mainWindowState.width,
    'height': mainWindowState.height
  });

  // Let us register listeners on the window, so we can update the state
  // automatically (the listeners will be removed when the window is closed)
  // and restore the maximized or full screen state
  mainWindowState.manage(win);
});

Please do not set useContentSize to true at creating BrowserWindow instance because it changes how to calculate window size.

API

windowStateKeeper(opts)

Note: Don't call this function before the ready event is fired.

opts

defaultWidth - Number

The width that should be returned if no file exists yet. Defaults to 800.

defaultHeight - Number

The height that should be returned if no file exists yet. Defaults to 600.

path - String

The path where the state file should be written to. Defaults to app.getPath('userData')

file - String

The name of file. Defaults to window-state.json. This is usefull if you want to support multiple windows. Simply create multiple windowStateKeeper instances with different filenames.

maximize - Boolean

Should we automatically maximize the window, if it was last closed maximized. Defaults to true

fullScreen - Boolean

Should we automatically restore the window to full screen, if it was last closed full screen. Defaults to true

state object

const windowState = windowStateKeeper({
  defaultWidth: 1000,
  defaultHeight: 800
});

x - Number

The saved x coordinate of the loaded state. undefined if the state has not been saved yet.

y - Number

The saved y coordinate of the loaded state. undefined if the state has not been saved yet.

width - Number

The saved width of loaded state. defaultWidth if the state has not been saved yet.

height - Number

The saved heigth of loaded state. defaultHeight if the state has not been saved yet.

isMaximized - Boolean

true if the window state was saved while the window was maximized. undefined if the state has not been saved yet.

isFullScreen - Boolean

true if the window state was saved while the window was in full screen mode. undefined if the state has not been saved yet.

manage(window) - Function

Register listeners on the given BrowserWindow for events that are related to size or position changes (resize, move). It will also restore the window's maximized or full screen state. When the window is closed we automatically remove the listeners and save the state.

unmanage - Function

Removes all listeners of the managed BrowserWindow in case it does not need to be managed anymore.

saveState(window) - Function

Saves the current state of the given BrowserWindow. This exists mostly for legacy purposes, and in most cases it's better to just use manage.

License

MIT © Marcel Wiehle

electron-window-state's People

Contributors

arusakov avatar drebrez avatar eliot-akira avatar ffflorian avatar jeffbargmann avatar joshaber avatar mateusmedeiros avatar mathieudebit avatar mawie81 avatar rhysd avatar sokki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

electron-window-state's Issues

Electron v1.x support

It appears that electron-window-state does not work with the electron version 1.x. Attempting to build a previously working project using electron-window-state v2.1.0 after upgrading electron from 0.37.8 to 1.0.1 gives an error like the following:

Error opening app
The app provided is not a valid Electron app, please read the docs on how to write one:
https://github.com/electron/electron/tree/v1.0.1/docs

Error: Cannot find module 'app'

If one then manually changes node_modules\electron-window-state\index.js to use require('electron').app instead of require('app') (e.g. line 3) then this error goes away and another appears, this time related to the screen module:
screen-error

Once again, replacing require('screen') with require('electron').screen appears to resolve the problem....I guess I'll just make a PR for this now :)

this is good stuff

Not a complain, just a message to say that this project is exactly what i needed and it has been super easy to use, the documentation is awesome.

Thank you :-D

Window state not persisted anymore

Since a while (maybe since Electron 11), the window state does not persist anymore. The json file is not created anymore so my window state resets every time.
I tried giving it a different path but does not seem to work either.

  const defaultWidth = Math.min(1920, screen.getPrimaryDisplay().size.width)
  const defaultHeight = Math.min(1080, screen.getPrimaryDisplay().size.height)

  const mainWindowState = WindowStateKeeper({
    defaultWidth,
    defaultHeight,
    maximize: true // Doesn't seem to work, but does set isMaximized to undefined when window isnt maximized
  })

  // Create the browser window.
  win = new BrowserWindow({
    x: mainWindowState.x,
    y: mainWindowState.y,
    width: mainWindowState.width,
    height: mainWindowState.height,
    frame: false,
    resizable: true,
    fullscreenable: true,
    maximizable: true,
    minimizable: true,
    minHeight: 800,
    minWidth: 1024,
    closable: true,
    titleBarStyle: 'hidden',
    backgroundColor: '#222',
    webPreferences: {
      nodeIntegration: true,
      nodeIntegrationInWorker: true,
      devTools: ALLOW_DEVTOOLS,
      enableRemoteModule: true
    }
  })

  mainWindowState.manage(win)
    "electron-window-state": "^5.0.3",
    "electron": "11.0.2",

TypeError: Error processing argument at index 0

For a few of our windows-(10)-user it happens sporadically that they end up with a "x":null in their window-state.json like:

{"width":483,"height":681,"x":null,"y":48,"isMaximized":true,"isFullScreen":false,"displayBounds":{"x":0,"y":0,"width":1280,"height":720}}

This prevents the app from start until they manually delete/fix the json:

Uncaught Exception:
TypeError: Error processing argument at index 0, conversion failure from #<Object>
    at TypeError (native)
    at validateState (<APP>/node_modules/electron-window-state/index.js:47:34)
    at module.exports (<APP>/node_modules/electron-window-state/index.js:155:3)
    at createMainWindow (<APP>/src/main.js:26:25)
    at App.<anonymous> (<APP>/src/main.js:58:18)
    at emitTwo (events.js:106:13)
    at App.emit (events.js:191:7)

I think it's the state.x = null; in validateState() that should be state.x = 0; or state.x = undefined; !?

Versions

  • electron 1.3.10
  • electron-compile 4.0.2
  • electron-window-state 3.1.0

Transparency and Resziable is ignored when using it

Transparent and Resziable is ignored.

let mainWindowState = windowStateKeeper({ defaultWidth: 440, defaultHeight: 335, }); win = createWindow("main", { alwaysOnTop: true, //frame: false, transparent: true, //resizable: false, width: 440, height: 335, 'x': mainWindowState.x, 'y': mainWindowState.y, 'width': mainWindowState.width, 'height': mainWindowState.height, });

Window size not preserved correctly when multiple displays use different screen scaling (devicePixelRatio)

Configuration:
Windows 10
2 monitors, side-by-side configuration.
Left monitor scaling set to 150%.
Right monitor scaling set to 200%.
Left monitor is primary display.
(other scale factors should produce the same results, as long as the two displays have different scale factors)

Steps to reproduce:

  1. open electron application, move to any location on the right monitor.
  2. close & re-open application

Problem description:
The X & Y location of the software is preserved correctly. However, the width and height of the application is now larger than it was when closed. The width and height were both scaled up by 33%.

Expected behavior:
The width and height are restored correctly.

This seems like a per-display scaling awareness problem, but I'm not sure if it's an issue with electron-window-state, or with the electron BrowserWindow constructor width & height arguments. It does seem likely however that the problem could be corrected in electron-window-state.

Window state saved when second screen disconnected

I sometimes use a second monitor, and sometimes I don't. If an app has window-state.json stored with a location on the second monitor, then the second monitor is disconnected, I cannot see the app when the app is launched again. It is launched off the screen, and the only way I can figure to bring it back is to delete window-state.json. Using Win+left doesn't move it, it just stays there.

Rewrite to TypeScript

Advantages:

  • Static typing (less mistakes)
  • Type definitions (from the box)
  • Using the newest es2015-2017 syntax, transpiling to es5 (from the box), because uglifyjs is still not support es2015+ syntax, but I think a lot of users use it for production

@mawie81
What do you think about it?
I can help and rewrite all by myself.

Easier to use API

Currently we have to do a lot of boilerplate:

let windowState = windowStateKeeper({
  defaultWidth: 1000,
  defaultHeight: 800
});

win = new BrowserWindow({
  x: windowState.x,
  y: windowState.y,
  width: windowState.width,
  height: windowState.height,
  // ... other props
});

Why not just make the returned state object support object assignment so it can seamlessly blend with the BrowserWindow options? Then we can just:

win = new BrowserWindow(Object.assign(windowProps, windowStateKeeper()));

In this API, you don't even need defaultWidth|defaultHeight options, since they can be defined in windowProps, and will be overridden by recalled state if present.

By support assignment I mean:

  • Construct the state object so its enumerable properties match BrowserWindow options.
  • Describe methods and other proprietary stuff as non-enumerable so they don't pollute the BrowserWindow options object.

This would be the proposal with no magic and the lowest API surface I can think of. If you want to keep your proprietary props and methods, and don't like the non-enumerable treatment, a different approach might be a method that does this:

win = new BrowserWindow(windowStateKeeper().assign(windowProps));

Or even better, an API that would also eliminate the need for #manage(win):

win = windowFromState(props); // BrowserWindow instance created by state keeper

props in here would be a combination of your options and BrowserWindow options. Your options would be consumed and deleted from this object, which would then be extended with recalled state, and passed to new BrowserWindow() on creation.

Just make sure to fire stuff like win.maximize() on next tick to give us time to bind listeners.

BrowswerWindow flashes and then closes

I had an issue where some windows users were unable to open the app. This only was happening to some users. They would try to open the app, which would flash for a split second and then go away. The process still stayed visible in Task Manager as a background process. After removing electron-window-state from the project, this error went away. I don't know if there is something else I could have done to fix this issue, but it definitely seems like an issue with electron-window-state.

Project information:

  • electron 4.0.1
  • electron-builder 20.38.4
    • set up with auto updates

DevTools WindowState

hi,

I built something like this for our Jibo SDK simulator. We have multiple processes in our simulator including the running app, so we want to remember the open/close and left/top/right/bottom states/positions of each devtool instance. Have you figured out how to extract and reinstate devtool state? For now I just track if each was opened or closed. It seems if you only have one open it will automatically remember where it was positioned/sized.

Francois

Multiple monitors, window opens on wrong monitor

I did these steps:

  • I added the code as per usage example
  • I ran my app, moved the window to the left screen (I have 3 24" screens)
  • maximised it
  • closed the window (the app is now terminated)
  • re-ran the app and the window opened maximised but in the centre screen

I'm running Ubuntu 16.04, using node 7.9.0, Chrome 58.0.3029.110, and Electron 1.7.8

Edit:
Further testing shows that my app's window will maximise on which ever screen the terminal window I'm launching it from is on

Fix npm breakage with v3.0.0 release

For some reason, index.js is not getting included in the bundle any more, so npm install --save electron-window-state creates a folder in node_modules with just the readme, license, and package.json file.
However, if one changes their package.json file (for project using electron-window-state) from this (also breaks with *, 3.x, ~3.0.0, or 3.0.0 for version though strangely works for 2.1.0 despite not being modified since then aside from the version field):

  "dependencies": {
    "electron-window-state": "^3.0.0"
  }

to this (or references commit SHA)

  "dependencies": {
    "electron-window-state": "[email protected]:mawie81/electron-window-state.git"
  }

and runs npm install again then it appears.

App off the screen if user selects a different display as their main and then launches the electron app

When a user changes their main display (2 monitors windows 10: right click on desktop -> display settings -> make this my main display), then electron-windows-state does not detect this and instead of resetting the coordinates, it shows on the old coordinates, which launches off the screen. The solution would be the user reverts their main display selection and then launch the app and move it to different monitor, and then reelects main display and then the app starts okay. If there is any I am missing in the code, please kindly advice, or is there a way to reset x, y coordinates or detect if the app is in the visible zone.

Include the type definition file (index.d.ts) into npm package.

Currently, in the package.json, there is only a file included into the npm package and published.

{
    "files": [
        "index.js"
    ]
}

Thus, users will get files as shown in the image below after they do npm install electron-window-state, where index.d.ts is missing.
image


It should be like this.

{
    "files": [
        "index.js",
        "index.d.ts"
    ]
}

Looking for maintainers

As you might have noticed this project currently lacks a bit of maintenance.
I currently do not have the time and also moved away from electron into other adventures.

If you like to help out, be it by fixing bugs, adding features or providing support, please let me know.

Multi-screen support

There are 2 problems with the current implementation when working with more than 1 screen:

  • If you closed your app on some external screen and than you try to open it when that screen is not available (e.g. working directly on your laptop), the app will be invisible since it's still using the positioning for the external screen. Some users might not even know how to get the app back to their available screen (on Windows you can click on the app icon in the taskbar and move it using the Win key with the left or right arrows).
  • If you opened the app on screen 1, then move it to screen 2 and maximize it. If you close it maximized on screen 2, the next time you run it, it will open as maximized on screen 1. This happens since we don't save the x and y of the second screen.

We can solve the first issue by saving the matching display bounds using screen.getDisplayMatching(rect) and then on app load we can call it again with the app bounds and see if we get the same display bounds. If they are different it means the screen is not available or the screens layout changed, so we need to use the defaults.

The second issue is more complicated. Maybe save the position on move while not maximized?

Store other/custom window state details (e.g. URL)

Does it make sense for this library to also store other window state? For example if each window is a BrowserWindow with a specific URL loaded, then when windows are restored, it would be nice to restore each to view the previous URLs too, similar to how Chrome works.

Please let me know if you think whether this is in-scope for this project. I see two similar projects (electron-window-state-manager and electron-window-plus) that do look like they could support custom values like this, though I haven't tried them... and I'm already using yours.

Suggestion: saving the open/close state

Use case: an app may have opened different windows which the user may close.

When re-launching the app, only windows that were opened when the app exited should be re-opened.

Having an additional property isOpen (that defaults to true) in the window state would fix the problem. Closing a specific window would set state.isOpen to false.

Code like this could be used:

const userListState = windowStateKeeper({
    file: 'userList'
  });

// only open userList window if it was previously opened
if (userListSate.isOpen) {
    const userListWindow = new BrowserWindow();
    // ...
 }

Support pinned windows

Nice module. This is a tricky one.

If you pin a window to the left/right on Windows 10 or Mac OS X for example, kill the app, and re-open it, the window will be put on the left/right but it won't be correct. It'll just be placed in the right place, but it won't be pinned. So ideally this should be supported like how maximizing is supported already (instead of simply restoring the coordinates and dimensions of the maximized window).

I'm not sure how you could work around this though 😞

Support portrait monitors

Hi, thanks for the nice plugin!

It's great that it remembers the monitor as well as the size and position of the window when restoring from saved settings. It works perfectly for monitors in landscape orientation, but it doesn't quite work right when restoring to a monitor in portrait orientation, unfortunately.

I have a three-monitor setup where my left monitor (1050x1680) is in portrait orientation instead of landscape like the other two. When the window is restored on the portrait monitor, its height always gets truncated to the width of the monitor (1050 i.e. what would normally be the height in landscape mode). If I save the window with a smaller height, then it restores ok. It's only when the height is more than the 1050 width that there's a problem.

Here's a sample window-state.json file (reformatted with whitespace for readability) when saving a window that takes up the full left half of my portrait monitor (I didn't save use the full width here to avoid confusion with thinking the height and width were being swapped, since that's not the problem).

{
  "width":525,
  "height":1650,
  "x":-1050,
  "y":30,
  "isMaximized":false,
  "isFullScreen":false,
  "displayBounds": {
    "x":-1050,
    "y":30,
    "width":1050,
    "height":1680
  }
}

(The 'missing' 30px is due to the taskbar at the bottom of the screen.)

For reference, here's the settings file after immediately closing the app after being restored from the above settings:

{
  "width":525,
  "height":1050,
  "x":-1050,
  "y":30,
  "isMaximized":false,
  "isFullScreen":false,
  "displayBounds": {
    "x":-1050,
    "y":30,
    "width":1050,
    "height":1680
  }
}

Notice that the height was truncated from 1650 to 1050.

I don't see an obvious problem in the validateState bounds-checking code. However, it does rely on the electron screen.getDisplayMatching method, so maybe the actual problem is in the electron code?

Thanks in advance!

Maximize window problem

Hi! Im use your cool library, and together with this, I use this code:

    mainWindow = new BrowserWindow({
        show: false,
    });

    mainWindow.webContents.on('dom-ready', function() {
        mainWindow.show();
    });

in order to the contents of the window displayed only when fully loaded. When window is no maximized this working fine, but when app start maximized, this code does not work. Without your library all working as it should. Is there any solution?

Specifying path param won't work

Hello!

I'm trying to save the file into a specific path using the path property as the documentation says, but it won't work for me. windowStateKeeper keeps saving the file in the default path (app.getPath('userData')).

This is how I'm trying to do it:

let mainWindowState = windowStateKeeper({
  path: app.getPath('documents'),
  file: 'window-state-my-app.json',
  defaultWidth: 1000,
  defaultHeight: 600
})

I guess I'm probably doing something wrong, any idea what could it be?

Uncaught Exception: at validateState

Tried to restart my application and during windowStateKeeper initialization this library threw unhandled exception.

Traceback:

Uncaught Exception:
TypeError: Error processing argument at index 0, conversion failure from # <Object>
    at TypeError (native)
    at validateState
(D:\projects\my_app\app\app\node_modules\electron-window-state\index.js:45:34)
    at module.exports
(D:\projects\my_app\app\app\node_modules\electron-window-state\index.js:153:3)
...
rest of the traceback is from my app (not relevant)

My code

        const mainWindowState = windowStateKeeper({
            defaultWidth: 1200,
            defaultHeight: 800,
        });
        const {x, y} = mainWindowState;
        const validLocation = isValidScreenLocation(x, y);  // Custom function to validate x and y positions
        const mainWindow = this.mainWindow = new BrowserWindow({
            x: validLocation ? x : 100,  // Default to 100 when no valid screen location
            y: validLocation ? y : 100,  // Default to 100 when no valid screen location
            width: mainWindowState.width,
            height: mainWindowState.height,
        });

Contents of my stored window-state.json

{
  "width": 1200,
  "height": 768,
  "x": 100,
  "y": 100,
  "isMaximized": false,
  "isFullScreen": false,
  "displayBounds": {
    "x": 0,
    "y": 0,
    "width": 1366,
    "height": 768
  }
}

Didn't figure out yet what was the actual problem.

I'm using:

  • electron-window-state: 4.0.1
  • electron: 1.4.2

Window with width and height 0

For reasons I was not able to seize, users of my app find themselves with a window of height and width of 0.
Here is an example of window-state.json I saw:

{
  "width": 0,
  "height": 0,
  "x": 40,
  "y": 23,
  "isMaximized": false,
  "isFullScreen": false,
  "displayBounds": {
    "x": 0,
    "y": 0,
    "width": 1440,
    "height": 900
  }
}

It's on macOS with [email protected] and [email protected]
I don't do anything particular with my window sizing in the code, I let electron-window-state handle that.
Nevertheless, I tend to notice that affected users use a secondary display from time to time.

While finding the actual cause of the bug would be better, shouldn't we implement a safeguard in electron-window-state? a size with 0 as width or 0 as height is not a valid state.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.