0

I created a very simple site to create a popup on my second screen.

The Multi-Screen Window Placement Api promises to do the trick, but i am not able to make it work.

I get all the informations about both screens, but cant open the popup on the correct display.

Does anyone have an idea? Is it because of the "window-placement" permission or something?

Here is the simple site I made:

<!DOCTYPE html>
<html>

<title>Window Placement</title>

<head>
  <script type="text/javascript">
    let url = "file:///C:/Users/path/to/file.html";
    let x = "1000";
    let y = "250";
    let width = "250";
    let height = "250";
    let popup;

    async function screenDetails() {
      if (window.screen.isExtended) {
        console.log("Multiple screens detected");

        try {
          const screens = await window.getScreenDetails();

          let primary;
          let second;

          for (let element of screens.screens) {
            if (element.isPrimary) {
              primary = element;
            } else {
              second = element;
            }
          }

          let features = "left=" + x + ",top=" + y +
            ",width=" + width + ",height=" + height;

          popup = window.open(url, 'Popup', features);
        } catch (err) {
          console.error(err);
        }

      } else {
        console.log("Single screen detected");
      }
    }
  </script>
</head>

<body>
  <button type="button" onclick="open()">Open</button>
</body>

</html>
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
kanonroald
  • 41
  • 6

2 Answers2

1

So, I got it to work, albeit not in the Stack Snippet environment I'm providing the code in.

It does indeed have to do with permissions; you must ask for permission to get screen details. In the code below, I created a new function which will query for doing this, getPermissionAndScreenDetails in the code below. It verifies the API is available, that the permission is present and not denied (it is automatically 'denied' in a Stack Snippet for security reasons). It then returns the result of calling window.getScreenDetails() as that is necessary to get permission if the state is set to 'prompt'.

I altered your function to use that function's return value.

I also added some code that will open the popup in the middle of the first secondary screen it finds.

let url = "about:blank";
let x = "1000";
let y = "250";
let width = "250";
let height = "250";
let popup;

async function getPermissionAndScreenDetails() {
  if ('getScreenDetails' in window) {
    let granted = false;
    try {
      const permission = await navigator.permissions.query({
        name: 'window-placement'
      });
      console.log(permission, permission.state);
      if (permission.state !== 'denied') {
        return window.getScreenDetails();
      } else {
        return null;
      }
    } catch {
      // Nothing.
      return null;
    }
  } else {
    return null;
  }
}

async function screenDetails() {
  const screens = await getPermissionAndScreenDetails();
  if (screens != null && window.screen.isExtended) {
    console.log("Multiple screens detected");

    try {
      console.log(screens);
      let primary;
      let secondaries = [];

      for (let element of screens.screens) {
        if (element.isPrimary) {
          primary = element;
        } else {
          secondaries.push(element);
        }
      }
      console.log('primary: ', primary);
      console.log('secondaries: ', secondaries);

      // find secondary screen we can place the popup on
      const secondary = secondaries[0];
      x = secondary.left + (secondary.availWidth / 2) - (width / 2);
      y = secondary.top + (secondary.availHeight / 2) - (height / 2);


      let features = "left=" + (second.left + 1000) + ",top=" + (second.top + 400) +
        ",width=" + width + ",height=" + height;

      popup = window.open(url, 'Popup', features);
    } catch (err) {
      console.error(err);
    }

  } else {
    console.log("Single screen detected (or permission not granted)");
  }
}


document.getElementById("open").addEventListener('click', screenDetails);
<button type="button" id="open">Open</button>
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
  • thanks! But this still doesnt work for me. The popup lands on the edge of my primary screen. So this has to be a setup/configuration problem right? I granted the popup permission in Chrome settings, have this file locally on my pc, simply open that files filesystem url in chrome. Am i missing something? – kanonroald Jul 08 '22 at 17:51
  • It might just be a difference in configuration. I have three screens; one on either side of my primary screen. So when I run it, the popup shows in the middle of the left screen. I'd look at what was logged for `secondaries`. Do the calculations for x and y and see what you come up with. You might need to make some alterations based on your particular setup (like if your monitors overlap in your configuration or something weird like that). This is also very new tech; the standard has not been finalized, so it's like trying to build a house on a boat that's on the ocean. – Heretic Monkey Jul 08 '22 at 19:48
  • 1
    The calculations for secondaries is correct. I also tried to "hard-wire" some coordinates into the code to make the window open on the second screen. That still doesnt work. Thank for your effort, its good that i have an example that _should_ work on my pc. I will accept your answer. – kanonroald Jul 11 '22 at 09:27
0

First, onclick="open()" should be onclick="screenDetails()". Next, the hardcoded x and y values should use availLeft, availTop, etc. of the intended screen for window.open coordinates. Also, the opener may be on a secondary screen of the device; to open a window on any other screen, you can instead find a screens entry that isn't currentScreen, like my snippet below.

Besides permission, iframes requires 'window-management' permission policy, which is why Stack Overflow's "Run code snippet" doesn't work here.

See API sample code at https://michaelwasserman.github.io/window-placement-demo/

This snippet opens a window on any other screen; test at https://husky-imaginary-sale.glitch.me/

<button id="popup">Open popup on another screen</button>
<div id="logger"></div>

<script>
function log(text) {
  console.log(text);
  logger.innerText += text + '\n';
}

popup.addEventListener('click', async () => {
  try {
    window.screenDetails = await window.getScreenDetails();
  } catch {}
  if (!window.screenDetails) {
    log('API not supported or permission denied, skipping popup');
    return;
  }
  if (!window.screenDetails.screens.length > 1) {
    log('Single screen detected, skipping popup');
    return;
  }
  const other = window.screenDetails.screens.find(s=>s!=window.screenDetails.currentScreen);
  const width = 300;
  const height = 300;
  const left = other.availLeft + (other.availWidth / 2) - (width / 2);
  const top = other.availTop + (other.availHeight / 2) - (height / 2);
  const features = `left=${left},top=${top},width=${width},height=${height}`;
  log(`Opening popup with features: '${features}'`);
  window.open('about:blank', 'Popup', features);
});
</script>