nwjs / nw.js

Call all Node.js modules directly from DOM/WebWorker and enable a new way of writing applications with all Web technologies.
https://nwjs.io
MIT License
40.29k stars 3.88k forks source link

nw.Window.get... window doesn't return actual window object in new_instance #7848

Open UtterDonkey opened 2 years ago

UtterDonkey commented 2 years ago

image image Then from the secondary window: image

behaviour doesn't make a whole lot of sense. you get the newWin object which is the NW.js wrapper around the new window you just made. however, the window inside it isn't actually the window for that window... it's some new window, which allows you to add event listeners but isn't actually attached to the window. and when you add an event listener to it, the main window handles those events.

Expected behaviour: nw.Window.getAll(allWindows => {return allWindows[0].window}) returns the true window object.

Actual Behaviour: nw.Window.getAll(allWindows => {return allWindows[0].window}) returns a completely separate window object that somehow still acts like a window object.

Reproduce using the steps above⬆️

OS: Windows 10

sysrage commented 2 years ago

IMO, this issue can go two ways:

  1. The parameter passed to the nw.Window.open() callback (and the array returned by nw.Window.getAll()) should not have access to child window objects when new_instance === true. "fixing" this would make newWin.window undefined, preventing the ability add weird event listeners to some phantom window object that's not actually attached to that window.
  2. We should have access to to every window's window object through nw.Window.getAll() or the nw.Window.open() callback parameter. Adding this would allow postMessage() to work between windows, even when new_instance is true.

Either way, the "phantom" window added to the nw.Window.open() callback parameter should either be fixed or removed.

UtterDonkey commented 2 years ago

I am hoping for the second option.

UtterDonkey commented 2 years ago

nw.Window.getAll() returns the actual window object when not using new_instance

sysrage commented 2 years ago

It pains me to see a bug report with code in a screenshot, especially when those screenshots and comments were a copy/paste from what I said on Discord. So, I'm adding code explaining @UtterDonkey's last comment, as well as the original code...

NWJS Version : 0.62.0 Operating System : Windows 10

Expected behavior

There should be consistent behavior, in regards to how the win.window object is populated when new_instance is true.

Actual behavior

Currently, this object is sometimes undefined and sometimes points to a window object that's a partial clone of the main window's window object (not the new window).

How to reproduce

package.json

{
  "name": "test",
  "main": "index.html"
}

index.html

<script>
  window.addEventListener('message', (event) => {
    console.log(`Message sent to main window: ${event.data}`);
  });
  nw.Window.get().showDevTools();
</script>
  1. Run the above app with the NW.js SDK.

  2. Enter the following in the DevTools console:

    nw.Window.open('index.html', {}, (newWin) => {
    newWin.window.opener.postMessage('test via newWin.window.opener', '*');
    });
  3. In the new DevTools console that just opened, enter:

    window.opener.postMessage('test via window.opener', '*');
    nw.Window.getAll(windowList => windowList[0].window.postMessage('test via getAll()', '*'));
  4. Note that all three of these messages are successfully received in the first/main window (shown in the first DevTools console).

  5. Close the secondary window and enter the following in the first DevTools console:

    nw.Window.open('index.html', { new_instance: true }, (newWin) => {
    newWin.window.opener.postMessage('test via newWin.window.opener', '*');
    });
  6. In the new DevTools console that just opened, enter:

    window.opener.postMessage('test via window.opener', '*');
    nw.Window.getAll(windowList => windowList[0].window.postMessage('test via getAll()', '*'));
  7. Note that all three messages fail:

    • window.opener is null.
    • nw.Window.getAll(windowList => windowList[0].window) is undefined.
  8. Now here's where it starts to get fun. Close the secondary window again and enter the following in the first DevTools console:

    nw.Window.open('index.html', { new_instance: true }, (newWin) => {
    newWin.window.addEventListener('message', (event) => {
    console.log(`Message sent to 2nd window: ${event.data}`);
    });
    });
  9. Still in the first/main DevTools console, enter:

    nw.Window.getAll(winList => winList[0].window.postMessage('0', '*'));
    nw.Window.getAll(winList => winList[1].window.postMessage('1', '*'));
  10. The console for the main window will show both messages, but the secondary window will not have received either.

If the window object shouldn't be defined when new_instance is true, we shouldn't be able to add event listeners to the newWin.window object in the nw.Window.open() callback (it should be undefined). That said, it would be very handy to be able to get a handle to that window!