From 198e6fdf75e2362a6be3519d84f73678a815d043 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 30 Aug 2023 17:02:22 +0100 Subject: [PATCH 1/5] Add docs for the Window Management API --- .../web/api/window_management_api/index.md | 245 ++++++++++++++++++ files/jsondata/GroupData.json | 11 + 2 files changed, 256 insertions(+) create mode 100644 files/en-us/web/api/window_management_api/index.md diff --git a/files/en-us/web/api/window_management_api/index.md b/files/en-us/web/api/window_management_api/index.md new file mode 100644 index 000000000000000..4379d8ee4ef8b23 --- /dev/null +++ b/files/en-us/web/api/window_management_api/index.md @@ -0,0 +1,245 @@ +--- +title: Window Management API +slug: Web/API/Window_Management_API +page-type: web-api-overview +status: + - experimental +browser-compat: api.Window.getScreenDetails +--- + +{{SeeCompatTable}}{{DefaultAPISidebar("Window Management API")}} + +The **Window Management API** allows you to return detailed information on the displays connected to your device and more easily place windows on specific screens, paving the way towards more effective multi-screen applications. + +## Concepts and usage + +Historically, we have used {{domxref("Window.open()")}} to manage browser windows related to the current application — opening new windows, resizing and closing existing windows, etc. For example, to open a 400×300 window 50 pixels from the left and top of your screen: + +```js +const myWindow = window.open( + "https://example.com/", + "myWindow", + "left=50,top=50,width=400,height=300", +); +``` + +You can retrieve information about your screen from the {{domxref("Window.screen")}} property, such as how much screen space you have available to place windows in. + +However, the above features are limited. `Window.screen` only returns data about the primary screen, and not the other monitors attached to a device. To move a window to a second monitor for example, you could use {{domxref("Window.MoveTo()")}}, but you'd have to guess what coordinates to use based on where it is placed in your setup relative to the primary display. + +The Window Management API provides more robust, flexible window management. It allows you to query whether your display is extended with multiple screens and return information on each screen separately: windows can then be placed on each screen as desired. It also provides event handlers to allow you to respond to changes in the available screens, new fullscreen functionality to choose which screen to put into fullscreen mode (if any), and permissions functionality to control access to the API. + +## Use cases + +The Window Management API is useful in cases such as: + +- Multi-window graphics editors and audio processors that may wish to arrange editing tools and panels across different screens. +- Virtual trading desks that want to show market trends in multiple windows and put specific windows of interest in fullscreen mode. +- Slideshow apps that want to show speaker notes on the internal primary screen and the presentation on an external projector. + +## How does it work? + +The core of the Windows Management API is the {{domxref("Window.getScreenDetails()")}} method, which returns an object containing details of all the screens available to the user's system: + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the number of screens +const noOfScreens = screenDetails.screens.length; +``` + +When `getScreenDetails()` is invoked, the user will be asked for permission to manage windows on all their displays (the status of this permission can be checked using {{domxref("Permissions.query()")}} to query `window-management`). Provided they grant permission, the resulting {{domxref("ScreenDetails")}} object contains the following properties: + +- `screens` + - : An array of {{domxref("ScreenDetailed")}} objects, each one containing detailed information about a separate screen available to the system (see below). This array is also useful for determining the number of available screens, via `screens.length`. +- `currentScreen` + - : A single {{domxref("ScreenDetailed")}} object containing detailed information about the screen that the current browser window is displayed in. + +> **Note:** `ScreenDetails` is a live object, meaning that it updates as the available screens change. You can therefore keep querying the same object to get updated values, rather than repeatedly calling `getScreenDetails()`. + +> **Note:** You can gate functionality based on whether the user has more than one screen available using the {{domxref("Screen.isExtended", "Window.screen.isExtended")}} property. This returns `true` if the device has multiple screens, and `false` if not. + +{{domxref("ScreenDetailed")}} objects inherit the properties of the {{domxref("Screen")}} interface, and contain useful information for placing windows on specific screens. For example: + +- `availWidth` and `availHeight` + - : The width and height of the screen area available for opening windows in. These values are equal to `width` and `height`, plus the width/height of any OS-specific user interface elements drawn on the screen. +- `availLeft` and `availTop` + - : The top-left coordinate of the screen area available for opening windows in. These values are equal to `left` and `top`, plus the width/height of any OS-specific user interface elements drawn at the top-left of the screen. +- `isPrimary` + - : A boolean indicating whether this screen is set as the OS primary screen or not. +- `isInternal` + - : A boolean indicating whether this screen is internal to the device or not. +- `label` + - : A string providing a descriptive label for the screen, for example "Built-in Retina Display". This is useful for constructing a list of options to display to the user if you want them to choose a screen to display content on. + +You'll still need to use {{domxref("Window.open()")}} to open and manage windows, but the above provides you with better information for doing so in a multi-screen environment. For example, a utility function might look like so: + +```js +function openWindow(left, top, width, height, url) { + const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; + const windowRef = window.open( + url, + Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab + windowFeatures, + ); + + // Store a reference to the window in the windowRefs array + windowRefs.push(windowRef); +} +``` + +You would then invoke this function and open windows on specific screens like this: + +```js +const screen1 = screenDetails.screens[0]; +const screen2 = screenDetails.screens[1]; +// Windows will be a third the width and the full height of the screen +let windowWidth = Math.floor((screen1.availWidth - 3 * WINDOW_CHROME_X) / 3); +let windowHeight = Math.floor(screen1.availHeight - WINDOW_CHROME_Y); + +// Open the reference windows in thirds across the entire height of the primary screen +openWindow( + screen1.availLeft, + screen1.availTop, + windowWidth, + windowHeight, + sites[1].url, +); + +// ... +``` + +As shown in an earlier code block, it is a good idea to keep track of the windows you have open, for example using an array. This allows you to, for example, close them all when one window is closed: + +```js +function closeAllWindows() { + // Loop through all window refs and close each one + windowRefs.forEach(windowRef => { + windowRef.close(); + }); + windowRefs = []; +} + +// ... + +// Check whether one of our popup windows has been closed +// If so, close them all + +closeMonitor = setInterval(checkWindowClose, 250); + +function checkWindowClose() { + windowRefs.forEach(windowRef => { + if (windowRef.closed) { + closeAllWindows(); + return; + } + }); +``` + +> **Note:** In our experiments, the {{domxref("setInterval()")}} polling method shown above seemed to work best for detecting window closure in the case of multiple windows. Using events such as {{domxref("Window.beforeunload_event", "beforeunload")}}, {{domxref("Window.pagehide_event", "pagehide")}}, or {{domxref("Document.visibilitychange_event", "visibilitychange")}} proved unreliable because, when opening multiple windows in the first place, the rapid shift in focus/visibility seemed to fire the handler function prematurely. + +### Window management events + +The Window Management API provides some useful events for responding to changes in the available screens: + +- The `ScreenDetails` {{domxref("ScreenDetails.screenschange_event", "screenschange")}} event + - : Fired when the screens available to the system change in some way. +- The `ScreenDetails` {{domxref("ScreenDetails.currentscreenchange_event", "currentscreenchange")}} event + - : Fired when the current screen changes in some way. +- The `Screen` {{domxref("Screen.change_event", "change")}} event + - : Fired on a specific screen when it changes in some way. + +So for example, you could use the `screenschange` event to detect when the available screens have changed (perhaps when a screen is plugged in or unplugged), report the change, close all windows, and then reopen them all to suit the new configuration: + +```js +screenDetails.addEventListener("screenschange", () => { + // If the new number of screens is different to the old number of screens, report the difference + if (screenDetails.screens.length !== noOfScreens) { + console.log( + `The screen count changed from ${noOfScreens} to ${screenDetails.screens.length}`, + ); + } + + // If the windows are open, close them and then open them again + // So that they fit with the new screen configuration + if (windowRefs.length > 0) { + closeAllWindows(); + openWindows(); + } +}); +``` + +### requestFullscreen() screen option + +The Window Management API adds a new `screen` option to the {{domxref("Element.requestFullscreen", "requestFullscreen()")}} method that allows you to specify on which screen you want to put the element in fullscreen mode. For example, if you want to make it fullscreen on the primary OS screen: + +```js +try { + const primaryScreen = (await getScreenDetails()).screens.filter( + (screen) => screen.isPrimary, + )[0]; + await document.body.requestFullscreen({ screen: primaryScreen }); +} catch (err) { + console.error(err.name, err.message); +} +``` + +## Permissions policy integration + +The {{httpheader("Permissions-Policy/window-management", "window-management")}} [Permissions-Policy](/en-US/docs/Web/HTTP/Permissions_Policy) can be used to control permission to use the Window Management API. Specifically: + +- Usage of the {{domxref("Window.getScreenDetails()")}} method. If blocked, its {{jsxref("Promise")}} will reject with a `NotAllowedError` exception. +- Querying the {{domxref("Window.screen.isExtended")}} property. If blocked, it will always return `false`. + +Developers can explicitly grant permission for an {{htmlelement("iframe")}} to use Window Management via the `allow` attribute: + +```html + +``` + +## Interfaces + +- {{domxref("ScreenDetails")}} + - : Represents the details of all the screens available to the user's device. +- {{domxref("ScreenDetailed")}} + - : Represents detailed information about one specific screen available to the user's device. + +## Extensions to other interfaces + +- {{domxref("Screen.isExtended")}} + - : A boolean property that returns `true` if the device has multiple screens, and `false` if not. +- {{domxref("Element.requestFullscreen()")}}, the `screen` option + - : Specifies on which screen you want to put the element in fullscreen mode. +- {{domxref("Window.getScreenDetails()")}} + - : Returns a {{jsxref("Promise")}} that fulfills with a {{domxref("ScreenDetails")}} object instance. + +## Examples + +### Feature detection + +You can feature detect the Window Management API by checking for the existence of `getScreenDetails` in the current `window` instance. For example, you might want to provide a button to open a multi-window display if the API is supported, or a different experience such as creating links to the different pages if it isn't: + +```js +if ("getScreenDetails" in window) { + // The Window Management API is supported + createButton(); +} else { + // The Window Management API is not supported + createLinks(sites); +} +``` + +### Full examples + +You can find full examples here: + +- [Multi-window learning environment](https://mdn.github.io/dom-examples/window-management-api/) (see the [source code](https://github.com/mdn/dom-examples/tree/main/window-management-api)). +- [Elmer-inspired trading desk demo](https://window-placement.glitch.me/) (see the [source code](https://glitch.com/edit/#!/window-placement)). + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index dc0bbc781e37cad..2cb3675ebc71df9 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -2278,6 +2278,17 @@ "properties": ["Navigator.windowControlsOverlay"], "events": [] }, + "Window Management API": { + "overview": ["Window Management API"], + "interfaces": ["ScreenDetails", "ScreenDetailed"], + "methods": ["Element.requestFullscreen()", "Window.getScreenDetails()"], + "properties": ["Screen.isExtended"], + "events": [ + "Screen: change", + "ScreenDetails: currentscreenchange", + "ScreenDetails: screenschange" + ] + }, "XMLHttpRequest": { "overview": ["XMLHttpRequest"], "guides": [ From f702ac1d3557039237125d0521b5705a4fb7c563 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 4 Sep 2023 17:53:37 +0100 Subject: [PATCH 2/5] Adding rest of pages for the API --- files/en-us/_redirects.txt | 44 +++--- files/en-us/_wikihistory.json | 142 +++++++++--------- .../api/element/requestfullscreen/index.md | 19 +++ files/en-us/web/api/permissions_api/index.md | 1 + files/en-us/web/api/screen/availleft/index.md | 49 ------ files/en-us/web/api/screen/availtop/index.md | 34 ----- .../web/api/screen/change_event/index.md | 59 ++++++++ files/en-us/web/api/screen/index.md | 12 +- .../en-us/web/api/screen/isextended/index.md | 42 ++++++ files/en-us/web/api/screen/left/index.md | 26 ---- files/en-us/web/api/screen/top/index.md | 30 ---- .../web/api/screendetailed/availleft/index.md | 41 +++++ .../web/api/screendetailed/availtop/index.md | 41 +++++ .../screendetailed/devicepixelratio/index.md | 39 +++++ files/en-us/web/api/screendetailed/index.md | 99 ++++++++++++ .../api/screendetailed/isinternal/index.md | 39 +++++ .../web/api/screendetailed/isprimary/index.md | 41 +++++ .../web/api/screendetailed/label/index.md | 41 +++++ .../web/api/screendetailed/left/index.md | 41 +++++ .../en-us/web/api/screendetailed/top/index.md | 41 +++++ .../api/screendetails/currentscreen/index.md | 71 +++++++++ .../currentscreenchange_event/index.md | 69 +++++++++ files/en-us/web/api/screendetails/index.md | 118 +++++++++++++++ .../web/api/screendetails/screens/index.md | 34 +++++ .../screenschange_event/index.md | 81 ++++++++++ .../web/api/window/getscreendetails/index.md | 95 ++++++++++++ files/en-us/web/api/window/index.md | 2 + .../web/api/window_management_api/index.md | 12 +- .../http/headers/permissions-policy/index.md | 4 + .../window-management/index.md | 44 ++++++ 30 files changed, 1170 insertions(+), 241 deletions(-) delete mode 100644 files/en-us/web/api/screen/availleft/index.md delete mode 100644 files/en-us/web/api/screen/availtop/index.md create mode 100644 files/en-us/web/api/screen/change_event/index.md create mode 100644 files/en-us/web/api/screen/isextended/index.md delete mode 100644 files/en-us/web/api/screen/left/index.md delete mode 100644 files/en-us/web/api/screen/top/index.md create mode 100644 files/en-us/web/api/screendetailed/availleft/index.md create mode 100644 files/en-us/web/api/screendetailed/availtop/index.md create mode 100644 files/en-us/web/api/screendetailed/devicepixelratio/index.md create mode 100644 files/en-us/web/api/screendetailed/index.md create mode 100644 files/en-us/web/api/screendetailed/isinternal/index.md create mode 100644 files/en-us/web/api/screendetailed/isprimary/index.md create mode 100644 files/en-us/web/api/screendetailed/label/index.md create mode 100644 files/en-us/web/api/screendetailed/left/index.md create mode 100644 files/en-us/web/api/screendetailed/top/index.md create mode 100644 files/en-us/web/api/screendetails/currentscreen/index.md create mode 100644 files/en-us/web/api/screendetails/currentscreenchange_event/index.md create mode 100644 files/en-us/web/api/screendetails/index.md create mode 100644 files/en-us/web/api/screendetails/screens/index.md create mode 100644 files/en-us/web/api/screendetails/screenschange_event/index.md create mode 100644 files/en-us/web/api/window/getscreendetails/index.md create mode 100644 files/en-us/web/http/headers/permissions-policy/window-management/index.md diff --git a/files/en-us/_redirects.txt b/files/en-us/_redirects.txt index 8be9e77a3fe5190..0f414de7f0eb87a 100644 --- a/files/en-us/_redirects.txt +++ b/files/en-us/_redirects.txt @@ -2214,17 +2214,17 @@ /en-US/docs/DOM/window.restore /en-US/docs/Web/API/Window/moveTo /en-US/docs/DOM/window.screen /en-US/docs/Web/API/Window/screen /en-US/docs/DOM/window.screen.availHeight /en-US/docs/Web/API/Screen/availHeight -/en-US/docs/DOM/window.screen.availLeft /en-US/docs/Web/API/Screen/availLeft -/en-US/docs/DOM/window.screen.availTop /en-US/docs/Web/API/Screen/availTop +/en-US/docs/DOM/window.screen.availLeft /en-US/docs/Web/API/ScreenDetailed/availLeft +/en-US/docs/DOM/window.screen.availTop /en-US/docs/Web/API/ScreenDetailed/availTop /en-US/docs/DOM/window.screen.availWidth /en-US/docs/Web/API/Screen/availWidth /en-US/docs/DOM/window.screen.colorDepth /en-US/docs/Web/API/Screen/colorDepth /en-US/docs/DOM/window.screen.height /en-US/docs/Web/API/Screen/height -/en-US/docs/DOM/window.screen.left /en-US/docs/Web/API/Screen/left +/en-US/docs/DOM/window.screen.left /en-US/docs/Web/API/ScreenDetailed/left /en-US/docs/DOM/window.screen.lockOrientation /en-US/docs/Web/API/Screen/lockOrientation /en-US/docs/DOM/window.screen.mozBrightness /en-US/docs/Web/API/Screen/mozBrightness /en-US/docs/DOM/window.screen.mozEnabled /en-US/docs/Web/API/Screen/mozEnabled /en-US/docs/DOM/window.screen.pixelDepth /en-US/docs/Web/API/Screen/pixelDepth -/en-US/docs/DOM/window.screen.top /en-US/docs/Web/API/Screen/top +/en-US/docs/DOM/window.screen.top /en-US/docs/Web/API/ScreenDetailed/top /en-US/docs/DOM/window.screen.width /en-US/docs/Web/API/Screen/width /en-US/docs/DOM/window.screenX /en-US/docs/Web/API/Window/screenX /en-US/docs/DOM/window.screenY /en-US/docs/Web/API/Window/screenY @@ -2642,14 +2642,14 @@ /en-US/docs/DOM:window.resizeTo /en-US/docs/Web/API/Window/resizeTo /en-US/docs/DOM:window.screen /en-US/docs/Web/API/Window/screen /en-US/docs/DOM:window.screen.availHeight /en-US/docs/Web/API/Screen/availHeight -/en-US/docs/DOM:window.screen.availLeft /en-US/docs/Web/API/Screen/availLeft -/en-US/docs/DOM:window.screen.availTop /en-US/docs/Web/API/Screen/availTop +/en-US/docs/DOM:window.screen.availLeft /en-US/docs/Web/API/ScreenDetailed/availLeft +/en-US/docs/DOM:window.screen.availTop /en-US/docs/Web/API/ScreenDetailed/availTop /en-US/docs/DOM:window.screen.availWidth /en-US/docs/Web/API/Screen/availWidth /en-US/docs/DOM:window.screen.colorDepth /en-US/docs/Web/API/Screen/colorDepth /en-US/docs/DOM:window.screen.height /en-US/docs/Web/API/Screen/height -/en-US/docs/DOM:window.screen.left /en-US/docs/Web/API/Screen/left +/en-US/docs/DOM:window.screen.left /en-US/docs/Web/API/ScreenDetailed/left /en-US/docs/DOM:window.screen.pixelDepth /en-US/docs/Web/API/Screen/pixelDepth -/en-US/docs/DOM:window.screen.top /en-US/docs/Web/API/Screen/top +/en-US/docs/DOM:window.screen.top /en-US/docs/Web/API/ScreenDetailed/top /en-US/docs/DOM:window.screen.width /en-US/docs/Web/API/Screen/width /en-US/docs/DOM:window.screenX /en-US/docs/Web/API/Window/screenX /en-US/docs/DOM:window.screenY /en-US/docs/Web/API/Window/screenY @@ -3365,14 +3365,14 @@ /en-US/docs/Document_Object_Model_(DOM)/window.restore /en-US/docs/Web/API/Window/moveTo /en-US/docs/Document_Object_Model_(DOM)/window.screen /en-US/docs/Web/API/Window/screen /en-US/docs/Document_Object_Model_(DOM)/window.screen.availHeight /en-US/docs/Web/API/Screen/availHeight -/en-US/docs/Document_Object_Model_(DOM)/window.screen.availLeft /en-US/docs/Web/API/Screen/availLeft -/en-US/docs/Document_Object_Model_(DOM)/window.screen.availTop /en-US/docs/Web/API/Screen/availTop +/en-US/docs/Document_Object_Model_(DOM)/window.screen.availLeft /en-US/docs/Web/API/ScreenDetailed/availLeft +/en-US/docs/Document_Object_Model_(DOM)/window.screen.availTop /en-US/docs/Web/API/ScreenDetailed/availTop /en-US/docs/Document_Object_Model_(DOM)/window.screen.availWidth /en-US/docs/Web/API/Screen/availWidth /en-US/docs/Document_Object_Model_(DOM)/window.screen.colorDepth /en-US/docs/Web/API/Screen/colorDepth /en-US/docs/Document_Object_Model_(DOM)/window.screen.height /en-US/docs/Web/API/Screen/height -/en-US/docs/Document_Object_Model_(DOM)/window.screen.left /en-US/docs/Web/API/Screen/left +/en-US/docs/Document_Object_Model_(DOM)/window.screen.left /en-US/docs/Web/API/ScreenDetailed/left /en-US/docs/Document_Object_Model_(DOM)/window.screen.pixelDepth /en-US/docs/Web/API/Screen/pixelDepth -/en-US/docs/Document_Object_Model_(DOM)/window.screen.top /en-US/docs/Web/API/Screen/top +/en-US/docs/Document_Object_Model_(DOM)/window.screen.top /en-US/docs/Web/API/ScreenDetailed/top /en-US/docs/Document_Object_Model_(DOM)/window.screen.width /en-US/docs/Web/API/Screen/width /en-US/docs/Document_Object_Model_(DOM)/window.screenX /en-US/docs/Web/API/Window/screenX /en-US/docs/Document_Object_Model_(DOM)/window.screenY /en-US/docs/Web/API/Window/screenY @@ -9604,22 +9604,26 @@ /en-US/docs/Web/API/SVGStylable /en-US/docs/Web/API/SVGElement /en-US/docs/Web/API/SVGURIReference /en-US/docs/Web/SVG/Attribute/href /en-US/docs/Web/API/Screen.availHeight /en-US/docs/Web/API/Screen/availHeight -/en-US/docs/Web/API/Screen.availLeft /en-US/docs/Web/API/Screen/availLeft -/en-US/docs/Web/API/Screen.availTop /en-US/docs/Web/API/Screen/availTop +/en-US/docs/Web/API/Screen.availLeft /en-US/docs/Web/API/ScreenDetailed/availLeft +/en-US/docs/Web/API/Screen.availTop /en-US/docs/Web/API/ScreenDetailed/availTop /en-US/docs/Web/API/Screen.availWidth /en-US/docs/Web/API/Screen/availWidth /en-US/docs/Web/API/Screen.colorDepth /en-US/docs/Web/API/Screen/colorDepth /en-US/docs/Web/API/Screen.height /en-US/docs/Web/API/Screen/height -/en-US/docs/Web/API/Screen.left /en-US/docs/Web/API/Screen/left +/en-US/docs/Web/API/Screen.left /en-US/docs/Web/API/ScreenDetailed/left /en-US/docs/Web/API/Screen.lockOrientation /en-US/docs/Web/API/Screen/lockOrientation /en-US/docs/Web/API/Screen.mozBrightness /en-US/docs/Web/API/Screen/mozBrightness /en-US/docs/Web/API/Screen.mozEnabled /en-US/docs/Web/API/Screen/mozEnabled /en-US/docs/Web/API/Screen.onorientationchange /en-US/docs/Web/API/Screen/orientationchange_event /en-US/docs/Web/API/Screen.orientation /en-US/docs/Web/API/Screen/orientation /en-US/docs/Web/API/Screen.pixelDepth /en-US/docs/Web/API/Screen/pixelDepth -/en-US/docs/Web/API/Screen.top /en-US/docs/Web/API/Screen/top +/en-US/docs/Web/API/Screen.top /en-US/docs/Web/API/ScreenDetailed/top /en-US/docs/Web/API/Screen.unlockOrientation /en-US/docs/Web/API/Screen/unlockOrientation /en-US/docs/Web/API/Screen.width /en-US/docs/Web/API/Screen/width +/en-US/docs/Web/API/Screen/availLeft /en-US/docs/Web/API/ScreenDetailed/availLeft +/en-US/docs/Web/API/Screen/availTop /en-US/docs/Web/API/ScreenDetailed/availTop +/en-US/docs/Web/API/Screen/left /en-US/docs/Web/API/ScreenDetailed/left /en-US/docs/Web/API/Screen/onorientationchange /en-US/docs/Web/API/Screen/orientationchange_event +/en-US/docs/Web/API/Screen/top /en-US/docs/Web/API/ScreenDetailed/top /en-US/docs/Web/API/ScreenOrientation/onchange /en-US/docs/Web/API/ScreenOrientation/change_event /en-US/docs/Web/API/ScriptProcessorNode.bufferSize /en-US/docs/Web/API/ScriptProcessorNode/bufferSize /en-US/docs/Web/API/ScriptProcessorNode.onaudioprocess /en-US/docs/Web/API/ScriptProcessorNode/audioprocess_event @@ -10825,19 +10829,19 @@ /en-US/docs/Web/API/window.restore /en-US/docs/Web/API/Window/moveTo /en-US/docs/Web/API/window.screen /en-US/docs/Web/API/Window/screen /en-US/docs/Web/API/window.screen.availHeight /en-US/docs/Web/API/Screen/availHeight -/en-US/docs/Web/API/window.screen.availLeft /en-US/docs/Web/API/Screen/availLeft -/en-US/docs/Web/API/window.screen.availTop /en-US/docs/Web/API/Screen/availTop +/en-US/docs/Web/API/window.screen.availLeft /en-US/docs/Web/API/ScreenDetailed/availLeft +/en-US/docs/Web/API/window.screen.availTop /en-US/docs/Web/API/ScreenDetailed/availTop /en-US/docs/Web/API/window.screen.availWidth /en-US/docs/Web/API/Screen/availWidth /en-US/docs/Web/API/window.screen.colorDepth /en-US/docs/Web/API/Screen/colorDepth /en-US/docs/Web/API/window.screen.height /en-US/docs/Web/API/Screen/height -/en-US/docs/Web/API/window.screen.left /en-US/docs/Web/API/Screen/left +/en-US/docs/Web/API/window.screen.left /en-US/docs/Web/API/ScreenDetailed/left /en-US/docs/Web/API/window.screen.lockOrientation /en-US/docs/Web/API/Screen/lockOrientation /en-US/docs/Web/API/window.screen.mozBrightness /en-US/docs/Web/API/Screen/mozBrightness /en-US/docs/Web/API/window.screen.mozEnabled /en-US/docs/Web/API/Screen/mozEnabled /en-US/docs/Web/API/window.screen.onorientationchange /en-US/docs/Web/API/Screen/orientationchange_event /en-US/docs/Web/API/window.screen.orientation /en-US/docs/Web/API/Screen/orientation /en-US/docs/Web/API/window.screen.pixelDepth /en-US/docs/Web/API/Screen/pixelDepth -/en-US/docs/Web/API/window.screen.top /en-US/docs/Web/API/Screen/top +/en-US/docs/Web/API/window.screen.top /en-US/docs/Web/API/ScreenDetailed/top /en-US/docs/Web/API/window.screen.unlockOrientation /en-US/docs/Web/API/Screen/unlockOrientation /en-US/docs/Web/API/window.screen.width /en-US/docs/Web/API/Screen/width /en-US/docs/Web/API/window.screenX /en-US/docs/Web/API/Window/screenX diff --git a/files/en-us/_wikihistory.json b/files/en-us/_wikihistory.json index 3f7feb174e22439..57bfe939046a2ce 100644 --- a/files/en-us/_wikihistory.json +++ b/files/en-us/_wikihistory.json @@ -57786,41 +57786,6 @@ "Gor1" ] }, - "Web/API/Screen/availLeft": { - "modified": "2020-10-15T21:13:04.118Z", - "contributors": [ - "mfuji09", - "ExE-Boss", - "fscholz", - "cvrebert", - "Sebastianz", - "teoli", - "MHasan", - "kscarfone", - "Navin_Jadhav", - "Sheppy", - "jzaruba", - "Mgjbot", - "Yaroukh", - "Gor1" - ] - }, - "Web/API/Screen/availTop": { - "modified": "2020-10-15T21:16:26.852Z", - "contributors": [ - "mfuji09", - "ExE-Boss", - "fscholz", - "cvrebert", - "Sebastianz", - "teoli", - "kosvrouvas", - "Navin_Jadhav", - "Sheppy", - "Mgjbot", - "Gor1" - ] - }, "Web/API/Screen/availWidth": { "modified": "2020-10-15T21:16:26.709Z", "contributors": [ @@ -57871,23 +57836,6 @@ "Gor1" ] }, - "Web/API/Screen/left": { - "modified": "2020-10-15T21:16:24.841Z", - "contributors": [ - "ExE-Boss", - "fscholz", - "cvrebert", - "Sebastianz", - "teoli", - "MHasan", - "namolmes", - "Sheppy", - "Mgjbot", - "Nickolay", - "Jabez", - "Gor1" - ] - }, "Web/API/Screen/lockOrientation": { "modified": "2020-10-15T21:19:41.189Z", "contributors": [ @@ -57999,25 +57947,6 @@ "Gor1" ] }, - "Web/API/Screen/top": { - "modified": "2020-10-15T21:16:23.568Z", - "contributors": [ - "ExE-Boss", - "fscholz", - "cvrebert", - "teoli", - "jswisher", - "Anonymous", - "MHasan", - "chitra_lakhotia", - "Sheppy", - "ethertank", - "jryans", - "Mgjbot", - "Mw22", - "Gor1" - ] - }, "Web/API/Screen/unlockOrientation": { "modified": "2020-10-15T21:23:44.621Z", "contributors": [ @@ -58056,6 +57985,77 @@ "Gor1" ] }, + "Web/API/ScreenDetailed/availLeft": { + "modified": "2020-10-15T21:13:04.118Z", + "contributors": [ + "mfuji09", + "ExE-Boss", + "fscholz", + "cvrebert", + "Sebastianz", + "teoli", + "MHasan", + "kscarfone", + "Navin_Jadhav", + "Sheppy", + "jzaruba", + "Mgjbot", + "Yaroukh", + "Gor1" + ] + }, + "Web/API/ScreenDetailed/availTop": { + "modified": "2020-10-15T21:16:26.852Z", + "contributors": [ + "mfuji09", + "ExE-Boss", + "fscholz", + "cvrebert", + "Sebastianz", + "teoli", + "kosvrouvas", + "Navin_Jadhav", + "Sheppy", + "Mgjbot", + "Gor1" + ] + }, + "Web/API/ScreenDetailed/left": { + "modified": "2020-10-15T21:16:24.841Z", + "contributors": [ + "ExE-Boss", + "fscholz", + "cvrebert", + "Sebastianz", + "teoli", + "MHasan", + "namolmes", + "Sheppy", + "Mgjbot", + "Nickolay", + "Jabez", + "Gor1" + ] + }, + "Web/API/ScreenDetailed/top": { + "modified": "2020-10-15T21:16:23.568Z", + "contributors": [ + "ExE-Boss", + "fscholz", + "cvrebert", + "teoli", + "jswisher", + "Anonymous", + "MHasan", + "chitra_lakhotia", + "Sheppy", + "ethertank", + "jryans", + "Mgjbot", + "Mw22", + "Gor1" + ] + }, "Web/API/ScreenOrientation": { "modified": "2020-11-13T05:33:17.108Z", "contributors": [ diff --git a/files/en-us/web/api/element/requestfullscreen/index.md b/files/en-us/web/api/element/requestfullscreen/index.md index 1ce5f836b5782ac..77183e25e972efe 100644 --- a/files/en-us/web/api/element/requestfullscreen/index.md +++ b/files/en-us/web/api/element/requestfullscreen/index.md @@ -43,6 +43,8 @@ requestFullscreen(options) - `"auto"` - : The browser will choose which of the above settings to apply. This is the default value. + - `screen` {{optional_inline}} {{experimental_inline}} + - : Specifies on which screen you want to put the element in fullscreen mode. This takes a {{domxref("ScreenDetailed")}} object as a value, representing the chosen screen. ### Return value @@ -157,6 +159,23 @@ elem The promise's resolve handler does nothing, but if the promise is rejected, an error message is displayed by calling {{DOMxRef("Window.alert", "alert()")}}. +### Using the screen option + +If you wanted to make the element fullscreen on the primary OS screen, you could use code like the following: + +```js +try { + const primaryScreen = (await getScreenDetails()).screens.filter( + (screen) => screen.isPrimary, + )[0]; + await document.body.requestFullscreen({ screen: primaryScreen }); +} catch (err) { + console.error(err.name, err.message); +} +``` + +The {{domxref("Window.getScreenDetails()")}} method is used to retrieve the {{domxref("ScreenDetails")}} object for the current device, which contains {{domxref("ScreenDetailed")}} objects representing the different available screens. + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/permissions_api/index.md b/files/en-us/web/api/permissions_api/index.md index 53e01c7cd971293..58290b938e0952b 100644 --- a/files/en-us/web/api/permissions_api/index.md +++ b/files/en-us/web/api/permissions_api/index.md @@ -44,6 +44,7 @@ A non-exhaustive list of permission-aware APIs includes: - [Storage API](/en-US/docs/Web/API/Storage_API): `persistent-storage` - [Web Audio Output Devices API](/en-US/docs/Web/API/Audio_Output_Devices_API): `speaker-selection` - [Web MIDI API](/en-US/docs/Web/API/Web_MIDI_API): `midi` +- [Window Management API](/en-US/docs/Web/API/Window_Management_API): `window-management` ## Examples diff --git a/files/en-us/web/api/screen/availleft/index.md b/files/en-us/web/api/screen/availleft/index.md deleted file mode 100644 index 34902a14d2da7b3..000000000000000 --- a/files/en-us/web/api/screen/availleft/index.md +++ /dev/null @@ -1,49 +0,0 @@ ---- -title: "Screen: availLeft property" -short-title: availLeft -slug: Web/API/Screen/availLeft -page-type: web-api-instance-property -status: - - non-standard -browser-compat: api.Screen.availLeft ---- - -{{APIRef("CSSOM")}}{{Non-standard_Header}} - -Returns the first available pixel from the left side of the screen. - -## Value - -A number. - -## Examples - -```js -let setX = window.screen.width - window.screen.availLeft; -let setY = window.screen.height - window.screen.availTop; -window.moveTo(setX, setY); -``` - -## Notes - -In most cases, this property returns 0. - -If you work with two screens this property, evaluated on the right screen, returns the -width of the left one in pixels (thereby indicating the X coordinate of the left edge of -the screen on the right). - -On Windows, this property depends on which screen is set as your primary, returning the -X coordinate of the leftmost available pixel relative to the primary screen. That is, -the primary screen's left edge always has the X coordinate 0, even if it's not the -leftmost screen. If the secondary screen is to the left of the primary screen, it has a -negative X coordinate to compensate: - -\[1] \[2] - on left screen _availLeft_ returns **0**, on the right -screen it returns the **width** of the left one - -\[2] \[1] - on left screen _availLeft_ returns **-width** of that -screen, on the right screen, it returns **0** - -## Browser compatibility - -{{Compat}} diff --git a/files/en-us/web/api/screen/availtop/index.md b/files/en-us/web/api/screen/availtop/index.md deleted file mode 100644 index a10866766a41ef5..000000000000000 --- a/files/en-us/web/api/screen/availtop/index.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: "Screen: availTop property" -short-title: availTop -slug: Web/API/Screen/availTop -page-type: web-api-instance-property -status: - - non-standard -browser-compat: api.Screen.availTop ---- - -{{APIRef("CSSOM")}}{{Non-standard_Header}} - -Specifies the y-coordinate of the first pixel that is not allocated to permanent or -semipermanent user interface features. - -## Value - -A number. - -## Examples - -```js -let setX = window.screen.width - window.screen.availLeft; -let setY = window.screen.height - window.screen.availTop; -window.moveTo(setX, setY); -``` - -## Notes - -In most cases, this property returns `0`. - -## Browser compatibility - -{{Compat}} diff --git a/files/en-us/web/api/screen/change_event/index.md b/files/en-us/web/api/screen/change_event/index.md new file mode 100644 index 000000000000000..62f14ba84ebefd0 --- /dev/null +++ b/files/en-us/web/api/screen/change_event/index.md @@ -0,0 +1,59 @@ +--- +title: "Screen: change event" +short-title: change +slug: Web/API/Screen/change_event +page-type: web-api-event +status: + - experimental +browser-compat: api.Screen.change_event +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`change`** event of the {{domxref("Screen")}} interface is fired on a specific screen when it changes in some way — for example available width or height, or orientation. + +Specifically, _change_ means changes to a `Screen` instance's _basic observable properties_, which are: + +- {{domxref("Screen.width", "width")}} +- {{domxref("Screen.height", "height")}} +- {{domxref("Screen.availWidth", "availWidth")}} +- {{domxref("Screen.availHeight", "availHeight")}} +- {{domxref("Screen.colorDepth", "colorDepth")}} +- {{domxref("Screen.orientation", "orientation")}} + +## Syntax + +Use the event name in methods like {{domxref("EventTarget.addEventListener", "addEventListener()")}}, or set an event handler property. + +```js +addEventListener("change", (event) => {}); + +onchange = (event) => {}; +``` + +## Event type + +An event of type `change`, the event object of which is structurally equivalent to an {{domxref("Event")}}. + +{{InheritanceDiagram("Event")}} + +## Examples + +```js +const firstScreen = (await window.getScreenDetails())[0]; +firstScreen.addEventListener("change", async (event) => { + console.log("The first screen has changed.", event, firstScreen); +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screen/index.md b/files/en-us/web/api/screen/index.md index f50981a35f08849..54f5c48715d1710 100644 --- a/files/en-us/web/api/screen/index.md +++ b/files/en-us/web/api/screen/index.md @@ -17,10 +17,6 @@ Note that browsers determine which screen to report as current by detecting whic _Also inherits properties from its parent {{domxref("EventTarget")}}_. -- {{DOMxRef("Screen.availTop")}} {{Non-standard_Inline}} - - : Specifies the y-coordinate of the first pixel that is not allocated to permanent or semipermanent user interface features. -- {{DOMxRef("Screen.availLeft")}} {{Non-standard_Inline}} - - : Returns the first available pixel available from the left side of the screen. - {{DOMxRef("Screen.availHeight")}} - : Specifies the height of the screen, in pixels, minus permanent or semipermanent user interface features displayed by the operating system, such as the Taskbar on Windows. - {{DOMxRef("Screen.availWidth")}} @@ -29,14 +25,12 @@ _Also inherits properties from its parent {{domxref("EventTarget")}}_. - : Returns the color depth of the screen. - {{DOMxRef("Screen.height")}} - : Returns the height of the screen in pixels. -- {{DOMxRef("Screen.left")}} {{Non-standard_Inline}} - - : Returns the distance in pixels from the left side of the main screen to the left side of the current screen. +- {{domxref("Screen.isExtended")}} {{experimental_inline}} + - : Returns `true` if the user's device has multiple screens, and `false` if not. - {{DOMxRef("Screen.orientation")}} - : Returns the {{DOMxRef("ScreenOrientation")}} instance associated with this screen. - {{DOMxRef("Screen.pixelDepth")}} - : Gets the bit depth of the screen. -- {{DOMxRef("Screen.top")}} {{Deprecated_Inline}} {{Non-standard_Inline}} - - : Returns the distance in pixels from the top side of the current screen. - {{DOMxRef("Screen.width")}} - : Returns the width of the screen. - {{DOMxRef("Screen.mozEnabled")}} {{Non-standard_Inline}} {{Deprecated_Inline}} @@ -55,6 +49,8 @@ _Also inherits methods from its parent {{domxref("EventTarget")}}_. ## Events +- {{domxref("Screen.change_event", "change")}} {{experimental_inline}} + - : Fired on a specific screen when it changes in some way — for example available width or height, or orientation. - {{DOMxRef("Screen.orientationchange_event", "orientationchange")}} {{Deprecated_Inline}} {{Non-standard_Inline}} - : Fires when the screen orientation changes. diff --git a/files/en-us/web/api/screen/isextended/index.md b/files/en-us/web/api/screen/isextended/index.md new file mode 100644 index 000000000000000..30edf9d5dcb08c9 --- /dev/null +++ b/files/en-us/web/api/screen/isextended/index.md @@ -0,0 +1,42 @@ +--- +title: "Screen: isExtended property" +short-title: isExtended +slug: Web/API/Screen/isExtended +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.Screen.isExtended +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`isExtended`** read-only property of the +{{domxref("Screen")}} interface returns `true` if the user's device has multiple screens, and `false` if not. + +This property is most commonly accessed via `window.screen.isExtended`, and provides a useful test to see if multiple screens are available before attempting to create a multi-window, multi-screen layout using the [Window Management API](/en-US/docs/Web/API/Window_Management_API). However, since {{domxref("ScreenDetailed")}} inherits from `Screen`, `isExtended` is also available on all `ScreenDetailed` object instances contained inside the {{domxref("ScreenDetails")}} object returned by {{domxref("Window.getScreenDetails()")}}. When multiple screens are available, all `isExtended` properties will be `true`. + +## Value + +A boolean value — `true` if the device has multiple screens, and `false` if not. + +## Examples + +```js +if (window.screen.isExtended) { + // Create multi-screen window layout +} else { + // Create single-screen window layout +} +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screen/left/index.md b/files/en-us/web/api/screen/left/index.md deleted file mode 100644 index 165e8a571f940f8..000000000000000 --- a/files/en-us/web/api/screen/left/index.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: "Screen: left property" -short-title: left -slug: Web/API/Screen/left -page-type: web-api-instance-property -status: - - non-standard -browser-compat: api.Screen.left ---- - -{{APIRef("CSSOM")}}{{Non-standard_Header}} - -Returns the distance in pixels from the left side of the main screen to the left side -of the current screen. - -## Value - -A number. - -## Browser compatibility - -{{Compat}} - -## See also - -- {{DOMxRef("screen.top")}} diff --git a/files/en-us/web/api/screen/top/index.md b/files/en-us/web/api/screen/top/index.md deleted file mode 100644 index 24257cb936c3631..000000000000000 --- a/files/en-us/web/api/screen/top/index.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "Screen: top property" -short-title: top -slug: Web/API/Screen/top -page-type: web-api-instance-property -status: - - deprecated - - non-standard -browser-compat: api.Screen.top ---- - -{{APIRef("CSSOM")}}{{Deprecated_Header}}{{Non-standard_Header}} - -Returns the distance in pixels from the top side of the current screen. - -## Value - -A number. - -## Specifications - -Not part of any current specification. - -## Browser compatibility - -{{Compat}} - -## See also - -- {{DOMxRef("Screen.left")}} diff --git a/files/en-us/web/api/screendetailed/availleft/index.md b/files/en-us/web/api/screendetailed/availleft/index.md new file mode 100644 index 000000000000000..9dfb9495c96d2bb --- /dev/null +++ b/files/en-us/web/api/screendetailed/availleft/index.md @@ -0,0 +1,41 @@ +--- +title: "ScreenDetailed: availLeft property" +short-title: availLeft +slug: Web/API/ScreenDetailed/availLeft +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.availLeft +--- + +{{APIRef("Window Management API")}}{{seecompattable}} + +The **`availLeft`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a number representing the x-coordinate (left-hand edge) of the available screen area inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + +This is equal to the {{domxref("ScreenDetailed.left")}} property, plus the width of any OS UI element drawn on the left of the screen. Windows cannot be placed in those areas, so `availLeft` is useful for giving you the left boundary of the actual area you've got available. + +## Value + +A number. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the availLeft value of the first screen +const screen1AvailLeft = screenDetails.screens[0].availLeft; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/availtop/index.md b/files/en-us/web/api/screendetailed/availtop/index.md new file mode 100644 index 000000000000000..81944dbfae9a2a8 --- /dev/null +++ b/files/en-us/web/api/screendetailed/availtop/index.md @@ -0,0 +1,41 @@ +--- +title: "ScreenDetailed: availTop property" +short-title: availTop +slug: Web/API/ScreenDetailed/availTop +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.availTop +--- + +{{APIRef("Window Management API")}}{{seecompattable}} + +The **`availTop`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a number representing the y-coordinate (top edge) of the available screen area inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + +This is equal to the {{domxref("ScreenDetailed.top")}} property, plus the height of any OS UI element drawn at the top of the screen. Windows cannot be placed in those areas, so `availTop` is useful for giving you the top boundary of the actual area you've got available. + +## Value + +A number. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the availTop value of the first screen +const screen1AvailTop = screenDetails.screens[0].availTop; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/devicepixelratio/index.md b/files/en-us/web/api/screendetailed/devicepixelratio/index.md new file mode 100644 index 000000000000000..8411bc9422f714d --- /dev/null +++ b/files/en-us/web/api/screendetailed/devicepixelratio/index.md @@ -0,0 +1,39 @@ +--- +title: "ScreenDetailed: devicePixelRatio property" +short-title: devicePixelRatio +slug: Web/API/ScreenDetailed/devicePixelRatio +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.devicePixelRatio +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`devicePixelRatio`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a number representing the screen's device pixel ratio. This is the same as the value returned by {{domxref("Window.devicePixelRatio")}} (although that property always returns the device pixel ratio for the {{domxref("ScreenDetails.currentScreen", "current screen", "", "nocode")}}) — see that page for more information about device pixel ratios in general. + +## Value + +A number. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the device pixel ratio of the first screen +const screen1DPR = screenDetails.screens[0].devicePixelRatio; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/index.md b/files/en-us/web/api/screendetailed/index.md new file mode 100644 index 000000000000000..25d2fd52b8f0e3c --- /dev/null +++ b/files/en-us/web/api/screendetailed/index.md @@ -0,0 +1,99 @@ +--- +title: ScreenDetailed +slug: Web/API/ScreenDetailed +page-type: web-api-interface +status: + - experimental +browser-compat: api.ScreenDetailed +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`ScreenDetailed`** interface of the [Window Management API](/en-US/docs/Web/API/Window_Management_API) represents detailed information about one specific screen available to the user's device. + +`ScreenDetailed` objects can be accessed via the {{domxref("ScreenDetails.screens")}} and {{domxref("ScreenDetails.currentScreen")}} properties. + +{{InheritanceDiagram}} + +## Instance properties + +_Inherits properties from its parent, {{DOMxRef("Screen")}}._ + +- {{domxref("ScreenDetailed.availLeft", "availLeft")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A number representing the x-coordinate (left hand edge) of the available screen area. +- {{domxref("ScreenDetailed.availTop", "availTop")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A number representing the y-coordinate (top edge) of the available screen area. +- {{domxref("ScreenDetailed.devicePixelRatio", "devicePixelRatio")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A number representing the screen's device pixel ratio. +- {{domxref("ScreenDetailed.isInternal", "isInternal")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A boolean indicating whether the screen is internal to the device or external. +- {{domxref("ScreenDetailed.isPrimary", "isPrimary")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A boolean indicating whether the screen is set as the operating system (OS) primary screen or not. +- {{domxref("ScreenDetailed.label", "label")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A string providing a descriptive label for the screen, for example "Built-in Retina Display". +- {{domxref("ScreenDetailed.left", "left")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A number representing the x-coordinate (left hand edge) of the total screen area. +- {{domxref("ScreenDetailed.top", "top")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A number representing the y-coordinate (top edge) of the total screen area. + +## Examples + +When {{domxref("Window.getScreenDetails()")}} is invoked, the user will be asked for permission to manage windows on all their displays (the status of this permission can be checked using {{domxref("Permissions.query()")}} to query `window-management`). Provided they grant permission, the resulting {{domxref("ScreenDetails")}} object contains details of all the screens available to the user's system. + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the number of screens +const noOfScreens = screenDetails.screens.length; +``` + +You'll still need to use {{domxref("Window.open()")}} to open and manage windows, but the above provides you with better information for doing so in a multi-screen environment. For example, a utility function might look like so: + +```js +function openWindow(left, top, width, height, url) { + const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; + const windowRef = window.open( + url, + Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab + windowFeatures, + ); + + // Store a reference to the window in the windowRefs array + windowRefs.push(windowRef); +} +``` + +Each item inside the {{domxref("ScreenDetails.screens")}} array is a `ScreenDetailed` object, which can be used to place a window on a specific screen available to the current device. + +```js +const screen1 = screenDetails.screens[0]; +const screen2 = screenDetails.screens[1]; +// Windows will be a third the width and the full height of the screen +let windowWidth = Math.floor((screen1.availWidth - 3 * WINDOW_CHROME_X) / 3); +let windowHeight = Math.floor(screen1.availHeight - WINDOW_CHROME_Y); + +// Open the reference windows in thirds across the entire height of the primary screen +openWindow( + screen1.availLeft, + screen1.availTop, + windowWidth, + windowHeight, + sites[1].url, +); + +// ... +``` + +> **Note:** See [Multi-window learning environment](https://mdn.github.io/dom-examples/window-management-api/) for a full example (see the [source code](https://github.com/mdn/dom-examples/tree/main/window-management-api) also). + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/isinternal/index.md b/files/en-us/web/api/screendetailed/isinternal/index.md new file mode 100644 index 000000000000000..c344a8b6ae284d0 --- /dev/null +++ b/files/en-us/web/api/screendetailed/isinternal/index.md @@ -0,0 +1,39 @@ +--- +title: "ScreenDetailed: isInternal property" +short-title: isInternal +slug: Web/API/ScreenDetailed/isInternal +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.isInternal +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`isInternal`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a boolean indicating whether the screen is internal to the device or external. External devices are generally manufactured separately from the device they are attached to and can be connected and disconnected as needed, whereas internal screens are part of the device and not intended to be disconnected. + +## Value + +A boolean value — `true` if the screen is internal, and `false` if it is external. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Is the first screen internal? +const screen1Internal = screenDetails.screens[0].isInternal; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/isprimary/index.md b/files/en-us/web/api/screendetailed/isprimary/index.md new file mode 100644 index 000000000000000..b7ded2ac9f88415 --- /dev/null +++ b/files/en-us/web/api/screendetailed/isprimary/index.md @@ -0,0 +1,41 @@ +--- +title: "ScreenDetailed: isPrimary property" +short-title: isPrimary +slug: Web/API/ScreenDetailed/isPrimary +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.isPrimary +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`isPrimary`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a boolean indicating whether the screen is set as the operating system (OS) primary screen or not. + +The OS hosting the browser will have one primary screen, and one or more secondary screens. The primary screen can usually be specified by the user via OS settings, and generally contains OS UI features such as the taskbar/icon dock. The primary screen may change for a number of resons, such as a screen being unplugged. + +## Value + +A boolean value — `true` if the screen is primary, and `false` if it is secondary. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Is the first screen primary? +const screen1Primary = screenDetails.screens[0].isPrimary; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/label/index.md b/files/en-us/web/api/screendetailed/label/index.md new file mode 100644 index 000000000000000..b74e5b7ce46ff93 --- /dev/null +++ b/files/en-us/web/api/screendetailed/label/index.md @@ -0,0 +1,41 @@ +--- +title: "ScreenDetailed: label property" +short-title: label +slug: Web/API/ScreenDetailed/label +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.label +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`label`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a string providing a descriptive label for the screen, for example "Built-in Retina Display". + +This is useful for constructing a list of options to display to the user if you want them to choose a screen to display content on. + +## Value + +A string. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the label of the first screen +const screen1Label = screenDetails.screens[0].label; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/left/index.md b/files/en-us/web/api/screendetailed/left/index.md new file mode 100644 index 000000000000000..9e37ca6a4b6cd57 --- /dev/null +++ b/files/en-us/web/api/screendetailed/left/index.md @@ -0,0 +1,41 @@ +--- +title: "ScreenDetailed: left property" +short-title: left +slug: Web/API/ScreenDetailed/left +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.left +--- + +{{APIRef("Window Management API")}}{{seecompattable}} + +The **`left`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a number representing the x-coordinate (left-hand edge) of the total screen area inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + +This is equal to the true left-hand edge, ignoring any OS UI element drawn at the left of the screen. Windows cannot be placed in those areas; to get the left-hand coordinate of the screen area that windows can be placed in, use {{domxref("ScreenDetailed.availLeft")}}. + +## Value + +A number. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the absolute left value of the first screen +const screen1Left = screenDetails.screens[0].left; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetailed/top/index.md b/files/en-us/web/api/screendetailed/top/index.md new file mode 100644 index 000000000000000..9e90fec1ac844b9 --- /dev/null +++ b/files/en-us/web/api/screendetailed/top/index.md @@ -0,0 +1,41 @@ +--- +title: "ScreenDetailed: top property" +short-title: top +slug: Web/API/ScreenDetailed/top +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetailed.top +--- + +{{APIRef("Window Management API")}}{{seecompattable}} + +The **`top`** read-only property of the +{{domxref("ScreenDetailed")}} interface is a number representing the y-coordinate (top edge) of the total screen area inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + +This is equal to the true top edge, ignoring any OS UI element drawn at the top of the screen. Windows cannot be placed in those areas; to get the top coordinate of the screen area that windows can be placed in, use {{domxref("ScreenDetailed.availTop")}}. + +## Value + +A number. + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the absolute top value of the first screen +const screen1Top = screenDetails.screens[0].top; +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetails/currentscreen/index.md b/files/en-us/web/api/screendetails/currentscreen/index.md new file mode 100644 index 000000000000000..03f8797242d4454 --- /dev/null +++ b/files/en-us/web/api/screendetails/currentscreen/index.md @@ -0,0 +1,71 @@ +--- +title: "ScreenDetails: currentScreen property" +short-title: currentScreen +slug: Web/API/ScreenDetails/currentScreen +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetails.currentScreen +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`currentScreen`** read-only property of the +{{domxref("ScreenDetails")}} interface contains a single {{domxref("ScreenDetailed")}} object representing detailed information about the screen that the current browser window is displayed in. + +## Value + +A {{domxref("ScreenDetailed")}} object. + +## Examples + +```js +// Utility function for opening new windows +function openWindow(left, top, width, height, url) { + const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; + const windowRef = window.open( + url, + Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab + windowFeatures, + ); + + // Store a reference to the window in a windowRefs array + windowRefs.push(windowRef); +} + +// Constants to represent the width and height of the Chrome UI when calculating the window size to open +const WINDOW_CHROME_Y = 51; +const WINDOW_CHROME_X = 1; + +const screenDetails = await window.getScreenDetails(); + +// Return the current screen +const curScreen = screenDetails.currentScreen; + +// Windows will be a third the width and the full height of the current screen +let windowWidth = Math.floor((curScreen.availWidth - 3 * WINDOW_CHROME_X) / 3); +let windowHeight = Math.floor(curScreen.availHeight - WINDOW_CHROME_Y); + +// Open the reference windows in thirds across the entire height of the current screen +openWindow( + curScreen.availLeft, + curScreen.availTop, + windowWidth, + windowHeight, + sites[1].url, +); + +// ... +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetails/currentscreenchange_event/index.md b/files/en-us/web/api/screendetails/currentscreenchange_event/index.md new file mode 100644 index 000000000000000..b5787c58476382f --- /dev/null +++ b/files/en-us/web/api/screendetails/currentscreenchange_event/index.md @@ -0,0 +1,69 @@ +--- +title: "ScreenDetails: currentscreenchange event" +short-title: currentscreenchange +slug: Web/API/ScreenDetails/currentscreenchange_event +page-type: web-api-event +status: + - experimental +browser-compat: api.ScreenDetails.currentscreenchange_event +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`currentscreenchange`** event of the {{domxref("ScreenDetails")}} interface is fired when the {{domxref("ScreenDetails.currentScreen")}} changes in some way. + +Specifically, a _change_ in this context means either: + +- The current screen changes to a different screen, i.e., the current browser window is moved to a different screen. +- The current screen's _basic observable properties_ change. These are: + - {{domxref("Screen.width", "width")}} + - {{domxref("Screen.height", "height")}} + - {{domxref("Screen.availWidth", "availWidth")}} + - {{domxref("Screen.availHeight", "availHeight")}} + - {{domxref("Screen.colorDepth", "colorDepth")}} + - {{domxref("Screen.orientation", "orientation")}} +- The current screen's _advanced observable properties_ change. These are: + - The screen's position ((x,y) coordinates of the top-left corner) inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin) + - The screen's available position ((x,y) coordinates of the top-left corner) inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). This is equal to the screen position, plus the width/height of any OS UI elements drawn on the top-left of the screen — windows cannot be placed in those areas + - {{domxref("ScreenDetailed.devicePixelRatio", "devicePixelRatio")}} + - {{domxref("ScreenDetailed.label", "label")}} + - The screen's designation as primary or secondary (see {{domxref("ScreenDetailed.isPrimary", "isPrimary")}}) + - The screen's designation as internal or external (see {{domxref("ScreenDetailed.isInternal", "isInternal")}}) + +## Syntax + +Use the event name in methods like {{domxref("EventTarget.addEventListener", "addEventListener()")}}, or set an event handler property. + +```js +addEventListener("currentscreenchange", (event) => {}); + +oncurrentscreenchange = (event) => {}; +``` + +## Event type + +An event of type `currentscreenchange`, the event object of which is structurally equivalent to an {{domxref("Event")}}. + +{{InheritanceDiagram("Event")}} + +## Examples + +```js +const screenDetails = await window.getScreenDetails(); +screenDetails.addEventListener("currentscreenchange", async (event) => { + const details = screenDetails.currentScreen; + console.log("The current screen has changed.", event, details); +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetails/index.md b/files/en-us/web/api/screendetails/index.md new file mode 100644 index 000000000000000..0d83135d974851f --- /dev/null +++ b/files/en-us/web/api/screendetails/index.md @@ -0,0 +1,118 @@ +--- +title: ScreenDetails +slug: Web/API/ScreenDetails +page-type: web-api-interface +status: + - experimental +browser-compat: api.ScreenDetails +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`ScreenDetails`** interface of the [Window Management API](/en-US/docs/Web/API/Window_Management_API) represents the details of all the screens available to the user's device. + +This information is accessed via the {{domxref("Window.getScreenDetails()")}} method. + +{{InheritanceDiagram}} + +## Instance properties + +_Inherits properties from its parent, {{DOMxRef("Event")}}._ + +- {{domxref("ScreenDetails.screens", "screens")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : An array of {{domxref("ScreenDetailed")}} objects, each one representing detailed information about one specific screen available to the user's device. +- {{domxref("ScreenDetails.currentScreen", "currentScreen")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : A single {{domxref("ScreenDetailed")}} object representing detailed information about the screen that the current browser window is displayed in. + +## Events + +- {{domxref("ScreenDetails.screenschange_event", "screenschange")}} {{experimental_inline}} + - : Fired when the screens available to the system change in some way — for example when a screen is added or removed. +- {{domxref("ScreenDetails.currentscreenchange_event", "currentscreenchange")}} {{experimental_inline}} + - : Fired when the current screen changes in some way — for example available width or height, or orientation. + +## Examples + +> **Note:** See [Multi-window learning environment](https://mdn.github.io/dom-examples/window-management-api/) for a full example (see the [source code](https://github.com/mdn/dom-examples/tree/main/window-management-api) also). + +### Basic screen information access + +When {{domxref("Window.getScreenDetails()")}} is invoked, the user will be asked for permission to manage windows on all their displays (the status of this permission can be checked using {{domxref("Permissions.query()")}} to query `window-management`). Provided they grant permission, the resulting `ScreenDetails` object contains details of all the screens available to the user's system. + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the number of screens +const noOfScreens = screenDetails.screens.length; +``` + +You'll still need to use {{domxref("Window.open()")}} to open and manage windows, but the above provides you with better information for doing so in a multi-screen environment. For example, a utility function might look like so: + +```js +function openWindow(left, top, width, height, url) { + const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; + const windowRef = window.open( + url, + Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab + windowFeatures, + ); + + // Store a reference to the window in the windowRefs array + windowRefs.push(windowRef); +} +``` + +You would then invoke this function and open windows on specific screens like this: + +```js +const screen1 = screenDetails.screens[0]; +const screen2 = screenDetails.screens[1]; +// Windows will be a third the width and the full height of the screen +let windowWidth = Math.floor((screen1.availWidth - 3 * WINDOW_CHROME_X) / 3); +let windowHeight = Math.floor(screen1.availHeight - WINDOW_CHROME_Y); + +// Open the reference windows in thirds across the entire height of the primary screen +openWindow( + screen1.availLeft, + screen1.availTop, + windowWidth, + windowHeight, + sites[1].url, +); + +// ... +``` + +### Responding to changes in available screens + +You could use the `screenschange` event to detect when the available screens have changed (perhaps when a screen is plugged in or unplugged), report the change, close all windows, and then reopen them all to suit the new configuration: + +```js +screenDetails.addEventListener("screenschange", () => { + // If the new number of screens is different to the old number of screens, report the difference + if (screenDetails.screens.length !== noOfScreens) { + console.log( + `The screen count changed from ${noOfScreens} to ${screenDetails.screens.length}`, + ); + } + + // If the windows are open, close them and then open them again + // So that they fit with the new screen configuration + if (windowRefs.length > 0) { + closeAllWindows(); + openWindows(); + } +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetails/screens/index.md b/files/en-us/web/api/screendetails/screens/index.md new file mode 100644 index 000000000000000..c1a82981320ee8a --- /dev/null +++ b/files/en-us/web/api/screendetails/screens/index.md @@ -0,0 +1,34 @@ +--- +title: "ScreenDetails: screens property" +short-title: screens +slug: Web/API/ScreenDetails/screens +page-type: web-api-instance-property +status: + - experimental +browser-compat: api.ScreenDetails.screens +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`screens`** read-only property of the +{{domxref("ScreenDetails")}} interface contains an array of {{domxref("ScreenDetailed")}} objects, each one representing detailed information about one specific screen available to the user's device. + +## Value + +An array of {{domxref("ScreenDetailed")}} objects. + +## Examples + +See the main [`ScreenDetails` page](/en-US/docs/Web/API/ScreenDetails#examples) for example usage. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/screendetails/screenschange_event/index.md b/files/en-us/web/api/screendetails/screenschange_event/index.md new file mode 100644 index 000000000000000..40f55f8e4c6d2ef --- /dev/null +++ b/files/en-us/web/api/screendetails/screenschange_event/index.md @@ -0,0 +1,81 @@ +--- +title: "ScreenDetails: screenschange event" +short-title: screenschange +slug: Web/API/ScreenDetails/screenschange_event +page-type: web-api-event +status: + - experimental +browser-compat: api.ScreenDetails.screenschange_event +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`screenschange`** event of the {{domxref("ScreenDetails")}} interface is fired when the screens available to the system change in some way. + +Specifically, a _change_ in this context means either: + +- A screen ({{domxref("ScreenDetailed")}} object) is added to or removed from the {{domxref("ScreenDetails.screens", "screens")}} array. +- A screen's _basic observable properties_ change. These are: + - {{domxref("Screen.width", "width")}} + - {{domxref("Screen.height", "height")}} + - {{domxref("Screen.availWidth", "availWidth")}} + - {{domxref("Screen.availHeight", "availHeight")}} + - {{domxref("Screen.colorDepth", "colorDepth")}} + - {{domxref("Screen.orientation", "orientation")}} +- A screen's _advanced observable properties_ change. These are: + - The screen's position ((x,y) coordinates of the top-left corner) inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin) + - The screen's available position ((x,y) coordinates of the top-left corner) inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). This is equal to the screen position, plus the width/height of any OS UI elements drawn on the top-left of the screen — windows cannot be placed in those areas + - {{domxref("ScreenDetailed.devicePixelRatio", "devicePixelRatio")}} + - {{domxref("ScreenDetailed.label", "label")}} + - The screen's designation as primary or secondary (see {{domxref("ScreenDetailed.isPrimary", "isPrimary")}}) + - The screen's designation as internal or external (see {{domxref("ScreenDetailed.isInternal", "isInternal")}}) + +## Syntax + +Use the event name in methods like {{domxref("EventTarget.addEventListener", "addEventListener()")}}, or set an event handler property. + +```js +addEventListener("screenschange", (event) => {}); + +onscreenschange = (event) => {}; +``` + +## Event type + +An event of type `screenschange`, the event object of which is structurally equivalent to an {{domxref("Event")}}. + +{{InheritanceDiagram("Event")}} + +## Examples + +You could use the `screenschange` event to detect when the available screens have changed, report the change, close all windows, and then reopen them all to suit the new configuration: + +```js +screenDetails.addEventListener("screenschange", () => { + // If the new number of screens is different to the old number of screens, report the difference + if (screenDetails.screens.length !== noOfScreens) { + console.log( + `The screen count changed from ${noOfScreens} to ${screenDetails.screens.length}`, + ); + } + + // If the windows are open, close them and then open them again + // So that they fit with the new screen configuration + if (windowRefs.length > 0) { + closeAllWindows(); + openWindows(); + } +}); +``` + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/window/getscreendetails/index.md b/files/en-us/web/api/window/getscreendetails/index.md new file mode 100644 index 000000000000000..d36b02c362c62e7 --- /dev/null +++ b/files/en-us/web/api/window/getscreendetails/index.md @@ -0,0 +1,95 @@ +--- +title: "Window: getScreenDetails() method" +short-title: getScreenDetails() +slug: Web/API/Window/getScreenDetails +page-type: web-api-instance-method +status: + - experimental +browser-compat: api.Window.getScreenDetails +--- + +{{APIRef("Window Management API")}}{{SeeCompatTable}} + +The **`getScreenDetails()`** method of the +{{domxref("Window")}} interface returns a {{jsxref("Promise")}} that fulfills with a {{domxref("ScreenDetails")}} object instance representing the details of all the screens available to the user's device. + +## Syntax + +```js-nolint +getScreenDetails() +``` + +### Parameters + +None. + +### Return value + +A {{jsxref("Promise")}} that fulfills with a {{domxref("ScreenDetails")}} object instance. + +### Exceptions + +- `NotAllowedError` {{domxref("DOMException")}} + - : Thrown if a {{httpheader("Permissions-Policy/window-management", "window-management")}} [Permissions-Policy](/en-US/docs/Web/HTTP/Permissions_Policy) is set that blocks use of the [Window Management API](/en-US/docs/Web/API/Window_Management_API), or if the user has explicitly denied the browser's permission request to use the API. + +## Examples + +When `getScreenDetails()` is invoked, the user will be asked for permission to manage windows on all their displays (the status of this permission can be checked using {{domxref("Permissions.query()")}} to query `window-management`). Provided they grant permission, the resulting {{domxref("ScreenDetails")}} object contains details of all the screens available to the user's system. + +```js +const screenDetails = await window.getScreenDetails(); + +// Return the number of screens +const noOfScreens = screenDetails.screens.length; +``` + +You'll still need to use {{domxref("Window.open()")}} to open and manage windows, but the above provides you with better information for doing so in a multi-screen environment. For example, a utility function might look like so: + +```js +function openWindow(left, top, width, height, url) { + const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; + const windowRef = window.open( + url, + Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab + windowFeatures, + ); + + // Store a reference to the window in the windowRefs array + windowRefs.push(windowRef); +} +``` + +You would then invoke this function and open windows on specific screens like this: + +```js +const screen1 = screenDetails.screens[0]; +const screen2 = screenDetails.screens[1]; +// Windows will be a third the width and the full height of the screen +let windowWidth = Math.floor((screen1.availWidth - 3 * WINDOW_CHROME_X) / 3); +let windowHeight = Math.floor(screen1.availHeight - WINDOW_CHROME_Y); + +// Open the reference windows in thirds across the entire height of the primary screen +openWindow( + screen1.availLeft, + screen1.availTop, + windowWidth, + windowHeight, + sites[1].url, +); + +// ... +``` + +> **Note:** See [Multi-window learning environment](https://mdn.github.io/dom-examples/window-management-api/) for a full example (see the [source code](https://github.com/mdn/dom-examples/tree/main/window-management-api) also). + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) diff --git a/files/en-us/web/api/window/index.md b/files/en-us/web/api/window/index.md index f30fc1ba89557ff..25b564045735cb0 100644 --- a/files/en-us/web/api/window/index.md +++ b/files/en-us/web/api/window/index.md @@ -197,6 +197,8 @@ _This interface inherits methods from the {{domxref("EventTarget")}} interface._ - : Gets computed style for the specified element. Computed style indicates the computed values of all CSS properties of the element. - {{domxref("Window.getDefaultComputedStyle()")}} {{Non-standard_Inline}} - : Gets default computed style for the specified element, ignoring author stylesheets. +- {{domxref("Window.getScreenDetails()")}} {{experimental_inline}} + - : Returns a {{jsxref("Promise")}} that fulfills with a {{domxref("ScreenDetails")}} object instance representing the details of all the screens available to the user's device. - {{domxref("Window.getSelection()")}} - : Returns the selection object representing the selected item(s). - {{domxref("Window.matchMedia()")}} diff --git a/files/en-us/web/api/window_management_api/index.md b/files/en-us/web/api/window_management_api/index.md index 4379d8ee4ef8b23..343d7ff0391e413 100644 --- a/files/en-us/web/api/window_management_api/index.md +++ b/files/en-us/web/api/window_management_api/index.md @@ -29,6 +29,10 @@ However, the above features are limited. `Window.screen` only returns data about The Window Management API provides more robust, flexible window management. It allows you to query whether your display is extended with multiple screens and return information on each screen separately: windows can then be placed on each screen as desired. It also provides event handlers to allow you to respond to changes in the available screens, new fullscreen functionality to choose which screen to put into fullscreen mode (if any), and permissions functionality to control access to the API. +### Multi-screen origin + +xx + ## Use cases The Window Management API is useful in cases such as: @@ -66,7 +70,7 @@ When `getScreenDetails()` is invoked, the user will be asked for permission to m - `availLeft` and `availTop` - : The top-left coordinate of the screen area available for opening windows in. These values are equal to `left` and `top`, plus the width/height of any OS-specific user interface elements drawn at the top-left of the screen. - `isPrimary` - - : A boolean indicating whether this screen is set as the OS primary screen or not. + - : A boolean indicating whether this screen is set as the operating system (OS) primary screen or not. - `isInternal` - : A boolean indicating whether this screen is internal to the device or not. - `label` @@ -189,7 +193,7 @@ try { The {{httpheader("Permissions-Policy/window-management", "window-management")}} [Permissions-Policy](/en-US/docs/Web/HTTP/Permissions_Policy) can be used to control permission to use the Window Management API. Specifically: - Usage of the {{domxref("Window.getScreenDetails()")}} method. If blocked, its {{jsxref("Promise")}} will reject with a `NotAllowedError` exception. -- Querying the {{domxref("Window.screen.isExtended")}} property. If blocked, it will always return `false`. +- Querying the {{domxref("Screen.isExtended", "Window.screen.isExtended")}} property. If blocked, it will always return `false`. Developers can explicitly grant permission for an {{htmlelement("iframe")}} to use Window Management via the `allow` attribute: @@ -206,8 +210,10 @@ Developers can explicitly grant permission for an {{htmlelement("iframe")}} to u ## Extensions to other interfaces +- The `Screen` {{domxref("Screen.change_event", "change")}} event + - : Fired on a specific screen when it changes in some way — for example available width or height, or orientation. - {{domxref("Screen.isExtended")}} - - : A boolean property that returns `true` if the device has multiple screens, and `false` if not. + - : A boolean property that returns `true` if the user's device has multiple screens, and `false` if not. - {{domxref("Element.requestFullscreen()")}}, the `screen` option - : Specifies on which screen you want to put the element in fullscreen mode. - {{domxref("Window.getScreenDetails()")}} diff --git a/files/en-us/web/http/headers/permissions-policy/index.md b/files/en-us/web/http/headers/permissions-policy/index.md index f0a1b503a6083a0..4b9ef630d640c01 100644 --- a/files/en-us/web/http/headers/permissions-policy/index.md +++ b/files/en-us/web/http/headers/permissions-policy/index.md @@ -193,6 +193,10 @@ You can specify - : Controls whether or not the current document is allowed to use the {{domxref("Navigator.share","Navigator.share()")}} of Web Share API to share text, links, images, and other content to arbitrary destinations of user's choice, e.g. mobile apps. +- {{httpheader("Permissions-Policy/window-management", "window-management")}} + + - : Controls whether or not the current document is allowed to use the [Window Management API](/en-US/docs/Web/API/Window_Management_API) to manage windows on multiple displays. + - {{httpheader("Permissions-Policy/xr-spatial-tracking", "xr-spatial-tracking")}} {{Experimental_Inline}} - : Controls whether or not the current document is allowed to use the [WebXR Device API](/en-US/docs/Web/API/WebXR_Device_API) to interact with a WebXR session. diff --git a/files/en-us/web/http/headers/permissions-policy/window-management/index.md b/files/en-us/web/http/headers/permissions-policy/window-management/index.md new file mode 100644 index 000000000000000..bfd5475eed856c9 --- /dev/null +++ b/files/en-us/web/http/headers/permissions-policy/window-management/index.md @@ -0,0 +1,44 @@ +--- +title: "Permissions-Policy: window-management" +slug: Web/HTTP/Headers/Permissions-Policy/window-management +page-type: http-permissions-policy-directive +status: + - experimental +browser-compat: http.headers.Permissions-Policy.window-management +--- + +{{HTTPSidebar}}{{SeeCompatTable}} + +The HTTP {{HTTPHeader("Permissions-Policy")}} header `window-management` directive controls whether or not the current document is allowed to use the [Window Management API](/en-US/docs/Web/API/Window_Management_API) to manage windows on multiple displays. + +Where this policy forbids use of the API: + +- {{jsxref("Promise", "Promises")}} returned by the {{domxref("Window.getScreenDetails()")}} method will reject with a `NotAllowedError` exception. +- The {{domxref("Screen.isExtended", "Window.screen.isExtended")}} property will always return `false`. + +## Syntax + +```http +Permissions-Policy: window-management=; +``` + +- `` + - : A list of origins for which permission is granted to use the feature. See [`Permissions-Policy` > Syntax](/en-US/docs/Web/HTTP/Headers/Permissions-Policy#syntax) for more details. + +## Default policy + +The default allowlist for `window-management` is `self`. + +## Specifications + +{{Specifications}} + +## Browser compatibility + +{{Compat}} + +## See also + +- [Window Management API](/en-US/docs/Web/API/Window_Management_API) +- {{HTTPHeader("Permissions-Policy")}} header +- [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) From 6321a5e8427588d66c64f3a738b2c4e3a87da36b Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 5 Sep 2023 10:02:31 +0100 Subject: [PATCH 3/5] Adding information about the multi-screen origin --- files/en-us/web/api/screendetails/index.md | 2 + files/en-us/web/api/window/moveto/index.md | 2 + files/en-us/web/api/window/open/index.md | 2 + .../en-us/web/api/window/screenleft/index.md | 2 + files/en-us/web/api/window/screentop/index.md | 2 + files/en-us/web/api/window/screenx/index.md | 2 + files/en-us/web/api/window/screeny/index.md | 2 + .../web/api/window_management_api/index.md | 34 +++++-- .../primary-screen-left-source.drawio | 85 ++++++++++++++++++ .../primary-screen-left.png | Bin 0 -> 15032 bytes .../primary-screen-right-source.drawio | 85 ++++++++++++++++++ .../primary-screen-right.png | Bin 0 -> 15573 bytes 12 files changed, 212 insertions(+), 6 deletions(-) create mode 100644 files/en-us/web/api/window_management_api/primary-screen-left-source.drawio create mode 100644 files/en-us/web/api/window_management_api/primary-screen-left.png create mode 100644 files/en-us/web/api/window_management_api/primary-screen-right-source.drawio create mode 100644 files/en-us/web/api/window_management_api/primary-screen-right.png diff --git a/files/en-us/web/api/screendetails/index.md b/files/en-us/web/api/screendetails/index.md index 0d83135d974851f..c5087fd9e414060 100644 --- a/files/en-us/web/api/screendetails/index.md +++ b/files/en-us/web/api/screendetails/index.md @@ -13,6 +13,8 @@ The **`ScreenDetails`** interface of the [Window Management API](/en-US/docs/Web This information is accessed via the {{domxref("Window.getScreenDetails()")}} method. +> **Note:** `ScreenDetails` is a live object, meaning that it updates as the available screens change. You can therefore keep querying the same object to get updated values, rather than repeatedly calling `getScreenDetails()`. + {{InheritanceDiagram}} ## Instance properties diff --git a/files/en-us/web/api/window/moveto/index.md b/files/en-us/web/api/window/moveto/index.md index 7fbd72490c38c9b..1d5f4f253ce8d9f 100644 --- a/files/en-us/web/api/window/moveto/index.md +++ b/files/en-us/web/api/window/moveto/index.md @@ -15,6 +15,8 @@ interface moves the current window to the specified coordinates. > contrast, {{domxref("window.moveBy()")}} moves the window relative to its current > location. +> **Note:** On devices with multiple displays, `moveTo()` positions windows relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + ## Syntax ```js-nolint diff --git a/files/en-us/web/api/window/open/index.md b/files/en-us/web/api/window/open/index.md index 07830bd14557264..82b17af73972a04 100644 --- a/files/en-us/web/api/window/open/index.md +++ b/files/en-us/web/api/window/open/index.md @@ -10,6 +10,8 @@ browser-compat: api.Window.open The **`open()`** method of the [`Window`](/en-US/docs/Web/API/Window) interface loads a specified resource into a new or existing browsing context (that is, a tab, a window, or an [iframe](/en-US/docs/Web/HTML/Element/iframe)) under a specified name. +> **Note:** On devices with multiple displays, `open()` positions windows relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + ## Syntax ```js-nolint diff --git a/files/en-us/web/api/window/screenleft/index.md b/files/en-us/web/api/window/screenleft/index.md index 6369cb511d1f437..8522a04ed10903b 100644 --- a/files/en-us/web/api/window/screenleft/index.md +++ b/files/en-us/web/api/window/screenleft/index.md @@ -16,6 +16,8 @@ to the left side of the screen. > {{domxref("Window.screenX")}} property. `screenLeft` was originally > supported only in IE but was introduced everywhere due to popularity. +> **Note:** On devices with multiple displays, browsers will report the value of `screenTop` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + ## Value A number equal to the number of CSS pixels from the left edge of the browser viewport diff --git a/files/en-us/web/api/window/screentop/index.md b/files/en-us/web/api/window/screentop/index.md index dc3c62e60988de7..0c7ac0297b221eb 100644 --- a/files/en-us/web/api/window/screentop/index.md +++ b/files/en-us/web/api/window/screentop/index.md @@ -16,6 +16,8 @@ the top side of the screen. > {{domxref("Window.screenY")}} property. `screenTop` was originally > supported only in IE but was introduced everywhere due to popularity. +> **Note:** On devices with multiple displays, browsers will report the value of `screenTop` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + ## Value A number equal to the number of CSS pixels from the top edge of the browser viewport to diff --git a/files/en-us/web/api/window/screenx/index.md b/files/en-us/web/api/window/screenx/index.md index 6c6c53dde78d34b..e455ee0a82b29a8 100644 --- a/files/en-us/web/api/window/screenx/index.md +++ b/files/en-us/web/api/window/screenx/index.md @@ -16,6 +16,8 @@ the left side of the screen. > browsers in more recent times — {{domxref("Window.screenLeft")}}. This was originally > supported only in IE but was introduced everywhere due to popularity. +> **Note:** On devices with multiple displays, browsers will report the value of `screenX` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + ## Value A number equal to the number of CSS pixels from the left edge of the browser viewport diff --git a/files/en-us/web/api/window/screeny/index.md b/files/en-us/web/api/window/screeny/index.md index 75911c20e8fea99..0d0d7da46b8b3c8 100644 --- a/files/en-us/web/api/window/screeny/index.md +++ b/files/en-us/web/api/window/screeny/index.md @@ -12,6 +12,8 @@ The **`Window.screenY`** read-only property returns the vertical distance, in CS > **Note:** An alias of `screenY` was implemented across modern browsers in more recent times — {{domxref("Window.screenTop")}}. This was originally supported only in IE but was introduced everywhere due to popularity. +> **Note:** On devices with multiple displays, browsers will report the value of `screenY` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). + ## Value A number equal to the number of CSS pixels from the top edge of the browser viewport to the top edge of the screen. diff --git a/files/en-us/web/api/window_management_api/index.md b/files/en-us/web/api/window_management_api/index.md index 343d7ff0391e413..20a25af10baf125 100644 --- a/files/en-us/web/api/window_management_api/index.md +++ b/files/en-us/web/api/window_management_api/index.md @@ -25,13 +25,35 @@ const myWindow = window.open( You can retrieve information about your screen from the {{domxref("Window.screen")}} property, such as how much screen space you have available to place windows in. -However, the above features are limited. `Window.screen` only returns data about the primary screen, and not the other monitors attached to a device. To move a window to a second monitor for example, you could use {{domxref("Window.MoveTo()")}}, but you'd have to guess what coordinates to use based on where it is placed in your setup relative to the primary display. +However, the above features are limited. `Window.screen` only returns data about the primary screen, and not secondary displays available to a device. To move a window to a secondary display, you could use {{domxref("Window.MoveTo()")}}, but you'd have to guess what coordinates to use based on where it is placed in your setup relative to the primary display. The Window Management API provides more robust, flexible window management. It allows you to query whether your display is extended with multiple screens and return information on each screen separately: windows can then be placed on each screen as desired. It also provides event handlers to allow you to respond to changes in the available screens, new fullscreen functionality to choose which screen to put into fullscreen mode (if any), and permissions functionality to control access to the API. ### Multi-screen origin -xx +The Window Management API introduces the concept of the **multi-screen origin** — this is the (0,0) coordinate of the host operating system (OS)'s virtual screen arrangement, around which all available screens and windows are positioned. The multi-screen origin is the top-left corner of the OS primary screen (which can usually be specified by the user via OS settings, and generally contains OS UI features such as the taskbar/icon dock). + +On devices with multiple displays: + +- The values of {{domxref("ScreenDetailed.left")}}, {{domxref("ScreenDetailed.top")}}, {{domxref("ScreenDetailed.availLeft")}}, and {{domxref("ScreenDetailed.availTop")}} for each available screen are reported relative to the multi-screen origin. +- The values of {{domxref("Window.screenLeft")}}, {{domxref("Window.screenTop")}}, {{domxref("Window.screenX")}}, {{domxref("Window.screenY")}} for each window are reported relative to the multi-screen origin. +- When using {{domxref("Window.moveTo()")}} and {{domxref("Window.open()")}}, windows are positioned relative to the multi-screen origin. + +Say we have an external monitor of resolution 1920 x 1080 set as the primary monitor, and an internal laptop display of resolution 1440 x 900 set as a secondary monitor. Let's also say that the OS UI takes up 25px at the top of the screen, and is only drawn on the primary screen. + +If the secondary screen was positioned directly to the right of the primary screen, top screen edges in line: + +- The primary screen `left`/`top` values would be (0,0) while its `availLeft`/`availTop` values would be (0,25) — the OS UI thickness is added on. +- The secondary screen `left`/`top` values would be (1920,0) while its `availLeft`/`availTop` values would also be (1920,0) — the OS UI is not drawn on the secondary screen. + +![Two rectangles representing the primary screen with the secondary screen positioned to the right, as described above](primary-screen-left.png) + +However, if the secondary screen was positioned directly to the left of the primary screen, top screen edges in line: + +- The primary screen `left`/`top` values would still be (0,0) while its `availLeft`/`availTop` values would be (0,25). +- The secondary screen `left`/`top` values would be (-1440,0) while its `availLeft`/`availTop` values would also be (-1440,0). + +![Two rectangles representing the primary screen with the secondary screen positioned to the left, as described above](primary-screen-right.png) ## Use cases @@ -66,11 +88,11 @@ When `getScreenDetails()` is invoked, the user will be asked for permission to m {{domxref("ScreenDetailed")}} objects inherit the properties of the {{domxref("Screen")}} interface, and contain useful information for placing windows on specific screens. For example: - `availWidth` and `availHeight` - - : The width and height of the screen area available for opening windows in. These values are equal to `width` and `height`, plus the width/height of any OS-specific user interface elements drawn on the screen. + - : The width and height of the screen area available for opening windows in. These values are equal to `width` and `height`, minus the width/height of any OS-specific user interface elements drawn on the screen. - `availLeft` and `availTop` - - : The top-left coordinate of the screen area available for opening windows in. These values are equal to `left` and `top`, plus the width/height of any OS-specific user interface elements drawn at the top-left of the screen. + - : The top-left coordinate of the screen area available for opening windows in. These values are equal to `left` and `top`, plus the width/height of any OS-specific user interface elements drawn at the top/left of the screen. - `isPrimary` - - : A boolean indicating whether this screen is set as the operating system (OS) primary screen or not. + - : A boolean indicating whether this screen is set as the OS primary screen or not. - `isInternal` - : A boolean indicating whether this screen is internal to the device or not. - `label` @@ -140,7 +162,7 @@ function checkWindowClose() { }); ``` -> **Note:** In our experiments, the {{domxref("setInterval()")}} polling method shown above seemed to work best for detecting window closure in the case of multiple windows. Using events such as {{domxref("Window.beforeunload_event", "beforeunload")}}, {{domxref("Window.pagehide_event", "pagehide")}}, or {{domxref("Document.visibilitychange_event", "visibilitychange")}} proved unreliable because, when opening multiple windows in the first place, the rapid shift in focus/visibility seemed to fire the handler function prematurely. +> **Note:** In our experiments, the {{domxref("setInterval()")}} polling method shown above seemed to work best for detecting window closure in the case of multiple windows. Using events such as {{domxref("Window.beforeunload_event", "beforeunload")}}, {{domxref("Window.pagehide_event", "pagehide")}}, or {{domxref("Document.visibilitychange_event", "visibilitychange")}} proved unreliable because, when opening multiple windows at the same time, the rapid shift in focus/visibility seemed to fire the handler function prematurely. ### Window management events diff --git a/files/en-us/web/api/window_management_api/primary-screen-left-source.drawio b/files/en-us/web/api/window_management_api/primary-screen-left-source.drawio new file mode 100644 index 000000000000000..fb52def990d813d --- /dev/null +++ b/files/en-us/web/api/window_management_api/primary-screen-left-source.drawio @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/en-us/web/api/window_management_api/primary-screen-left.png b/files/en-us/web/api/window_management_api/primary-screen-left.png new file mode 100644 index 0000000000000000000000000000000000000000..02b0c323fb4d960681bbdf6f42240fc34dad9f3a GIT binary patch literal 15032 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 F{$Gd!(hdLs literal 0 HcmV?d00001 diff --git a/files/en-us/web/api/window_management_api/primary-screen-right-source.drawio b/files/en-us/web/api/window_management_api/primary-screen-right-source.drawio new file mode 100644 index 000000000000000..ef030426dfb67f3 --- /dev/null +++ b/files/en-us/web/api/window_management_api/primary-screen-right-source.drawio @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/en-us/web/api/window_management_api/primary-screen-right.png b/files/en-us/web/api/window_management_api/primary-screen-right.png new file mode 100644 index 0000000000000000000000000000000000000000..6e81abaf1f5a4a36636459c40415f209c10535ff GIT binary patch literal 15573 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 literal 0 HcmV?d00001 From 91938236427a6aafd4e1a7abd51fc22e2f8b11e3 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Tue, 17 Oct 2023 14:41:51 +0100 Subject: [PATCH 4/5] Making fixes for michaelwasserman comments --- .../api/element/requestfullscreen/index.md | 4 +- .../web/api/screen/change_event/index.md | 4 +- files/en-us/web/api/screen/index.md | 15 ++++- .../en-us/web/api/screen/isextended/index.md | 2 +- .../web/api/screendetailed/availleft/index.md | 15 ++++- .../web/api/screendetailed/availtop/index.md | 15 ++++- .../screendetailed/devicepixelratio/index.md | 7 +- files/en-us/web/api/screendetailed/index.md | 8 +-- .../web/api/screendetailed/left/index.md | 13 ++++ .../en-us/web/api/screendetailed/top/index.md | 13 ++++ .../api/screendetails/currentscreen/index.md | 40 +++--------- files/en-us/web/api/screendetails/index.md | 65 ++++++------------- .../screenschange_event/index.md | 26 +------- .../web/api/window/getscreendetails/index.md | 45 +++---------- files/en-us/web/api/window/moveto/index.md | 2 - files/en-us/web/api/window/open/index.md | 2 - .../en-us/web/api/window/screenleft/index.md | 2 +- files/en-us/web/api/window/screentop/index.md | 2 +- .../web/api/window_management_api/index.md | 57 +++++++++++----- 19 files changed, 165 insertions(+), 172 deletions(-) diff --git a/files/en-us/web/api/element/requestfullscreen/index.md b/files/en-us/web/api/element/requestfullscreen/index.md index 77183e25e972efe..9c67e1180f23134 100644 --- a/files/en-us/web/api/element/requestfullscreen/index.md +++ b/files/en-us/web/api/element/requestfullscreen/index.md @@ -165,9 +165,9 @@ If you wanted to make the element fullscreen on the primary OS screen, you could ```js try { - const primaryScreen = (await getScreenDetails()).screens.filter( + const primaryScreen = (await getScreenDetails()).screens.find( (screen) => screen.isPrimary, - )[0]; + ); await document.body.requestFullscreen({ screen: primaryScreen }); } catch (err) { console.error(err.name, err.message); diff --git a/files/en-us/web/api/screen/change_event/index.md b/files/en-us/web/api/screen/change_event/index.md index 62f14ba84ebefd0..0b66017f54ad6c9 100644 --- a/files/en-us/web/api/screen/change_event/index.md +++ b/files/en-us/web/api/screen/change_event/index.md @@ -40,8 +40,8 @@ An event of type `change`, the event object of which is structurally equivalent ## Examples ```js -const firstScreen = (await window.getScreenDetails())[0]; -firstScreen.addEventListener("change", async (event) => { +const firstScreen = (await window.getScreenDetails()).screens[0]; +firstScreen.addEventListener("change", (event) => { console.log("The first screen has changed.", event, firstScreen); }); ``` diff --git a/files/en-us/web/api/screen/index.md b/files/en-us/web/api/screen/index.md index 54f5c48715d1710..d656d522f8a266f 100644 --- a/files/en-us/web/api/screen/index.md +++ b/files/en-us/web/api/screen/index.md @@ -38,6 +38,19 @@ _Also inherits properties from its parent {{domxref("EventTarget")}}_. - {{DOMxRef("Screen.mozBrightness")}} {{Non-standard_Inline}} {{Deprecated_Inline}} - : Controls the brightness of a device's screen. A double between 0 and 1.0 is expected. +## Non-standard properties + +The following properties are standardized as part of the [Window Management API](/en-US/docs/Web/API/Window_Management_API), thus we have chosen to document their standard form, which is available on the {{domxref("ScreenDetailed")}} interface. However, non-standard versions of these properties are available on the `Screen` interface. + +- {{domxref("ScreenDetailed.availLeft", "Screen.availLeft")}} {{ReadOnlyInline}} {{Non-standard_Inline}} + - : A number representing the x-coordinate (left-hand edge) of the available screen area. +- {{domxref("ScreenDetailed.availTop", "Screen.availTop")}} {{ReadOnlyInline}} {{Non-standard_Inline}} + - : A number representing the y-coordinate (top edge) of the available screen area. +- {{domxref("ScreenDetailed.left", "Screen.left")}} {{ReadOnlyInline}} {{Non-standard_Inline}} + - : A number representing the x-coordinate (left-hand edge) of the total screen area. +- {{domxref("ScreenDetailed.top", "Screen.top")}} {{ReadOnlyInline}} {{Non-standard_Inline}} + - : A number representing the y-coordinate (top edge) of the total screen area. + ## Instance methods _Also inherits methods from its parent {{domxref("EventTarget")}}_. @@ -54,7 +67,7 @@ _Also inherits methods from its parent {{domxref("EventTarget")}}_. - {{DOMxRef("Screen.orientationchange_event", "orientationchange")}} {{Deprecated_Inline}} {{Non-standard_Inline}} - : Fires when the screen orientation changes. -## Example +## Examples ```js if (screen.pixelDepth < 8) { diff --git a/files/en-us/web/api/screen/isextended/index.md b/files/en-us/web/api/screen/isextended/index.md index 30edf9d5dcb08c9..e6407a02cfa6a0d 100644 --- a/files/en-us/web/api/screen/isextended/index.md +++ b/files/en-us/web/api/screen/isextended/index.md @@ -13,7 +13,7 @@ browser-compat: api.Screen.isExtended The **`isExtended`** read-only property of the {{domxref("Screen")}} interface returns `true` if the user's device has multiple screens, and `false` if not. -This property is most commonly accessed via `window.screen.isExtended`, and provides a useful test to see if multiple screens are available before attempting to create a multi-window, multi-screen layout using the [Window Management API](/en-US/docs/Web/API/Window_Management_API). However, since {{domxref("ScreenDetailed")}} inherits from `Screen`, `isExtended` is also available on all `ScreenDetailed` object instances contained inside the {{domxref("ScreenDetails")}} object returned by {{domxref("Window.getScreenDetails()")}}. When multiple screens are available, all `isExtended` properties will be `true`. +This property is typically accessed via `window.screen.isExtended`, and provides a useful test to see if multiple screens are available before attempting to create a multi-window, multi-screen layout using the [Window Management API](/en-US/docs/Web/API/Window_Management_API). ## Value diff --git a/files/en-us/web/api/screendetailed/availleft/index.md b/files/en-us/web/api/screendetailed/availleft/index.md index 9dfb9495c96d2bb..4a47c1d9e85ed69 100644 --- a/files/en-us/web/api/screendetailed/availleft/index.md +++ b/files/en-us/web/api/screendetailed/availleft/index.md @@ -13,7 +13,9 @@ browser-compat: api.ScreenDetailed.availLeft The **`availLeft`** read-only property of the {{domxref("ScreenDetailed")}} interface is a number representing the x-coordinate (left-hand edge) of the available screen area inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). -This is equal to the {{domxref("ScreenDetailed.left")}} property, plus the width of any OS UI element drawn on the left of the screen. Windows cannot be placed in those areas, so `availLeft` is useful for giving you the left boundary of the actual area you've got available. +This is equal to the {{domxref("ScreenDetailed.left")}} property, plus the width of any OS UI element drawn on the left of the screen. Windows cannot be placed in those areas, so `availLeft` is useful for giving you the left boundary of the actual area available to open or place windows. + +> **Note:** A non-standard implementation of the `availLeft` property is available on the `Screen` interface in all browsers. This represents the x-coordinate (left-hand edge) of the _current_ screen's available area (i.e. the screen containing the browser window the code is being run in). See the [Non-standard example](#non-standard_example) below for usage details, and see the [`Screen`](/en-US/docs/Web/API/Screen#browser_compatibility) reference page for browser support information relating to the non-standard implementation. ## Value @@ -21,13 +23,24 @@ A number. ## Examples +### Window Management API example + ```js +// Available in browsers that support the Window Management API const screenDetails = await window.getScreenDetails(); // Return the availLeft value of the first screen const screen1AvailLeft = screenDetails.screens[0].availLeft; ``` +### Non-standard example + +```js +// Available in all browsers +// Return the availLeft value of the current screen +const screenAvailLeft = window.screen.availLeft; +``` + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/screendetailed/availtop/index.md b/files/en-us/web/api/screendetailed/availtop/index.md index 81944dbfae9a2a8..648dee15a25f680 100644 --- a/files/en-us/web/api/screendetailed/availtop/index.md +++ b/files/en-us/web/api/screendetailed/availtop/index.md @@ -13,7 +13,9 @@ browser-compat: api.ScreenDetailed.availTop The **`availTop`** read-only property of the {{domxref("ScreenDetailed")}} interface is a number representing the y-coordinate (top edge) of the available screen area inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). -This is equal to the {{domxref("ScreenDetailed.top")}} property, plus the height of any OS UI element drawn at the top of the screen. Windows cannot be placed in those areas, so `availTop` is useful for giving you the top boundary of the actual area you've got available. +This is equal to the {{domxref("ScreenDetailed.top")}} property, plus the height of any OS UI element drawn at the top of the screen. Windows cannot be placed in those areas, so `availTop` is useful for giving you the top boundary of the actual area available to open or place windows. + +> **Note:** A non-standard implementation of the `availTop` property is available on the `Screen` interface in all browsers. This represents the y-coordinate (top edge) of the _current_ screen's available area (i.e. the screen containing the browser window the code is being run in). See the [Non-standard example](#non-standard_example) below for usage details, and see the [`Screen`](/en-US/docs/Web/API/Screen#browser_compatibility) reference page for browser support information relating to the non-standard implementation. ## Value @@ -21,13 +23,24 @@ A number. ## Examples +### Window Management API example + ```js +// Available in browsers that support the Window Management API const screenDetails = await window.getScreenDetails(); // Return the availTop value of the first screen const screen1AvailTop = screenDetails.screens[0].availTop; ``` +### Non-standard example + +```js +// Available in all browsers +// Return the availTop value of the current screen +const screenAvailTop = window.screen.availTop; +``` + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/screendetailed/devicepixelratio/index.md b/files/en-us/web/api/screendetailed/devicepixelratio/index.md index 8411bc9422f714d..010b31712399bf6 100644 --- a/files/en-us/web/api/screendetailed/devicepixelratio/index.md +++ b/files/en-us/web/api/screendetailed/devicepixelratio/index.md @@ -11,7 +11,12 @@ browser-compat: api.ScreenDetailed.devicePixelRatio {{APIRef("Window Management API")}}{{SeeCompatTable}} The **`devicePixelRatio`** read-only property of the -{{domxref("ScreenDetailed")}} interface is a number representing the screen's device pixel ratio. This is the same as the value returned by {{domxref("Window.devicePixelRatio")}} (although that property always returns the device pixel ratio for the {{domxref("ScreenDetails.currentScreen", "current screen", "", "nocode")}}) — see that page for more information about device pixel ratios in general. +{{domxref("ScreenDetailed")}} interface is a number representing the screen's device pixel ratio. + +This is the same as the value returned by {{domxref("Window.devicePixelRatio")}}, except that `Window.devicePixelRatio`: + +- always returns the device pixel ratio for the {{domxref("ScreenDetails.currentScreen", "current screen", "", "nocode")}}. +- also includes scaling of the window itself, i.e. page zoom (at least on some browser implementations). ## Value diff --git a/files/en-us/web/api/screendetailed/index.md b/files/en-us/web/api/screendetailed/index.md index 25d2fd52b8f0e3c..894641cfb6ebd80 100644 --- a/files/en-us/web/api/screendetailed/index.md +++ b/files/en-us/web/api/screendetailed/index.md @@ -20,7 +20,7 @@ The **`ScreenDetailed`** interface of the [Window Management API](/en-US/docs/We _Inherits properties from its parent, {{DOMxRef("Screen")}}._ - {{domxref("ScreenDetailed.availLeft", "availLeft")}} {{ReadOnlyInline}} {{Experimental_Inline}} - - : A number representing the x-coordinate (left hand edge) of the available screen area. + - : A number representing the x-coordinate (left-hand edge) of the available screen area. - {{domxref("ScreenDetailed.availTop", "availTop")}} {{ReadOnlyInline}} {{Experimental_Inline}} - : A number representing the y-coordinate (top edge) of the available screen area. - {{domxref("ScreenDetailed.devicePixelRatio", "devicePixelRatio")}} {{ReadOnlyInline}} {{Experimental_Inline}} @@ -32,7 +32,7 @@ _Inherits properties from its parent, {{DOMxRef("Screen")}}._ - {{domxref("ScreenDetailed.label", "label")}} {{ReadOnlyInline}} {{Experimental_Inline}} - : A string providing a descriptive label for the screen, for example "Built-in Retina Display". - {{domxref("ScreenDetailed.left", "left")}} {{ReadOnlyInline}} {{Experimental_Inline}} - - : A number representing the x-coordinate (left hand edge) of the total screen area. + - : A number representing the x-coordinate (left-hand edge) of the total screen area. - {{domxref("ScreenDetailed.top", "top")}} {{ReadOnlyInline}} {{Experimental_Inline}} - : A number representing the y-coordinate (top edge) of the total screen area. @@ -54,11 +54,11 @@ function openWindow(left, top, width, height, url) { const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; const windowRef = window.open( url, - Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab + "_blank", // needed for it to open in a new window windowFeatures, ); - // Store a reference to the window in the windowRefs array + // Store a reference to the window in the windowRefs array for later use windowRefs.push(windowRef); } ``` diff --git a/files/en-us/web/api/screendetailed/left/index.md b/files/en-us/web/api/screendetailed/left/index.md index 9e37ca6a4b6cd57..3a10dfbac7981ab 100644 --- a/files/en-us/web/api/screendetailed/left/index.md +++ b/files/en-us/web/api/screendetailed/left/index.md @@ -15,19 +15,32 @@ The **`left`** read-only property of the This is equal to the true left-hand edge, ignoring any OS UI element drawn at the left of the screen. Windows cannot be placed in those areas; to get the left-hand coordinate of the screen area that windows can be placed in, use {{domxref("ScreenDetailed.availLeft")}}. +> **Note:** In Firefox, a non-standard implementation of the `left` property is available on the `Screen` interface, and represents the x-coordinate (left-hand edge) of the _current_ screen's area (i.e. the screen containing the browser window the code is being run in). See the [Non-standard example](#non-standard_example) below for usage details, and see the [`Screen`](/en-US/docs/Web/API/Screen#browser_compatibility) reference page for browser support information relating to the non-standard implementation. + ## Value A number. ## Examples +### Window Management API example + ```js +// Available in browsers that support the Window Management API const screenDetails = await window.getScreenDetails(); // Return the absolute left value of the first screen const screen1Left = screenDetails.screens[0].left; ``` +### Non-standard example + +```js +// Available in Firefox +// Return the absolute left value of the current screen +const screenLeft = window.screen.left; +``` + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/screendetailed/top/index.md b/files/en-us/web/api/screendetailed/top/index.md index 9e90fec1ac844b9..f343710bdd5952f 100644 --- a/files/en-us/web/api/screendetailed/top/index.md +++ b/files/en-us/web/api/screendetailed/top/index.md @@ -15,19 +15,32 @@ The **`top`** read-only property of the This is equal to the true top edge, ignoring any OS UI element drawn at the top of the screen. Windows cannot be placed in those areas; to get the top coordinate of the screen area that windows can be placed in, use {{domxref("ScreenDetailed.availTop")}}. +> **Note:** In Firefox, a non-standard implementation of the `top` property is available on the `Screen` interface, and represents the y-coordinate (top edge) of the _current_ screen's area (i.e. the screen containing the browser window the code is being run in). See the [Non-standard example](#non-standard_example) below for usage details, and see the [`Screen`](/en-US/docs/Web/API/Screen#browser_compatibility) reference page for browser support information relating to the non-standard implementation. + ## Value A number. ## Examples +### Window Management API example + ```js +// Available in browsers that support the Window Management API const screenDetails = await window.getScreenDetails(); // Return the absolute top value of the first screen const screen1Top = screenDetails.screens[0].top; ``` +### Non-standard example + +```js +// Available in Firefox +// Return the absolute top value of the current screen +const screenTop = window.screen.top; +``` + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/screendetails/currentscreen/index.md b/files/en-us/web/api/screendetails/currentscreen/index.md index 03f8797242d4454..266ae6c710bd2d5 100644 --- a/files/en-us/web/api/screendetails/currentscreen/index.md +++ b/files/en-us/web/api/screendetails/currentscreen/index.md @@ -23,39 +23,19 @@ A {{domxref("ScreenDetailed")}} object. // Utility function for opening new windows function openWindow(left, top, width, height, url) { const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; - const windowRef = window.open( - url, - Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab - windowFeatures, - ); - - // Store a reference to the window in a windowRefs array - windowRefs.push(windowRef); + return window.open(url, "_blank", windowFeatures); } -// Constants to represent the width and height of the Chrome UI when calculating the window size to open -const WINDOW_CHROME_Y = 51; -const WINDOW_CHROME_X = 1; - -const screenDetails = await window.getScreenDetails(); - -// Return the current screen -const curScreen = screenDetails.currentScreen; - -// Windows will be a third the width and the full height of the current screen -let windowWidth = Math.floor((curScreen.availWidth - 3 * WINDOW_CHROME_X) / 3); -let windowHeight = Math.floor(curScreen.availHeight - WINDOW_CHROME_Y); - -// Open the reference windows in thirds across the entire height of the current screen -openWindow( - curScreen.availLeft, - curScreen.availTop, - windowWidth, - windowHeight, - sites[1].url, +// Open a new window that fills the available area of the current screen. +const currentScreen = (await window.getScreenDetails()).currentScreen; +console.log(`Opening a window to fill screen ${currentScreen.label}`); +const windowRef = openWindow( + currentScreen.availLeft, + currentScreen.availTop, + currentScreen.availWidth, + currentScreen.availHeight, + url, ); - -// ... ``` ## Specifications diff --git a/files/en-us/web/api/screendetails/index.md b/files/en-us/web/api/screendetails/index.md index c5087fd9e414060..9d2f2d4940cd903 100644 --- a/files/en-us/web/api/screendetails/index.md +++ b/files/en-us/web/api/screendetails/index.md @@ -19,19 +19,23 @@ This information is accessed via the {{domxref("Window.getScreenDetails()")}} me ## Instance properties -_Inherits properties from its parent, {{DOMxRef("Event")}}._ +_Inherits properties from its parent, {{DOMxRef("EventTarget")}}._ - {{domxref("ScreenDetails.screens", "screens")}} {{ReadOnlyInline}} {{Experimental_Inline}} + - : An array of {{domxref("ScreenDetailed")}} objects, each one representing detailed information about one specific screen available to the user's device. + + > **Note:** `screens` only includes "extended" displays, not those that mirror another display. + - {{domxref("ScreenDetails.currentScreen", "currentScreen")}} {{ReadOnlyInline}} {{Experimental_Inline}} - : A single {{domxref("ScreenDetailed")}} object representing detailed information about the screen that the current browser window is displayed in. ## Events - {{domxref("ScreenDetails.screenschange_event", "screenschange")}} {{experimental_inline}} - - : Fired when the screens available to the system change in some way — for example when a screen is added or removed. + - : Fired when screens are connected to or disconnected from the system. - {{domxref("ScreenDetails.currentscreenchange_event", "currentscreenchange")}} {{experimental_inline}} - - : Fired when the current screen changes in some way — for example available width or height, or orientation. + - : Fired when the window's current screen changes in some way — for example available width or height, or orientation. ## Examples @@ -41,53 +45,26 @@ _Inherits properties from its parent, {{DOMxRef("Event")}}._ When {{domxref("Window.getScreenDetails()")}} is invoked, the user will be asked for permission to manage windows on all their displays (the status of this permission can be checked using {{domxref("Permissions.query()")}} to query `window-management`). Provided they grant permission, the resulting `ScreenDetails` object contains details of all the screens available to the user's system. +The below example opens a full-size window on each available display. + ```js const screenDetails = await window.getScreenDetails(); -// Return the number of screens -const noOfScreens = screenDetails.screens.length; -``` - -You'll still need to use {{domxref("Window.open()")}} to open and manage windows, but the above provides you with better information for doing so in a multi-screen environment. For example, a utility function might look like so: - -```js -function openWindow(left, top, width, height, url) { - const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; - const windowRef = window.open( +// Open a window on each screen of the device +for (const screen of screenDetails.screens) { + openWindow( + screen.availLeft, + screen.availTop, + screen.availWidth, + screen.availHeight, url, - Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab - windowFeatures, ); - - // Store a reference to the window in the windowRefs array - windowRefs.push(windowRef); } ``` -You would then invoke this function and open windows on specific screens like this: - -```js -const screen1 = screenDetails.screens[0]; -const screen2 = screenDetails.screens[1]; -// Windows will be a third the width and the full height of the screen -let windowWidth = Math.floor((screen1.availWidth - 3 * WINDOW_CHROME_X) / 3); -let windowHeight = Math.floor(screen1.availHeight - WINDOW_CHROME_Y); - -// Open the reference windows in thirds across the entire height of the primary screen -openWindow( - screen1.availLeft, - screen1.availTop, - windowWidth, - windowHeight, - sites[1].url, -); - -// ... -``` - ### Responding to changes in available screens -You could use the `screenschange` event to detect when the available screens have changed (perhaps when a screen is plugged in or unplugged), report the change, close all windows, and then reopen them all to suit the new configuration: +You could use the `screenschange` event to detect when the available screens have changed (perhaps when a screen is plugged in or unplugged), report the change, and update window arrangements to suit the new configuration: ```js screenDetails.addEventListener("screenschange", () => { @@ -98,12 +75,8 @@ screenDetails.addEventListener("screenschange", () => { ); } - // If the windows are open, close them and then open them again - // So that they fit with the new screen configuration - if (windowRefs.length > 0) { - closeAllWindows(); - openWindows(); - } + // Open, close, or rearrange windows as needed, to fit the new screen configuration + updateWindows(); }); ``` diff --git a/files/en-us/web/api/screendetails/screenschange_event/index.md b/files/en-us/web/api/screendetails/screenschange_event/index.md index 40f55f8e4c6d2ef..7697e18467435b7 100644 --- a/files/en-us/web/api/screendetails/screenschange_event/index.md +++ b/files/en-us/web/api/screendetails/screenschange_event/index.md @@ -12,23 +12,7 @@ browser-compat: api.ScreenDetails.screenschange_event The **`screenschange`** event of the {{domxref("ScreenDetails")}} interface is fired when the screens available to the system change in some way. -Specifically, a _change_ in this context means either: - -- A screen ({{domxref("ScreenDetailed")}} object) is added to or removed from the {{domxref("ScreenDetails.screens", "screens")}} array. -- A screen's _basic observable properties_ change. These are: - - {{domxref("Screen.width", "width")}} - - {{domxref("Screen.height", "height")}} - - {{domxref("Screen.availWidth", "availWidth")}} - - {{domxref("Screen.availHeight", "availHeight")}} - - {{domxref("Screen.colorDepth", "colorDepth")}} - - {{domxref("Screen.orientation", "orientation")}} -- A screen's _advanced observable properties_ change. These are: - - The screen's position ((x,y) coordinates of the top-left corner) inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin) - - The screen's available position ((x,y) coordinates of the top-left corner) inside the OS virtual screen arrangement, relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). This is equal to the screen position, plus the width/height of any OS UI elements drawn on the top-left of the screen — windows cannot be placed in those areas - - {{domxref("ScreenDetailed.devicePixelRatio", "devicePixelRatio")}} - - {{domxref("ScreenDetailed.label", "label")}} - - The screen's designation as primary or secondary (see {{domxref("ScreenDetailed.isPrimary", "isPrimary")}}) - - The screen's designation as internal or external (see {{domxref("ScreenDetailed.isInternal", "isInternal")}}) +Specifically, a _change_ in this context means a screen ({{domxref("ScreenDetailed")}} object) has been added to or removed from the {{domxref("ScreenDetails.screens", "screens")}} array. ## Syntax @@ -59,12 +43,8 @@ screenDetails.addEventListener("screenschange", () => { ); } - // If the windows are open, close them and then open them again - // So that they fit with the new screen configuration - if (windowRefs.length > 0) { - closeAllWindows(); - openWindows(); - } + // Open, close, or rearrange windows as needed, to fit the new screen configuration + updateWindows(); }); ``` diff --git a/files/en-us/web/api/window/getscreendetails/index.md b/files/en-us/web/api/window/getscreendetails/index.md index d36b02c362c62e7..b32c20200dc4622 100644 --- a/files/en-us/web/api/window/getscreendetails/index.md +++ b/files/en-us/web/api/window/getscreendetails/index.md @@ -36,50 +36,23 @@ A {{jsxref("Promise")}} that fulfills with a {{domxref("ScreenDetails")}} object When `getScreenDetails()` is invoked, the user will be asked for permission to manage windows on all their displays (the status of this permission can be checked using {{domxref("Permissions.query()")}} to query `window-management`). Provided they grant permission, the resulting {{domxref("ScreenDetails")}} object contains details of all the screens available to the user's system. +The below example opens a full-size window on each available display. + ```js const screenDetails = await window.getScreenDetails(); -// Return the number of screens -const noOfScreens = screenDetails.screens.length; -``` - -You'll still need to use {{domxref("Window.open()")}} to open and manage windows, but the above provides you with better information for doing so in a multi-screen environment. For example, a utility function might look like so: - -```js -function openWindow(left, top, width, height, url) { - const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; - const windowRef = window.open( +// Open a window on each screen of the device +for (const screen of screenDetails.screens) { + openWindow( + screen.availLeft, + screen.availTop, + screen.availWidth, + screen.availHeight, url, - Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab - windowFeatures, ); - - // Store a reference to the window in the windowRefs array - windowRefs.push(windowRef); } ``` -You would then invoke this function and open windows on specific screens like this: - -```js -const screen1 = screenDetails.screens[0]; -const screen2 = screenDetails.screens[1]; -// Windows will be a third the width and the full height of the screen -let windowWidth = Math.floor((screen1.availWidth - 3 * WINDOW_CHROME_X) / 3); -let windowHeight = Math.floor(screen1.availHeight - WINDOW_CHROME_Y); - -// Open the reference windows in thirds across the entire height of the primary screen -openWindow( - screen1.availLeft, - screen1.availTop, - windowWidth, - windowHeight, - sites[1].url, -); - -// ... -``` - > **Note:** See [Multi-window learning environment](https://mdn.github.io/dom-examples/window-management-api/) for a full example (see the [source code](https://github.com/mdn/dom-examples/tree/main/window-management-api) also). ## Specifications diff --git a/files/en-us/web/api/window/moveto/index.md b/files/en-us/web/api/window/moveto/index.md index 1d5f4f253ce8d9f..7fbd72490c38c9b 100644 --- a/files/en-us/web/api/window/moveto/index.md +++ b/files/en-us/web/api/window/moveto/index.md @@ -15,8 +15,6 @@ interface moves the current window to the specified coordinates. > contrast, {{domxref("window.moveBy()")}} moves the window relative to its current > location. -> **Note:** On devices with multiple displays, `moveTo()` positions windows relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). - ## Syntax ```js-nolint diff --git a/files/en-us/web/api/window/open/index.md b/files/en-us/web/api/window/open/index.md index 82b17af73972a04..07830bd14557264 100644 --- a/files/en-us/web/api/window/open/index.md +++ b/files/en-us/web/api/window/open/index.md @@ -10,8 +10,6 @@ browser-compat: api.Window.open The **`open()`** method of the [`Window`](/en-US/docs/Web/API/Window) interface loads a specified resource into a new or existing browsing context (that is, a tab, a window, or an [iframe](/en-US/docs/Web/HTML/Element/iframe)) under a specified name. -> **Note:** On devices with multiple displays, `open()` positions windows relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). - ## Syntax ```js-nolint diff --git a/files/en-us/web/api/window/screenleft/index.md b/files/en-us/web/api/window/screenleft/index.md index 8522a04ed10903b..4538fc46cd577af 100644 --- a/files/en-us/web/api/window/screenleft/index.md +++ b/files/en-us/web/api/window/screenleft/index.md @@ -16,7 +16,7 @@ to the left side of the screen. > {{domxref("Window.screenX")}} property. `screenLeft` was originally > supported only in IE but was introduced everywhere due to popularity. -> **Note:** On devices with multiple displays, browsers will report the value of `screenTop` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). +> **Note:** On devices with multiple displays, browsers will report the value of `screenLeft` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). ## Value diff --git a/files/en-us/web/api/window/screentop/index.md b/files/en-us/web/api/window/screentop/index.md index 0c7ac0297b221eb..233247e120c0162 100644 --- a/files/en-us/web/api/window/screentop/index.md +++ b/files/en-us/web/api/window/screentop/index.md @@ -16,7 +16,7 @@ the top side of the screen. > {{domxref("Window.screenY")}} property. `screenTop` was originally > supported only in IE but was introduced everywhere due to popularity. -> **Note:** On devices with multiple displays, browsers will report the value of `screenTop` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). +> **Note:** On devices with multiple displays, browsers will report the value of `screenTop` relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin), except for Safari, which returns coordinates relative to the current display. ## Value diff --git a/files/en-us/web/api/window_management_api/index.md b/files/en-us/web/api/window_management_api/index.md index 20a25af10baf125..0e7db3ea332ca38 100644 --- a/files/en-us/web/api/window_management_api/index.md +++ b/files/en-us/web/api/window_management_api/index.md @@ -25,15 +25,15 @@ const myWindow = window.open( You can retrieve information about your screen from the {{domxref("Window.screen")}} property, such as how much screen space you have available to place windows in. -However, the above features are limited. `Window.screen` only returns data about the primary screen, and not secondary displays available to a device. To move a window to a secondary display, you could use {{domxref("Window.MoveTo()")}}, but you'd have to guess what coordinates to use based on where it is placed in your setup relative to the primary display. +However, the above features are limited. `Window.screen` only returns data about the primary screen, and not secondary displays available to a device. To move a window to a secondary display, you could use {{domxref("Window.moveTo()")}}, but you'd have to guess what coordinates to use based on where it is placed in your setup relative to the primary display. The Window Management API provides more robust, flexible window management. It allows you to query whether your display is extended with multiple screens and return information on each screen separately: windows can then be placed on each screen as desired. It also provides event handlers to allow you to respond to changes in the available screens, new fullscreen functionality to choose which screen to put into fullscreen mode (if any), and permissions functionality to control access to the API. ### Multi-screen origin -The Window Management API introduces the concept of the **multi-screen origin** — this is the (0,0) coordinate of the host operating system (OS)'s virtual screen arrangement, around which all available screens and windows are positioned. The multi-screen origin is the top-left corner of the OS primary screen (which can usually be specified by the user via OS settings, and generally contains OS UI features such as the taskbar/icon dock). +The Window Management API introduces the concept of the **multi-screen origin** — this is the (0,0) coordinate of the host operating system (OS)'s virtual screen arrangement, around which all available screens and windows are positioned. The multi-screen origin is commonly, but not always, the top-left corner of the OS primary screen (which can usually be specified by the user via OS settings, and generally contains OS UI features such as the taskbar/icon dock). -On devices with multiple displays: +On devices with multiple displays, the following are true on Chrome. Firefox behaves in the same way, but not reliably/consistently, whereas Safari generally uses local values relative to the _current_ screen. - The values of {{domxref("ScreenDetailed.left")}}, {{domxref("ScreenDetailed.top")}}, {{domxref("ScreenDetailed.availLeft")}}, and {{domxref("ScreenDetailed.availTop")}} for each available screen are reported relative to the multi-screen origin. - The values of {{domxref("Window.screenLeft")}}, {{domxref("Window.screenTop")}}, {{domxref("Window.screenX")}}, {{domxref("Window.screenY")}} for each window are reported relative to the multi-screen origin. @@ -77,7 +77,11 @@ const noOfScreens = screenDetails.screens.length; When `getScreenDetails()` is invoked, the user will be asked for permission to manage windows on all their displays (the status of this permission can be checked using {{domxref("Permissions.query()")}} to query `window-management`). Provided they grant permission, the resulting {{domxref("ScreenDetails")}} object contains the following properties: - `screens` + - : An array of {{domxref("ScreenDetailed")}} objects, each one containing detailed information about a separate screen available to the system (see below). This array is also useful for determining the number of available screens, via `screens.length`. + + > **Note:** `screens` only includes "extended" displays, not those that mirror another display. + - `currentScreen` - : A single {{domxref("ScreenDetailed")}} object containing detailed information about the screen that the current browser window is displayed in. @@ -105,7 +109,7 @@ function openWindow(left, top, width, height, url) { const windowFeatures = `left=${left},top=${top},width=${width},height=${height}`; const windowRef = window.open( url, - Math.random().toString(), // a target is needed for it to open as a separate window rather than a tab + "_blank", // needed for it to open in a new window windowFeatures, ); @@ -140,42 +144,58 @@ As shown in an earlier code block, it is a good idea to keep track of the window ```js function closeAllWindows() { // Loop through all window refs and close each one - windowRefs.forEach(windowRef => { + windowRefs.forEach((windowRef) => { windowRef.close(); }); windowRefs = []; } -// ... - // Check whether one of our popup windows has been closed // If so, close them all closeMonitor = setInterval(checkWindowClose, 250); function checkWindowClose() { - windowRefs.forEach(windowRef => { - if (windowRef.closed) { - closeAllWindows(); - return; - } - }); + if (windowRefs.some((windowRef) => windowRef.closed)) { + closeAllWindows(); + clearInterval(closeMonitor); + } +} ``` > **Note:** In our experiments, the {{domxref("setInterval()")}} polling method shown above seemed to work best for detecting window closure in the case of multiple windows. Using events such as {{domxref("Window.beforeunload_event", "beforeunload")}}, {{domxref("Window.pagehide_event", "pagehide")}}, or {{domxref("Document.visibilitychange_event", "visibilitychange")}} proved unreliable because, when opening multiple windows at the same time, the rapid shift in focus/visibility seemed to fire the handler function prematurely. +> **Note:** One concern with the above example is that it uses constant values to represent the size of the Chrome window UI portions in the calculations — `WINDOW_CHROME_X` and `WINDOW_CHROME_Y` — to get the window size calculations correct. This might not produce entirely correctly-sized windows on other future implementations of the API, or future versions of Chrome that might have a different-sized UI. There currently isn't an easy way to work around this. + +### Simple single-window per display case + +If you want to open a single window on each available display that is the full width and height of the display, you could use a pattern like this: + +```js +// Open a window on each screen of the device +for (const screen of screenDetails.screens) { + openWindow( + screen.availLeft, + screen.availTop, + screen.availWidth, + screen.availHeight, + url, + ); +} +``` + ### Window management events The Window Management API provides some useful events for responding to changes in the available screens: - The `ScreenDetails` {{domxref("ScreenDetails.screenschange_event", "screenschange")}} event - - : Fired when the screens available to the system change in some way. + - : Fired when screens are connected to or disconnected from the system. - The `ScreenDetails` {{domxref("ScreenDetails.currentscreenchange_event", "currentscreenchange")}} event - - : Fired when the current screen changes in some way. + - : Fired when the window's current screen changes in some way. - The `Screen` {{domxref("Screen.change_event", "change")}} event - : Fired on a specific screen when it changes in some way. -So for example, you could use the `screenschange` event to detect when the available screens have changed (perhaps when a screen is plugged in or unplugged), report the change, close all windows, and then reopen them all to suit the new configuration: +So for example, you could use the `screenschange` event to detect when the available screens have changed (perhaps when a screen is plugged in or unplugged), report the change, close all windows, and update window arrangements to suit the new configuration: ```js screenDetails.addEventListener("screenschange", () => { @@ -201,9 +221,9 @@ The Window Management API adds a new `screen` option to the {{domxref("Element.r ```js try { - const primaryScreen = (await getScreenDetails()).screens.filter( + const primaryScreen = (await getScreenDetails()).screens.find( (screen) => screen.isPrimary, - )[0]; + ); await document.body.requestFullscreen({ screen: primaryScreen }); } catch (err) { console.error(err.name, err.message); @@ -263,6 +283,7 @@ You can find full examples here: - [Multi-window learning environment](https://mdn.github.io/dom-examples/window-management-api/) (see the [source code](https://github.com/mdn/dom-examples/tree/main/window-management-api)). - [Elmer-inspired trading desk demo](https://window-placement.glitch.me/) (see the [source code](https://glitch.com/edit/#!/window-placement)). +- [Window management demo](https://michaelwasserman.github.io/window-placement-demo/) (see the [source code](https://github.com/michaelwasserman/window-placement-demo)). ## Specifications From f58e40deb0d5e0bca918740c77c8f2415e975399 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Wed, 18 Oct 2023 17:30:15 +0100 Subject: [PATCH 5/5] Fixes for 2nd round of michaelwasserman comments --- files/en-us/web/api/screen/index.md | 2 +- files/en-us/web/api/window/moveto/index.md | 2 ++ files/en-us/web/api/window/open/index.md | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/api/screen/index.md b/files/en-us/web/api/screen/index.md index d656d522f8a266f..10d8b427a0d2f7f 100644 --- a/files/en-us/web/api/screen/index.md +++ b/files/en-us/web/api/screen/index.md @@ -40,7 +40,7 @@ _Also inherits properties from its parent {{domxref("EventTarget")}}_. ## Non-standard properties -The following properties are standardized as part of the [Window Management API](/en-US/docs/Web/API/Window_Management_API), thus we have chosen to document their standard form, which is available on the {{domxref("ScreenDetailed")}} interface. However, non-standard versions of these properties are available on the `Screen` interface. +The following properties are specified as part of the [Window Management API](/en-US/docs/Web/API/Window_Management_API), which makes them available on the {{domxref("ScreenDetailed")}} interface; this is where we have chosen to document them. However, non-standard versions of these properties are available on the `Screen` interface in browsers that don't support that API. See this page's [Browser compatibility](#browser_compatibility) table for details of the non-standard support. - {{domxref("ScreenDetailed.availLeft", "Screen.availLeft")}} {{ReadOnlyInline}} {{Non-standard_Inline}} - : A number representing the x-coordinate (left-hand edge) of the available screen area. diff --git a/files/en-us/web/api/window/moveto/index.md b/files/en-us/web/api/window/moveto/index.md index 7fbd72490c38c9b..8308cc9409a4815 100644 --- a/files/en-us/web/api/window/moveto/index.md +++ b/files/en-us/web/api/window/moveto/index.md @@ -15,6 +15,8 @@ interface moves the current window to the specified coordinates. > contrast, {{domxref("window.moveBy()")}} moves the window relative to its current > location. +> **Note:** On devices with multiple displays, `moveTo()` should position windows relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). This is true in Chromium-based browsers, while Firefox does it inconsistently, sometimes exhibiting unusual behavior. Safari on the other hand moves it relative to the _current_ screen. + ## Syntax ```js-nolint diff --git a/files/en-us/web/api/window/open/index.md b/files/en-us/web/api/window/open/index.md index 07830bd14557264..845716f371629e9 100644 --- a/files/en-us/web/api/window/open/index.md +++ b/files/en-us/web/api/window/open/index.md @@ -10,6 +10,8 @@ browser-compat: api.Window.open The **`open()`** method of the [`Window`](/en-US/docs/Web/API/Window) interface loads a specified resource into a new or existing browsing context (that is, a tab, a window, or an [iframe](/en-US/docs/Web/HTML/Element/iframe)) under a specified name. +> **Note:** On devices with multiple displays, `open()` should position windows relative to the [multi-screen origin](/en-US/docs/Web/API/Window_Management_API#multi-screen_origin). This is true in Chromium-based browsers, while Firefox does it inconsistently, sometimes exhibiting unusual behavior. Safari on the other hand uses local values, always opening it relative to the primary display. + ## Syntax ```js-nolint