├── .github └── workflows │ └── auto-publish.yml ├── .pr-preview.json ├── CHANGES.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── EXPLAINER.md ├── EXPLAINER_fullscreen_popups.md ├── EXPLAINER_initiating_multi_screen_experiences.md ├── EXPLAINER_spec_and_permission_rename.md ├── HOWTO.md ├── LICENSE.md ├── README.md ├── additional_explorations.md ├── index.bs ├── logo.svg ├── mdn-drafts ├── ScreenDetailed.md ├── ScreenDetails.md ├── currentScreen.md ├── isExtended.md └── screens_property.md ├── multi_screen_origin.psd ├── multi_screen_origin.svg ├── security_and_privacy.md ├── security_and_privacy_fullscreen_popups.md ├── security_and_privacy_initiating_multi_screen_experiences.md └── w3c.json /.github/workflows/auto-publish.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: {} 4 | push: 5 | branches: [main] 6 | jobs: 7 | main: 8 | name: Build, Validate and Deploy 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: w3c/spec-prod@v2 13 | with: 14 | GH_PAGES_BRANCH: gh-pages 15 | W3C_ECHIDNA_TOKEN: ${{ secrets.ECHIDNA_TOKEN }} 16 | W3C_WG_DECISION_URL: https://lists.w3.org/Archives/Public/public-secondscreen/2022Apr/0007.html 17 | W3C_BUILD_OVERRIDE: | 18 | Status: WD 19 | -------------------------------------------------------------------------------- /.pr-preview.json: -------------------------------------------------------------------------------- 1 | { 2 | "src_file": "index.bs", 3 | "type": "bikeshed", 4 | "params": { 5 | "force": 1 6 | } 7 | } -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | ## API Surface Changes 2 | 3 | This file describes API surface changes made during experimentation. These 4 | changes were made to address some feedback and requests: 5 | - Github issue [30](https://github.com/w3c/window-management/issues/30) 6 | presented compelling API design advice from @jakearchibald and @kenchris: 7 | - Permission-gate access to EventTarget for screen array changes 8 | - Ensure data is updated (& sync accessible...) when change events are fired 9 | - Resolve unclear permission-gating of isMultiScreen() 10 | - GitHub issues [35](https://github.com/w3c/window-management/issues/35) 11 | and [21](https://github.com/w3c/window-management/issues/21) suggest 12 | aligning related proposals, partly motivating a new Screens interface. 13 | - See the proposed [Screen Fold API](https://w3c.github.io/screen-fold/) and 14 | [Window Segments Enumeration API](https://github.com/webscreens/window-segments) 15 | - See the high-level [Form Factors Explainer](https://webscreens.github.io/form-factors/) 16 | - Partner feedback requested access to: 17 | - User-friendly screen labels, which vastly improve custom multi-screen picker and configuration UIs for apps 18 | - Screen change events, including changes to the multi-screen bit, to obviate polling 19 | - Starting in the second origin trial, a [permissions policy](https://w3c.github.io/webappsec-permissions-policy/) was added, so embedders could control feature access of embedded iframes. 20 | - Some screen properties of reduced imperative were removed, at least for now. 21 | - `id`: A temporary generated per-origin unique ID; reset when cookies are deleted. 22 | - `touchSupport`: Whether the screen supports touch input; a predecessor of `pointerTypes`. 23 | - `pointerTypes`: The set of PointerTypes supported by the screen. 24 | - The `window-placement` permission and permission policy name were renamed to `window-management` as per GitHub issue [114](https://github.com/w3c/window-management/issues/114) 25 | 26 | ## Examples of requesting additional screen information 27 | 28 | **Before (1st Origin Trial, Chrome M86-M88)** 29 | 30 | [This explainer snapshot](https://github.com/w3c/window-management/blob/a1e6c7cbf6e60ca04483ef817c5ea0ff069beecd/EXPLAINER.md) 31 | captures our older vision for the API, implemented in early experimentation. 32 | 33 | ```javascript 34 | // Detect the presence of extended screen areas; async method on Window. 35 | const multiScreenUI = await window.isMultiScreen(); 36 | 37 | // Request a static array of static dictionaries. 38 | let cachedScreens = await window.getScreens(); 39 | cachedScreens[0].primary; // e.g. true 40 | cachedScreens[0].internal; // e.g. true 41 | cachedScreens[0].touchSupport; // e.g. true 42 | cachedScreens[0].scaleFactor; // e.g. 2 43 | 44 | // Access the static dictionary corresponding to the current `window.screen`. 45 | // The object is stale on cross-screen window placements or device changes. 46 | let currentScreen = cachedScreens.find( 47 | s => s.availLeft == window.screen.availLeft && 48 | s.availTop == window.screen.availTop); 49 | 50 | // Observe changes of one or more screens; need to await updated info. 51 | window.addEventListener('screenschange', async function() { 52 | let updatedScreens = await window.getScreens(); 53 | let screenCountChanged = screens.length != updatedScreens.length; 54 | }); 55 | ``` 56 | 57 | **After (2nd Origin Trial, Chrome M93-M96)** 58 | 59 | The [explainer](https://github.com/w3c/window-management/blob/main/EXPLAINER.md) 60 | and [draft spec](https://w3c.github.io/window-management/) capture our 61 | latest vision for the API, implemented in later experimentation. 62 | 63 | ```javascript 64 | // Detect the presence of extended screen areas; sync attribute on Screen. 65 | const multiScreenUI = window.screen.isExtended; 66 | 67 | // Request an interface with a FrozenArray of live Screen-inheriting objects. 68 | const screenDetails = await window.getScreenDetails(); 69 | screenDetails.screens[0].isPrimary; // e.g. true 70 | screenDetails.screens[0].isInternal; // e.g. true 71 | screenDetails.screens[0].devicePixelRatio; // e.g. 2 72 | // New access to user-friendly labels for each screen: 73 | screenDetails.screens[0].label; // e.g. 'Samsung Electric Company 28"' 74 | 75 | // Access the live object corresponding to the current `window.screen`. 76 | // The object is updated on cross-screen window placements or device changes. 77 | screenDetails.currentScreen; 78 | 79 | // Observe 'screens' array and 'currentScreen' changes; sync info access. 80 | let cachedScreenCount = screenDetails.screens.length; 81 | let cachedCurrentScreen = screenDetails.currentScreen; 82 | screenDetails.addEventListener('screenschange', function() { 83 | // NOTE: Does not fire on changes to attributes of individual Screens. 84 | let screenCountChanged = cachedScreenCount != screenDetails.screens.length; 85 | }); 86 | screenDetails.addEventListener('currentscreenchange', function() { 87 | // NOTE: Fires on currentScreen attribute changes, and when the window moves to another screen. 88 | let currentScreenChanged = cachedCurrentScreen !== screenDetails.currentScreen; 89 | }); 90 | 91 | // Observe changes to a specific Screen's attributes. 92 | window.screen.addEventListener('change', function() { ... }); 93 | screenDetails.screens[0].addEventListener('change', function() { ... }); 94 | ``` 95 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | All documentation, code and communication under this repository are covered by the [W3C Code of Ethics and Professional Conduct](https://www.w3.org/Consortium/cepc/). 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | Please refer to the group's [Work Mode](https://www.w3.org/wiki/Second_Screen/Work_Mode). 4 | 5 | Contributions to this repository are intended to become part of Recommendation-track documents governed by the 6 | [W3C Patent Policy](https://www.w3.org/Consortium/Patent-Policy-20200915/) and 7 | [Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). 8 | To make substantive contributions to specifications, you must either participate 9 | in the relevant W3C Working Group or make a non-member patent licensing commitment. 10 | 11 | If you are not the sole contributor to a contribution (pull request), please identify all 12 | contributors in the pull request comment. 13 | 14 | To add a contributor (other than yourself, that's automatic), mark them one per line as follows: 15 | 16 | ``` 17 | +@github_username 18 | ``` 19 | 20 | If you added a contributor by mistake, you can remove them in a comment with: 21 | 22 | ``` 23 | -@github_username 24 | ``` 25 | 26 | If you are making a pull request on behalf of someone else but you had no part in designing the 27 | feature, you can remove yourself with the above syntax. 28 | 29 | # Tests 30 | 31 | For normative changes, a corresponding 32 | [web-platform-tests](https://github.com/web-platform-tests/wpt) PR is highly appreciated. Typically, 33 | both PRs will be merged at the same time. Note that a test change that contradicts the spec should 34 | not be merged before the corresponding spec change. If testing is not practical, please explain why 35 | and if appropriate [file a web-platform-tests issue](https://github.com/web-platform-tests/wpt/issues/new) 36 | to follow up later. Add the `type:untestable` or `type:missing-coverage` label as appropriate. 37 | -------------------------------------------------------------------------------- /EXPLAINER.md: -------------------------------------------------------------------------------- 1 | # Window Management on the Web 2 | 3 | ## Introduction 4 | 5 | This proposal introduces incremental improvements to existing screen information 6 | and window placement APIs, allowing web applications to be intentional about the 7 | experiences they offer to users of multi-screen devices. 8 | 9 | ## Background 10 | 11 | Operating systems generally allow users to connect multiple screens to a single 12 | device and arrange them virtually to extend the overall visual workspace. 13 | 14 | A variety of applications use platform tools to place windows in multi-screen 15 | environments, but web application developers are limited by existing APIs, like 16 | [`Screen`](https://drafts.csswg.org/cssom-view/#the-screen-interface) and 17 | [`Window`](https://drafts.csswg.org/cssom-view/#extensions-to-the-window-interface), 18 | which were generally designed around the use of a single screen: 19 | * `Element.requestFullscreen()` only supports fullscreen on the current screen 20 | * `Window.open()` and `moveTo()/moveBy()` often clamp to the current screen 21 | * `Window.screen` only provides information about the Window's current screen 22 | * The `Web-exposed screen area` does not account for multiple available screens 23 | 24 | So, web application users with multiple screens have no choice but to manually 25 | drag windows to the appropriate screen, exit and re-enter fullscreen to use the 26 | intended screen, and work around other limitations of web applications that can 27 | only make use of an artificially limited visual workspace. 28 | 29 | Also, prospective web application developers may see this as another reason to 30 | seek [proprietary APIs](https://developer.chrome.com/apps/system_display), 31 | [platform extensions](https://www.electronjs.org/docs/api/screen), or another 32 | application development platform altogether. 33 | 34 | As multi-screen devices and applications become a more common and critical part 35 | of user experiences, it becomes more important to give developers information 36 | and tools to leverage that expanded visual environment. This document describes 37 | some possible incremental solutions enabling web application developers to make 38 | use of multi-screen devices, in order to facilitate discussion and seek 39 | concensus on a path forward. 40 | 41 | ## Use Cases 42 | 43 | The aim of this proposal is enable better experiences for web application users 44 | with multiple screens. Here are some use cases that inform the goals below: 45 | * Slideshow app presents on a projector, shows speaker notes on a laptop screen 46 | * Financial app opens a dashboard of windows across multiple monitors 47 | * Medical app opens images (e.g. x-rays) on a high-resolution grayscale display 48 | * Creativity app shows secondary windows (e.g. pallete) on a separate screen 49 | * Conference room app shows controls on a touch screen device and video on a TV 50 | * Multi-screen layouts in gaming, signage, artistic, and other types of apps 51 | * Site optimizes content and layout when a window spans multiple screens 52 | 53 | ## Goals 54 | 55 | The following specific goals and proposed solutions make incremental extensions 56 | of existing window placement APIs to support extended multi-screen environments. 57 | * Support requests to show elements fullscreen on a specific screen 58 | * Extend `Element.requestFullscreen()` for specific screen requests 59 | * Support requests to place web app windows on a specific screen 60 | * Extend `Window.open()` and `moveTo()/moveBy()` for cross-screen coordinates 61 | * Provide requisite information to achieve the goals above 62 | * Add `Screen.isExtended` to expose the presence of extended screen areas 63 | * Add `Screen.change`, an event fired when Screen attributes change 64 | * Add `Window.getScreenDetails()` to request additional permission-gated screen info 65 | * Add `ScreenDetails` and `ScreenDetailed` interfaces for additional screen info 66 | * Standardize common `Screen.availLeft` and `Screen.availTop` attributes 67 | * Add Permission API support for a new `window-management` entry 68 | 69 | These allow web applications to make window placement requests optimized for the 70 | specific use case, characteristics of available screens, and user preferences. 71 | 72 | See explorations of alternative and supplemental proposals in 73 | [additional_explorations.md](https://github.com/w3c/window-management/blob/main/additional_explorations.md). 74 | 75 | ### Non-goals 76 | 77 | * Expose extraneous or especially identifying screen information (e.g. EDID) 78 | * Expose APIs to control the configuration of screen devices 79 | * Place windows outside a user's view or across virtual workspaces/desktops 80 | * Offer declarative window arrangements managed by the browser 81 | * Open or move windows on remote displays connected to other devices 82 | * See the [Presentation](https://www.w3.org/TR/presentation-api/) and 83 | [Remote Playback](https://www.w3.org/TR/remote-playback/) APIs 84 | * Capturing links in specific existing/new windows, etc. 85 | * See [Link Capturing](https://docs.google.com/document/d/1w9qHqVJmZfO07kbiRMd9lDQMW15DeK5o-p-rZyL7twk/edit?usp=sharing) 86 | 87 | ## Support requests to show elements fullscreen on a specific screen 88 | 89 | One of the primary use cases for Window Management is showing fullscreen content 90 | on the optimal screen for the given use case. An example of this is presenting a 91 | slideshow or other media on an external display when the web application window 92 | controlling the presentation is on the 'internal' display built into a laptop. 93 | 94 | Our proposed solution is to support requests for a specific screen through the 95 | [`fullscreenOptions`](https://fullscreen.spec.whatwg.org/#dictdef-fullscreenoptions) 96 | dictionary parameter of 97 | [`Element.requestFullscreen()`](https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen). 98 | 99 | ```webidl 100 | dictionary FullscreenOptions { 101 | FullscreenNavigationUI navigationUI = "auto"; 102 | 103 | // NEW: An optional way to request a specific screen for element fullscreen. 104 | ScreenDetailed screen; 105 | }; 106 | ``` 107 | 108 | In the slideshow presentation example, the presenter could now click a button to 109 | "Present on external display", which requests fullscreen on the intended screen, 110 | instead of first dragging the window to that intended screen and then clicking 111 | a button that can only request fullscreen on the current display. 112 | 113 | ```js 114 | // Show the slideshow element fullscreen on the optimal screen. 115 | // See the definition of getScreenForSlideshow() later in this document. 116 | // NEW: `screen` on `fullscreenOptions` for `requestFullscreen()`. 117 | slideshowElement.requestFullscreen({ screen: await getScreenForSlideshow() }); 118 | ``` 119 | 120 | As the `screen` dictionary member is not `required`, it is implicitly optional. 121 | Callers can omit the member altogether to use the window's current screen, which 122 | ensures backwards compatibility with existing usage. Callers can also explicitly 123 | pass `undefined` for the same result. Passing `null` for this optional member is 124 | not supported and will yield a TypeError, as is typical of modern web APIs. 125 | 126 | ## Support requests to place web app windows on a specific screen 127 | 128 | Web applications also have compelling use cases for placing non-fullscreen 129 | content windows on screens other than the current screen. For example, a media 130 | editing application may wish to place companion windows on a separate screen, 131 | when the main editing window is maximized on a particular screen. The app may 132 | determine an initial multi-screen placement based on available screen info and 133 | application settings, or it may be restoring a user's saved window arrangement. 134 | 135 | Existing `Window` placement APIs have varied histories and awkward shapes, but 136 | generally offer a sufficient surface for cross-screen window placement: 137 | * [`open()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/open) 138 | accepts `left`, `top`, `width`, and `height` in the 139 | [features](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features) 140 | argument string 141 | * [`moveTo(x, y)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/moveTo) 142 | and 143 | [`resizeTo(width, height)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/resizeTo) 144 | take similar values to place existing windows 145 | * [`screenX`](https://drafts.csswg.org/cssom-view/#dom-window-screenx), 146 | [`screenY`](https://drafts.csswg.org/cssom-view/#dom-window-screeny), 147 | [`outerWidth`](https://drafts.csswg.org/cssom-view/#dom-window-outerwidth), 148 | and 149 | [`outerHeight`](https://drafts.csswg.org/cssom-view/#dom-window-outerheight) 150 | provide info about the current window placement 151 | 152 | ```webidl 153 | partial interface Window { 154 | // NEW: `features` support `left` and `top` coordinates on other screens. 155 | Window? open(optional USVString url="", optional DOMString target = "_blank", 156 | optional DOMString features = ""); 157 | // NEW: `x` and `y` support coordinates placing windows on other screens. 158 | void moveTo(long x, long y); 159 | // NEW: `x` and `y` support deltas placing windows on other screens. 160 | void moveBy(long x, long y); 161 | 162 | // NEW: Coordinates are defined relative to the multi-screen origin. 163 | readonly attribute long screenX; 164 | readonly attribute long screenLeft; 165 | readonly attribute long screenY; 166 | readonly attribute long screenTop; 167 | }; 168 | ``` 169 | 170 | The least invasive way to support multi-screen window placement is to specify 171 | positional coordinates relative to a multi-screen origin (e.g. top-left of the 172 | primary screen) in existing API surfaces. Coordinates are currently specified as 173 | [CSS pixels](https://drafts.csswg.org/css-values-4/#px) relative to the 174 | [web exposed screen area](https://drafts.csswg.org/cssom-view/#web-exposed-screen-area), 175 | which refers to a singular output device. Those definitions would be updated to 176 | clarify the behavior in multi-screen environments. 177 | 178 | A common convention of most window managers is to use the top-left corner of the 179 | system's primary screen as the origin of the coordinate system used to position 180 | other screens in a two-dimensional plane, relative to the primary screen. 181 | However, in other cases, an arbitrary point may be used as the multi-screen 182 | coordinate space origin, and all screens are placed relative to that point. 183 | This is both window manager and implementation specific behavior. 184 | 185 | Most browser implementations already use coordinates relative to a multi-screen 186 | origin, but may clamp placement within the current screen, rather than allowing 187 | placement on other screens. Implementation-specific behaviors may be acceptable, 188 | but aforementioned existing specifications would permit placing windows on other 189 | screens, in accordance with the requested coordinates and any applicable user 190 | permissions. 191 | 192 | This aspect of the proposal matches the existing behavior of some browsers, 193 | requires no API shape changes, and seems like the simplest option available, but 194 | it has some challenges. See alternatives, considerations, and more examples in 195 | [additional_explorations.md](https://github.com/w3c/window-management/blob/main/additional_explorations.md). 196 | 197 | In the media editing application example, the user might save and close their 198 | current project, later selecting an option to open that saved project, which 199 | restores the multi-screen window placement configuration for that project. A 200 | similar pattern would be useful to financial dashboards and other applications. 201 | 202 | ```js 203 | // Save the open windows with placements when the user saves the project. 204 | function saveOpenWindows(project, openWindows) { 205 | await saveWindowInIndexDB(project, openWindows.map(w => { 206 | return { url: w.location.href, name: w.name, 207 | left: w.screenX, top: w.screenY, 208 | width: w.outerWidth, height: w.outerHeight }; 209 | })); 210 | } 211 | 212 | // Restore saved windows with placements when the user opens the project. 213 | function restoreSavedWindows(project, openWindows) { 214 | for (let w of await getSavedWindowsFromIndexDB(project)) { 215 | let openWindow = openWindows.find(o => o.name === w.name); 216 | if (openWindow) { 217 | // NEW: `x` and `y` may be outside the window's current screen. 218 | openWindow.moveTo(w.left, w.top); 219 | openWindow.resizeTo(w.width, w.height); 220 | } else { 221 | // NEW: `left` and `top` may be outside the opener's current screen. 222 | window.open(w.url, w.name, `left=${w.left},top=${w.top}` + 223 | `width=${w.width},height=${w.height}`); 224 | } 225 | } 226 | } 227 | ``` 228 | 229 | ## Provide requisite information to achieve the goals above 230 | 231 | ### Add `Screen.isExtended` to expose the presence of extended screen areas 232 | 233 | The most basic question developers may ask to support multi-screen devices is: 234 | "Does this device have multiple screens that may be used for window placement?" 235 | The proposed shape for this particularly valuable limited-information query is 236 | a single `Screen.isExtended` boolean, exposed to secure contexts without an 237 | explicit permission prompt. 238 | 239 | ```webidl 240 | partial interface Screen { 241 | // NEW: Yields whether the visual workspace extends over 2+ screens. 242 | [SecureContext] readonly attribute boolean isExtended; 243 | }; 244 | ``` 245 | 246 | This single bit provides high value to users and developers alike, allowing 247 | sites to offer multi-screen functionality only when it is applicable, and to 248 | avoid requesting additional information and capabilities that are not applicable 249 | to single-screen environments. The value of this information seems to outweigh 250 | the risks posed by minimally increasing the device fingerprinting surface. See 251 | more thorough Privacy & Security considerations later in this document. 252 | 253 | In the slideshow example, the site may now offer specific UI entrypoints for 254 | single-screen and multi-screen environments. 255 | 256 | ```js 257 | function updateSlideshowButtons() { 258 | // NEW: Yields whether the visual workspace extends over 2+ screens. 259 | const multiScreenUI = window.screen.isExtended; // Offer multi-screen UI? 260 | document.getElementById("multi-screen-slideshow").hidden = !multiScreenUI; 261 | document.getElementById("single-screen-slideshow").hidden = multiScreenUI; 262 | } 263 | ``` 264 | 265 | ### Add `Screen.change`, an event fired when Screen attributes change 266 | 267 | Sites must currently poll the existing `Screen` interface for changes. This is 268 | problematic, as polling frequently consumes battery life, polling infrequently 269 | delays UI updates (detracting from the user experience), and the overall pattern 270 | yields inconsistencies between sites and adds a development burden. This can 271 | easily be solved by adding an event that is fired when screen attributes change. 272 | The proposed shape is a `Screen.change` event, exposed to secure contexts 273 | without an explicit permission prompt. 274 | 275 | ```webidl 276 | // NEW: Screen inherits EventTarget. 277 | interface Screen : EventTarget { 278 | // 279 | 280 | // NEW: An event fired when attributes of a specific screen change. 281 | [SecureContext] attribute EventHandler onchange; 282 | }; 283 | ``` 284 | 285 | This is useful for updating multi-screen UI entrypoints or prompting users for 286 | additional multi-screen information when extended screens become available. It 287 | may also be useful for adapting content or window placements to screen changes. 288 | See Privacy & Security considerations for these events later in this document. 289 | 290 | The slideshow example's multi-screen UI can now be updated in a change handler: 291 | 292 | ```js 293 | let cachedScreenIsExtended = window.screen.isExtended; 294 | window.screen.addEventListener('change', function() { 295 | if (cachedScreenIsExtended != window.screen.isExtended) 296 | updateSlideshowButtons(); // Defined in a prior explainer section. 297 | }); 298 | ``` 299 | 300 | ### Add `Window.getScreenDetails()` to request additional permission-gated screen info 301 | 302 | Sites require information about the available screens in order to make optimal 303 | application-specific use of that space, to save and restore the user's window 304 | placement preferences for specific screens, or to offer users customized UI for 305 | choosing appropriate window placements. The proposed shape of this query is a 306 | `Window.getScreenDetails()` method, alongside the existing `screen` attribute. 307 | 308 | ```webidl 309 | partial interface Window { 310 | // NEW: Requests permission-gated access to additional screen information. 311 | [SecureContext] Promise getScreenDetails(); 312 | }; 313 | ``` 314 | 315 | This method gives the web platform a surface to optionally expose an appropriate 316 | amount of multi-screen information to web applications. By returning a promise, 317 | user agents can asynchronously determine what amount of information to expose, 318 | prompt users to decide, obtain underlying information lazily, and reject or 319 | resolve accordingly. 320 | 321 | The slideshow example can now request access to multi-screen information: 322 | 323 | ```js 324 | // Request information for multi-screen slideshow functionality, if available. 325 | async function startSlideshow() { 326 | // NEW: Feature-detect availability of additional screen information. 327 | if ("getScreenDetails" in window) { 328 | try { 329 | // NEW: Requests permission-gated access to additional screen information. 330 | let screenDetails = await window.getScreenDetails(); 331 | startMultiScreenSlideshow(screenDetails); 332 | return; 333 | } catch (err) { 334 | // The request was denied or an error occurred. 335 | console.error(err.name, err.message); 336 | } 337 | } 338 | // If multi-screen info is not available, start a single-screen slideshow. 339 | startSingleScreenSlideshow(); 340 | }; 341 | ``` 342 | 343 | ### Add `ScreenDetails` and `ScreenDetailed` interfaces for additional screen info 344 | 345 | The `getScreenDetails()` method grants access to a `ScreenDetails` interface on success. 346 | That provides multi-screen information and change events, as well as additional 347 | per-screen information via a `ScreenDetailed` interface, which inherits from the 348 | existing [`Screen`](https://drafts.csswg.org/cssom-view/#screen) interface. The 349 | proposed shapes of these interfaces, exposed to secure contexts with explicit 350 | permission, are outlined below: 351 | 352 | ```webidl 353 | // NEW: Interface exposing multiple screens and additional information. 354 | [SecureContext] interface ScreenDetails: EventTarget { 355 | // NEW: The set of available screens with additional per-screen info. 356 | readonly attribute FrozenArray screens; 357 | 358 | // NEW: A reference to the current screen with additional info. 359 | // NOTE: This is intentionally not [SameObject] so that currentScreen 360 | // can be a member of screens. 361 | readonly attribute ScreenDetailed currentScreen; 362 | 363 | // NEW: Change event fired when the set of screens changes. 364 | // NOTE: Does not fire on changes to attributes of individual ScreenDetails. 365 | attribute EventHandler onscreenschange; 366 | 367 | // NEW: Change event fired when any attribute on the currentScreen changes, 368 | // including when the window is moved to another screen. 369 | attribute EventHandler oncurrentscreenchange; 370 | }; 371 | 372 | // NEW: Interface inherits Screen and exposes additional information. 373 | [SecureContext] interface ScreenDetailed : Screen { 374 | // Shape matches commonly implemented Screen attributes that that are not yet 375 | // standardized; see https://developer.mozilla.org/en-US/docs/Web/API/Screen 376 | // Distances from a multi-screen origin (e.g. primary screen top left) to the: 377 | readonly attribute long left; // Left edge of the screen area, e.g. 1920 378 | readonly attribute long top; // Top edge of the screen area, e.g. 0 379 | // NOTE: readonly attribute long availLeft should be specified on Screen. 380 | // NOTE: readonly attribute long availTop should be specified on Screen. 381 | 382 | // New properties critical for many multi-screen window placement use cases: 383 | 384 | // If this screen is designated as the 'primary' screen by the OS (otherwise 385 | // it is 'secondary'). Useful for placing prominent vs peripheral windows. 386 | readonly attribute boolean isPrimary; // e.g. true 387 | 388 | // If this screen is an 'internal' screen, built into the device, like a 389 | // laptop display. Useful for placing slideshows on external projectors and 390 | // controls or notes on internal laptop screens. 391 | readonly attribute boolean isInternal; // e.g. false 392 | 393 | // The ratio of this screen's resolution in physical pixels to its resolution 394 | // in CSS pixels. Useful for placing windows on screens with optimal scaling 395 | // and appearances for a given application. 396 | readonly attribute float devicePixelRatio; // e.g. 2 397 | 398 | // A user-friendly label for the screen, determined by the user agent and OS. 399 | readonly attribute DOMString label; // e.g. 'Samsung Electric Company 28"' 400 | }; 401 | ``` 402 | 403 | These interfaces provide the most crucial information for placing windows in 404 | extended multi-screen environments. The relative bounds establish a coordinate 405 | system for cross-screen window placement, while newly exposed display device 406 | properties allow applications to restore or choose window placements. Label 407 | strings allow sites to offer custom configuration UIs or pickers, similar to the 408 | [MediaDeviceInfo.label](https://w3c.github.io/mediacapture-main/#dom-mediadeviceinfo-label) 409 | of the Media Capture and Streams API. See relevant Privacy & Security 410 | considerations later in this document. 411 | 412 | The slideshow example can now define `startMultiScreenSlideshow()` to provide an 413 | enhanced web application experience, commonplace among non-web counterparts: 414 | 415 | ```js 416 | // Place slides and notes windows on separate screens, if available. 417 | async function startMultiScreenSlideshow(screenDetails) { 418 | // NEW: Use granted multi-screen info; cache the count for comparison later. 419 | let cachedScreenCount = screenDetails.screens.length; 420 | 421 | // NEW: Handle changes to the set of available screens. 422 | screenDetails.addEventListener('screenschange', function() { 423 | // NEW: Check if the change was fired because a new screen was connected. 424 | if (screenDetails.screens.length > cachedScreenCount) { 425 | // Offer to move the presentation to the newly connected screen. 426 | } 427 | cachedScreenCount = screenDetails.screens.length; 428 | }); 429 | 430 | if (screenDetails.screens.length == 1) { 431 | // If only one screen is available, start a single-screen slideshow. 432 | startSingleScreenSlideshow(); 433 | return; 434 | } 435 | 436 | // Prefer an external screen or a secondary screen for the slideshow window. 437 | const slidesScreen = 438 | screenDetails.screens.find(s => !s.internal) 439 | ?? screenDetails.screens.find(s => !s.isPrimary); 440 | 441 | // Prefer an internal screen, or any other screen for the notes window. 442 | const otherScreens = screenDetails.screens.filter(s => s != slidesScreen); 443 | const notesScreen = otherScreens.find(s => s.internal) ?? otherScreens[0]; 444 | 445 | // TODO: Define this with requestFullscreen and/or window.open/moveTo? 446 | placeSlidesAndNotesOnPreferredScreens(slidesScreen, notesScreen); 447 | } 448 | ``` 449 | 450 | Similar screen selection logic is critical for other web application use cases: 451 | 452 | ```js 453 | // Get a wide color gamut screen for a creativity app's color balancing window. 454 | let wideColorGamutScreen = screenDetails.screens.reduce( 455 | (a, b) => a.colorDepth > b.colorDepth ? a : b); 456 | ``` 457 | 458 | ```js 459 | // Get a high-resolution screen for a medical app's image inspection window. 460 | let highResolutionScreen = screenDetails.screens.reduce( 461 | (a, b) => a.width*a.height > b.width*b.height ? a : b); 462 | ``` 463 | 464 | ```js 465 | // Get screens in left-to-right order for a signage app's multi-screen layout. 466 | let sortedScreens = screenDetails.screens.sort((a, b) => b.left - a.left); 467 | ``` 468 | 469 | NOTE: The `element.requestFullscreen()` algorithm could reasonably be updated to 470 | support being triggered by user-generated `ScreenDetails.onscreenschange` events, matching 471 | [existing behavior](https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen) 472 | when triggered by user-generated `ScreenOrientation.onchange` events. This would 473 | allow sites to request fullscreen or change the screen used for fullscreen when 474 | users connect a new screen. 475 | 476 | NOTE: Screen mirroring relationships are not currently exposed; Screens may omit 477 | destinations and only expose source screens of screen mirroring relationships. 478 | 479 | ### Standardize common `Screen.availLeft` and `Screen.availTop` attributes 480 | 481 | The [`Screen`](https://drafts.csswg.org/cssom-view/#the-screen-interface) 482 | interface currently specifies the sizes of the 483 | [`web-exposed screen area`](https://drafts.csswg.org/cssom-view/#web-exposed-screen-area) 484 | and the 485 | [`web-exposed available screen area`](https://drafts.csswg.org/cssom-view/#web-exposed-available-screen-area) 486 | (which excludes screen areas reserved for system UI, like toolbars or taskbars). 487 | Unfortunately, the available area's bounds cannot be determined, since its 488 | origin is unspecified and assuming zeroes is incorrect. 489 | 490 | Even in single-screen environments, the top or left edge of the screen may be 491 | reserved for system UI, so `window.moveTo(0, 0)` may specify a window position 492 | outside the available area, and undesirably trigger user-agent-defined clamping. 493 | Sites should be able to determine the screen's available area, to accurately 494 | formulate and better anticipate outcomes of standardized placement requests. 495 | 496 | To solve this, most browsers also expose two unstandardized Screen attributes, 497 | [`availLeft`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/availLeft) 498 | and 499 | [`availTop`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/availTop), 500 | which are critical for discerning the region available for placing windows. 501 | These attributes should be standardized on the `Screen` interface itself to 502 | support valid single-screen (or same-screen) placement requests, to support 503 | existing scripts that already use these unstandardized attributes, and to 504 | support new multi-screen window placement requests. 505 | 506 | ```webidl 507 | partial interface Screen { 508 | // NEW: Shape matches commonly implemented Screen attributes that are not yet 509 | // standardized; see https://developer.mozilla.org/en-US/docs/Web/API/Screen 510 | // Distances from a multi-screen origin (e.g. primary screen top left) to the: 511 | readonly attribute long availLeft; // Left edge of the available screen area, e.g. 1920 512 | readonly attribute long availTop; // Top edge of the available screen area, e.g. 0 513 | }; 514 | ``` 515 | 516 | This allows sites to better determine the `web-exposed available screen area`, 517 | and formulate more coherent and predictable window placement requests. 518 | 519 | ```js 520 | // NEW: Move the window to a position known to be in available screen space. 521 | window.moveTo(screen.availLeft + offsetX, screen.availTop + offsetY); 522 | ``` 523 | 524 | See prior discussion regarding coordinates in the section titled 525 | "Support requests to place web app windows on a specific screen". 526 | 527 | ### Add Permission API support for a new `window-management` entry 528 | 529 | Sites may wish to know whether users have already granted or denied a requisite 530 | permission before attempting to access gated information and capabilities. The 531 | proposed shape is adding a `PermissionName` entry and corresponding support via 532 | the `query()` method of the [Permission API](https://w3c.github.io/permissions). 533 | 534 | ```webidl 535 | enum PermissionName { 536 | // ... 537 | "window-management", 538 | // ... 539 | }; 540 | ``` 541 | 542 | This allows sites to educate users that haven't been prompted, provide seamless 543 | cross-screen support for users that have already granted permission, and respect 544 | users that have already denied the permission. 545 | 546 | ```js 547 | navigator.permissions.query({name:'window-management'}).then(function(status) { 548 | if (status.state === "prompt") 549 | showMultiScreenEducationalUI(); 550 | else if (status.state === "granted") 551 | showMultiScreenUI(); 552 | else // status.state === "denied" 553 | showSingleScreenUI(); 554 | }); 555 | ``` 556 | 557 | Window Management is also a 558 | [policy-controlled feature](https://w3c.github.io/webappsec-permissions-policy/) 559 | which is disabled by default for embedded cross-origin pages. 560 | If a cross-origin page wants an embedded page to have access to this API, 561 | then it needs to specify an `allow` attribute on the iframe, e.g. 562 | 563 | ```html 564 | 565 | ``` 566 | 567 | ### Open questions 568 | 569 | * Would changes to the existing synchronous methods break critical assumptions? 570 | * Do any sites expect open/move coordinates to be local to the current screen? 571 | * Is there value in supporting windows placements spanning multiple screens? 572 | * Suggest normative behavior for choosing a target display and clamping? 573 | * How should `ScreenDetailed` references behave when screens are disconnected? 574 | * Does checking `cachedReference in screenDetails.screens` suffice? 575 | * Should there be a `ScreenDetailed.isConnected`? 576 | * How can objects in the screens array be consistently ordered? 577 | * Is sorting by (`left`, `top`) sufficient, even for mirrored screens? 578 | 579 | ## Privacy & Security 580 | 581 | This proposal exposes new information about the screens connected to a device, 582 | increasing the [fingerprinting](https://w3c.github.io/fingerprinting-guidance) 583 | surface of users, especially those with multiple screens consistently connected 584 | to their devices. As one mitigation of this privacy concern, the exposed screen 585 | properties are limited to the minimum needed for common placement use cases. 586 | Further, new information is limited to secure contexts. 587 | 588 | New window placement capabilities themselves may pose additional privacy and 589 | security considerations; for example, showing sensitive content on unexpected 590 | screens, hiding unwanted windows on less conspicuous screens, or otherwise using 591 | cross-screen placements to act in deceptive, abusive, or annoying manners. 592 | 593 | To help mitigate these concerns, user permission should be required for sites to 594 | access nontrivial multi-screen information and place windows on other screens. 595 | Given the API shape proposed above, user agents could reasonably prompt users 596 | when sites call `getScreenDetails()`, fulfilling the promise if the user accepts the 597 | prompt, and rejecting the promise if the user denies access. If the permission 598 | is not already granted, cross-screen placement requests could fall back to 599 | same-screen placements, matching pre-existing behavior of some user agents. The 600 | amount of information exposed to a given site would be at the discretion of 601 | users and their agents. Some APIs, like the 602 | [Media Capture and Streams API](https://w3c.github.io/mediacapture-main), offer 603 | precedent for exposing limited information about devices, with user permission. 604 | 605 | The `Screen.isExtended` boolean is exposed without explicit permission checks, 606 | as this minimal single bit of information supports some critical features for 607 | which a permission prompt would be obtrusive (e.g. show/hide multi-screen UI 608 | entry points like “Show on another screen”), and helps avoid unnecessarily 609 | prompting single-screen users for inapplicable information and capabilities. 610 | This generally follows a TAG design principle for 611 | [device enumeration](https://w3ctag.github.io/design-principles/#device-enumeration): 612 | 613 | >When designing API which allows users to select a device, it may be necessary 614 | to also expose the fact that there are devices are available to be picked. This 615 | does expose one bit of fingerprinting data about the user’s environment to 616 | websites, so it isn’t quite as safe as an API which doesn’t have such a feature. 617 | 618 | >The trade-off is that by allowing websites this extra bit of information, the 619 | API lets authors make their user interface less confusing. They can choose to 620 | show a button to trigger the picker only if at least one device is available. 621 | 622 | A point to note here is that many user agents already effectively expose the 623 | presence of multiple screens to windows located on secondary screens, where 624 | `window.screen.availLeft|Top` >> 0. Script access of this bit is a detectable 625 | [active fingerprinting](https://w3c.github.io/fingerprinting-guidance/#active) 626 | signal, which may be observed and blocked by the user agent. 627 | 628 | The new `Screen.onchange` events pose a slight risk by making 629 | [ephemeral fingerprinting](https://github.com/asankah/ephemeral-fingerprinting) 630 | easier, but scripts can already achieve the same result by polling for changes 631 | to `window.screen`. This risk could be partially mitigated by delaying event 632 | dispatch for hidden documents until such documents are no longer hidden. 633 | 634 | User agents can generally measure and otherwise intervene when sites request the 635 | newly proposed information or use the newly proposed capabilities. 636 | 637 | Alternative API shapes giving less power to sites were considered, but offer 638 | poor experiences for users and developers (e.g. prompting users to pick a 639 | screen, requiring declarative screen rankings from developers). Few, if any, 640 | alternatives exist for non-fullscreen placement of app windows on any connected 641 | screen. The proposed API shape seems like the most natural extension of existing 642 | APIs to support a more complete screen environment, and requires a reasonable 643 | permission. Future work may include ways to query for more limited multi-screen 644 | information to let sites voluntarily minimize their information exposure. 645 | 646 | Some other notes: 647 | - A user gesture is typically already required for `Element.requestFullscreen()` 648 | and `Window.open()`, this just adds permission-gated multi-screen support. 649 | - Existing subframe capabilities (e.g. element fullscreen with ‘allowfullscreen’ 650 | feature policy, and window.open) should support cross-screen info and 651 | placements with permission. 652 | - Gating pre-existing information exposure and placement capabilities on the 653 | newly proposed permission may be reasonable. 654 | - Placement on a different screen from the active window is less likely to 655 | create additional clickjacking risk for users, since the user's cursor or 656 | finger is likely to be co-located with the current screen and window, not on 657 | the separate target screen. 658 | - A new affordance for fullscreen requests on `ScreenDetails.onscreenschange` events follows 659 | the precedent of `ScreenOrientation.onchange`, which is not permission gated. 660 | 661 | See 662 | [security_and_privacy.md](https://github.com/w3c/window-management/blob/main/security_and_privacy.md) 663 | for additional explorations of privacy and security concerns. 664 | 665 | ## Related explainers: 666 | | Name | Link | 667 | |------|------| 668 | | Form Factors Explained | [Draft Community Group Report](https://webscreens.github.io/form-factors/) 669 | | Window Segments Enumeration API | [Explainer](https://github.com/webscreens/window-segments/blob/master/EXPLAINER.md)| 670 | | Screen Fold API | [Explainer](https://github.com/SamsungInternet/Explainers/blob/master/Foldables/FoldState.md), [Unofficial Draft Spec](https://w3c.github.io/screen-fold/) | 671 | | Visual Viewport API | [Draft Community Group Report](https://wicg.github.io/visual-viewport/), [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API) | 672 | -------------------------------------------------------------------------------- /EXPLAINER_fullscreen_popups.md: -------------------------------------------------------------------------------- 1 | 2 | # 🟥 Obsolete 🟥 3 | 4 | This feature is no longer being pursued as of March 27, 2024. This feature is superseded by [HTML Fullscreen Without a Gesture](https://github.com/explainers-by-googlers/html-fullscreen-without-a-gesture) which provides similar capabilities. The document below is maintained for archival reasons. 5 | 6 | --- 7 | 8 | 9 | # Window Management on the Web - Creating Fullscreen Popup Windows 10 | 11 | ## Introduction 12 | This proposal aims to reduce user and developer friction for initiating a fullscreen experience on the desired display of a multi-screen device. The proposed web platform enhancement allows web applications to open a new window in HTML [fullscreen](https://fullscreen.spec.whatwg.org/) mode on a specific display with a single user gesture. 13 | 14 | ## Background 15 | [Window Management](https://github.com/w3c/window-management) is a new permission-gated web platform API that provides web applications with information about the device's connected screens, allowing them to open and position windows or request fullscreen on any of those screens. 16 | 17 | The HTML living standard specifies [Tracking User Activation](https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation), to gate some web platform APIs on user interaction signals. 18 | 19 | ## Problem 20 | Web applications are limited in the ways that they can [Initiate Multi-Screen Experiences](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md) across multi-display configurations. Specifically, opening a popup and transitioning the window to fullscreen typically requires two separate user gestures (see [Spec Notes](#spec-notes)). This results in a cumbersome user experience for web applications which utilize multiple displays. Additionally, web apps wish to show fullscreen content on a specific display, alongside the original content, but target-display fullscreen may make the existing window inaccessible 21 | 22 | Multiple partners and early adopters of the [Window Management API](https://w3c.github.io/window-management/) have specifically requested the ability to show one or more fullscreen popups from a single user gesture, to avoid the user friction entailed with making separate gestures to create each window and make each window fullscreen. For example: 23 | * [window.open should support the 'fullscreen' option](https://github.com/w3c/window-management/issues/7) 24 | * [Feature Request: Initiate a multi-screen experience from a single user activation](https://github.com/w3c/window-management/issues/98#top) 25 | * [Feature request: Fullscreen support on multiple screens](https://github.com/w3c/window-management/issues/92). 26 | 27 | ## Goals 28 | The goal of this document is to outline the necessary spec changes that would permit web applications to open a new fullscreen window on a specific display, with only a single user gesture. It also aims to explore abuse and other security / privacy considerations. In particular this document focuses on introducing straightforward API surface and corresponding algorithmic changes to allow such behavior. 29 | 30 | The [Initiating Multi-Screen Experiences Explainer](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md) covers some related goals (i.e. launching N fullscreen windows on N displays) not covered in this proposal. 31 | 32 | ## Use Cases 33 | Some basic illustrative examples which may be achieved with this proposal are listed below: 34 | * Video streaming app launches a video directly to fullscreen on a separate display. 35 | * 3D modeling app launches a preview in fullscreen on a separate display. 36 | * Medical report app opens imagery fullscreen on a specialized display. 37 | * Point-of-sale app opens a fullscreen payment window on a customer display. 38 | 39 | This proposal is limited to launching at most one fullscreen popup onto one display, given a single transient user activation. [Future enhancements](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md) could allow a web application to launch multiple fullscreen popup windows from a single transient user activation, to allow for more use cases: 40 | 41 | * Financial app opens a fullscreen dashboard on the primary monitor and a fullscreen stock tracker window on a secondary display. 42 | * Virtual desktop app launches fullscreen windows on primary and secondary displays to mimic a remote monitor configuration. 43 | * Security monitoring app launches 6 fullscreen video feeds on an array of 6 displays. 44 | * Gaming app launches 3 fullscreen windows across 3 displays to provide a continuous widescreen view. 45 | 46 | ## Proposal 47 | Allow sites with the `window-management` permission to open a fullscreen window on a specified display from a single user gesture. Scripts calling [window.open()](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) to request a popup window could also include a new fullscreen boolean window feature. 48 | 49 | Fullscreen popup requests could also include window bounds features (e.g. `left`, `top`, `width`, `height`), with positions specified [relative to the multi-screen origin](https://w3c.github.io/window-management/#api-window-attribute-and-method-definition-changes), to request that the window be made fullscreen on the screen containing those bounds, and also to be used as the popup window bounds after exiting fullscreen. 50 | 51 | ### Example Code 52 | 53 | #### Basic Example: 54 | ```js 55 | window.open(url, '_blank', 'popup,fullscreen'); 56 | ``` 57 | 58 | #### Opening a fullscreen popup on another display: 59 | ```js 60 | const otherScreen = screenDetails.screens.find(s => s !== screenDetails.currentScreen); 61 | window.open(url, '_blank', `left=${otherScreen.availLeft},` + 62 | `top=${otherScreen.availTop},` + 63 | `width=${otherScreen.availWidth},` + 64 | `height=${otherScreen.availHeight},` + 65 | `fullscreen`); 66 | ``` 67 | 68 | ### Spec Changes 69 | The spec does not contain an exhaustive list of valid features in the `features` argument, however, the spec does contain procedures for determining if a [popup window is requested](https://html.spec.whatwg.org/multipage/window-object.html#popup-window-is-requested), and the specific `tokenizedFeatures` to look for. Following this model, the spec shall be updated to define a similar algorithm for checking if a **fullscreen window** is requested. A fullscreen window must also first be considered a popup window. 70 | 71 | After [checking if a popup window is requested](https://html.spec.whatwg.org/multipage/window-object.html#popup-window-is-requested), add the following section: 72 | 73 | To **check if a fullscreen window is requested**, given _tokenizedFeatures_: 74 | 1. If _tokenizedFeatures_ is empty, then return false. 75 | 2. Let _popup_ be the result of [checking if a popup window is requested](https://html.spec.whatwg.org/multipage/window-object.html#popup-window-is-requested). 76 | 3. If _popup_ is false, then return false. 77 | 4. Let _fullscreen_ be the result of [checking if a window feature is set](https://html.spec.whatwg.org/multipage/window-object.html#window-feature-is-set), given _tokenizedFeatures_, "`fullscreen`", and false. 78 | 5. If _fullscreen_ is false, then return false. 79 | 6. Let _permissionPolicyWindowManagementState_ be the result of [Is feature enabled in document for origin?](https://www.w3.org/TR/permissions-policy/#is-feature-enabled) given feature "`window-management`", the current [Document](https://dom.spec.whatwg.org/#document) and the current [origin](https://url.spec.whatwg.org/#concept-url-origin). 80 | 7. If _permissionPolicyWindowManagementState_ is "Disabled", then return false. 81 | 8. Let _permissionPolicyFullscreenState_ be the result of [Is feature enabled in document for origin?](https://www.w3.org/TR/permissions-policy/#is-feature-enabled) given "`fullscreen`", the current [Document](https://dom.spec.whatwg.org/#document) and the current [origin](https://url.spec.whatwg.org/#concept-url-origin). 82 | 9. If _permissionPolicyFullscreenState_ is "Disabled", then return false. 83 | 10. If the [transient activation state](https://html.spec.whatwg.org/multipage/interaction.html#transient-activation) is false, then return false. 84 | 11. Let _permissionState_ be the result of [getting the current permission state](https://w3c.github.io/permissions/#dfn-getting-the-current-permission-state) given "`window-management`". 85 | 12. If _permissionState_ is not "[granted](https://w3c.github.io/permissions/#dom-permissionstate-granted)", then return false. 86 | 13. [Consume user activation](https://html.spec.whatwg.org/multipage/interaction.html#consume-user-activation). 87 | 14. Return true. 88 | 89 | Add a Note below this algorithm which reads: 90 | > User agents are encouraged to restore the user-agent-adjusted window.open() specified bounds, or their inferred defaults when a fullscreen popup exits fullscreen. 91 | 92 | In [7.3.2 Browsing contexts](https://html.spec.whatwg.org/multipage/document-sequences.html#windows), insert a new list item after the [is popup](https://html.spec.whatwg.org/multipage/document-sequences.html#is-popup) item and its corresponding note. The new item should read: "An **is fullscreen** boolean, initially false." with an anchor of #is-fullscreen. 93 | 94 | Add a note below the item which reads: 95 | > If **is fullscreen** is true, user agents should [requestFullscreen](https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen) on the [browsing context’s](https://html.spec.whatwg.org/multipage/document-sequences.html#browsing-context) active document [documentElement](https://dom.spec.whatwg.org/#dom-document-documentelement) once the `documentElement` is ready. 96 | 97 | After step 12.1 in **[window open steps](https://html.spec.whatwg.org/multipage/nav-history-apis.html#window-open-steps)**, after "_Set targetNavigable's active browsing context's is popup to the result of [...]_", insert a step: 98 | > Set targetNavigable's [active browsing context](https://html.spec.whatwg.org/multipage/document-sequences.html#nav-bc)'s is fullscreen to the result of [checking if a fullscreen window is requested](https://html.spec.whatwg.org/multipage/nav-history-apis.html#popup-window-is-requested), given tokenizedFeatures. 99 | 100 | "is fullscreen" should link to the list item anchor (#is-fullscreen) added to [7.3.2 Browsing contexts](https://html.spec.whatwg.org/multipage/document-sequences.html#windows) as previously described. 101 | 102 | 103 | #### Spec Notes 104 | **[`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) Activation Consumption** 105 | 106 | The published specifications do not specify that the [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) algorithm consumes the [transient activation](https://html.spec.whatwg.org/multipage/interaction.html#transient-activation), nor does any spec list it as an [activation consuming API](https://html.spec.whatwg.org/multipage/interaction.html#activation-consuming-api). In the [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) [window open steps](https://html.spec.whatwg.org/multipage/nav-history-apis.html#window-open-steps), the [rules for choosing a navigable](https://html.spec.whatwg.org/multipage/document-sequences.html#the-rules-for-choosing-a-navigable) describe procedures for checking if a [transient activation](https://html.spec.whatwg.org/multipage/interaction.html#transient-activation) exists, but nothing describing that it should consume it, presumably leaving it up to the user agent to decide based on their own security and popup blocking measures. 107 | 108 | However, in practice, multiple user agents (Chrome, Firefox, Safari) do consume the [transient activation](https://html.spec.whatwg.org/multipage/interaction.html#transient-activation) when popup blocking is enabled. Additionally, some conflicting documentation has been published which describes [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) as an activation consuming API: 109 | * [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation) describe [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) as an example API which consumes the user activation. 110 | * A Chrome developer [blog post](https://developer.chrome.com/blog/user-activation/#how-does-user-activation-v2-work) describes [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) as an example API which consumes the user activation. 111 | 112 | Published specifications may need some corrective action, but that is outside the scope of this proposal. The proposal in this document makes the assumption that user agents may or may not consume the transient activation in [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev). 113 | 114 | ### Considerations 115 | 116 | #### **Overlapping Fullscreen Windows** 117 | This proposal does not define behavior for certain scenarios which should be considered by user agents implementing the proposal: 118 | * Opening a fullscreen popup on a display which already contains a fullscreen window. 119 | * Opening a fullscreen popup on the same display as the opener, which may or not be fullscreen. 120 | * Pre-existing protections prevent placing popups over fullscreen 121 | * Chrome exits fullscreen (see [ForSecurityDropFullscreen](https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/web_contents.h?q=ForSecurityDropFullscreen)) 122 | * Firefox exits fullscreen 123 | * Safari opens the popup in a separate fullscreen space 124 | 125 | #### **Feature detection** 126 | There is no standard API for querying which features are supported in the [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) `features` argument. There is no way for a web application to check that the user agent supports the `fullscreen` key in the `features` argument without calling the API and detecting if the resulting popup window's [`Document.fullscreenElement`](https://fullscreen.spec.whatwg.org/#ref-for-dom-document-fullscreenelement%E2%91%A0) is non-null. 127 | 128 | The ability to detect supported keys of the `features` argument is out of scope for this proposal. Future [improvements](https://github.com/whatwg/html/issues/7485) to `window.open()` could allow for feature detection. 129 | 130 | #### **Requiring popup initial boundaries** 131 | Scripts may specify window boundaries through the `left`, `top`, `width`, `height` features of [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev) which, under this proposal, control which display the window will appear fullscreen on. Leaving out these parameters may cause undefined behavior (e.g. appearing on the display which contains screen coordinates (0,0)). As a more concrete solution, the algorithmic check for fullscreen could require that `left` and `top` are set which always require the web application to specify a display, and leaves less room for decision by the user agent. However, since `left`, `top`, `width`, `height` are already not required for popup windows, it's reasonable to let the user agent use the existing defaults and fullscreen the window on whichever display would have contained the popup if the `fullscreen` parameter wasn't specified. 132 | 133 | #### **Other fullscreen windows** 134 | This proposal requires that a new fullscreen window must first be also considered a popup window. Future enhancements may consider allowing other types of windows to be opened in fullscreen. 135 | 136 | #### **Fullscreen Exit Behavior** 137 | The proposed note specifies that user agents are encouraged to restore the window to specified bounds after fullscreen exits. Some alternative examples include: Closing the window, restoring to a popup with bounds expanded to each edge of the display. 138 | 139 | #### **Asynchronous behavior** 140 | `Element.requestFullscreen()` returns a promise that resolves after the element becomes fullscreen, but Window.open() does not return a promise. Web applications would need alternative methods of detecting when the window is open, ready and fullscreen. 141 | 142 | #### **fullscreenchange event** 143 | The browser may omit a `fullscreenchange` event prior to any scripts being executed in the new popup window frame. Web applications expecting a `fullscreenchange` would need to account for this behavior in fullscreen-popup scenarios, or browsers would need to carefully ensure that `fullscreenchange` is not emitted until after scripts are ready to handle the event. 144 | 145 | #### **Delays entering fullscreen** 146 | There may exist a delay (unintentional or malicious) between the time the popup is created during the original [user activation](https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation) and the time that the [document element](https://dom.spec.whatwg.org/#document-element) becomes available. Slow network conditions or intentional throttling by a malicious server may introduce a significant delay between the popup window opening and the popup's document element becoming available to fullscreen. In such case, the user agent could postpone or abort the steps for making the popup's document element fullscreen. 147 | 148 | #### **Cross-Origin Popups** 149 | The proposal allows fullscreen popup requests for cross-origin content. If Site A is granted `window-management` and requests a fullscreen popup for Site B, then the browser shall allow Site B to open fullscreen. Site B may opt-out of fullscreen by using the appropriate [permission policy headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy) and even set them dynamically based on the [Referer header](https://www.rfc-editor.org/rfc/rfc9110#field.referer) which contains the URL which opened the popup. There is also a risk for Site A to open a malicious Site B. However, there is an implicit chain of trust via the `window-management` permission suggesting that the user trusts Site A to not open malicious content (regardless of origin). This should be compared to traditional HTML fullscreen of cross-origin iframes, and opening non-fullscreen cross-origin popups. 150 | 151 | #### **HTTP Redirects** 152 | HTTP redirects are supported. When Site A opens a fullscreen popup for Site B, but Site B provides an [HTTP Redirect](https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections) to a different origin it will be treated as a cross-origin popup. See [Cross-Origin Popups](#cross-origin-popups). 153 | 154 | #### **Fullscreen hidden content** 155 | Fullscreen popups allow sites to fullscreen content which was not previously visible to users. However, there are already ways to achieve this with [Element.requestFullscreen](https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0) (e.g. unhide an element immediately before requesting fullscreen). 156 | 157 | ## Security Considerations 158 | A notable security consideration stems from the fact that the web application may launch a fullscreen window on a display that the user is not looking at, since the [user activation](https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation) (i.e. button click) may have occurred on another display which the user is focused on. The user may not notice the fullscreen window transition, nor the fullscreen bubble (e.g. Firefox's "<origin> is now full screen [Exit Full Screen (Esc)]" or Chrome's "Press [Esc] to exit full screen") which could allow for a malicious application to mimic other applications or the operating system without the user realizing that it is a browser window. 159 | 160 | This is partially mitigated by gating this feature on the "`window-management`" permission. Users should only grant permissions for [powerful features](https://w3c.github.io/permissions/#dfn-powerful-feature) to web applications that they trust. 161 | 162 | This could also be mitigated further by having the user agent show a fullscreen bubble when the user first interacts with the cross-display fullscreen window or by showing a bubble on the screen where the user activation took place (i.e. "Window went fullscreen on display ###"), or both. In these scenarios, there is a higher confidence that the user will see a fullscreen bubble. 163 | 164 | ## Privacy Considerations 165 | This feature does not expose any information to sites, and there are no privacy considerations to note beyond those already documented in the Window Management [Privacy Considerations](https://www.w3.org/TR/window-management/#privacy) section. The feature is gated behind the "`window-management`" permission, so it does not expose any information outside what is already available from the API when permission is granted. 166 | 167 | ## Alternatives Considered 168 | 169 | ### Keep the existing behavior. 170 | Web applications can create a popup window that fills the available display bounds, as a poor substitute of HTML fullscreen. However, this contains window borders and decorations not appropriate for some use cases. 171 | 172 | ### Allow a *target-screen* fullscreen request after opening a *cross-screen* popup. 173 | * Requires more complex changes to user activation signals, which has several consequences: 174 | * Requires the user agent to maintain transient user activation signal(s) on one or more frames (the opener and/or the new window and its descendant frames). 175 | * Less straightforward, which could reduce adoption. 176 | * Propagating a transient user activation signal to a new popup or otherwise relaxing the user activation requirements for [`element.requestFullscreen()`](https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0) in this scenario would likely raise significant additional concerns. 177 | * Less ergonomic for application developers. 178 | * A web developer would need to manually call [`element.requestFullscreen()`](https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0) from within the popup after it has loaded, or call [`element.requestFullscreen()`](https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0) from the opener’s script after calling [`window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev). Both versions would require different user activation signal propagation strategies as mentioned above. 179 | 180 | ### Allow fullscreen capability delegation to the new window after creating a popup. 181 | Utilize [capability delegation](https://wicg.github.io/capability-delegation/spec.html) to allow the opener window to delegate fullscreen capabilities to the new popup window via` window.postMessage()`. This currently does not work since `window.open()` consumes the transient user activation which prevents capability delegation. 182 | 183 | This approach has similar disadvantages to the preceding alternative in that it is less intuitive for developers and requires additional consideration for transient user activation changes. An advantage to this approach is that it gives the developers more control over which element to fullscreen in the resulting windows document, but the proposed solution also allows this with some (albeit less straightforward) procedures. -------------------------------------------------------------------------------- /EXPLAINER_initiating_multi_screen_experiences.md: -------------------------------------------------------------------------------- 1 | # Multi-Screen Window Placement on the Web - Initiating Multi-Screen Experiences 2 | 3 | ## Introduction 4 | 5 | This proposal introduces a Multi-Screen Window Placement API enhancement that 6 | would allow web applications to initiate a multi-screen experience from a single 7 | user activation. 8 | 9 | ## Background 10 | 11 | [Multi-Screen Window Placement](https://github.com/w3c/window-management) 12 | is a new permission-gated web platform API that provides web applications with 13 | information about the device's connected screens, allows them to open and 14 | position windows or request fullscreen on any of those screens. 15 | 16 | The HTML living standard specifies 17 | [Tracking User Activation](https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation), 18 | to gate some web platform APIs on user interaction signals. The transient user 19 | activation signal (e.g. from a mouse click) is required and consumed when web 20 | application scripts open a popup window via Window.open(), and when they request 21 | fullscreen via Element.requestFullscreen(). 22 | 23 | ## Problem 24 | 25 | Web applications wishing to offer compelling multi-screen experiences are 26 | currently hindered by the single-screen paradigms incorporated in existing 27 | algorithms of standard specifications. 28 | 29 | A Multi-Screen Window Placement API partner requested the ability to display 30 | multi-screen content when the user clicks a button. See 31 | [Issue 1233970: Window Placement: Pop-ups are blocked when fullscreen is requested](http://crbug.com/1233970). 32 | 33 | Specifically, they would like to 34 | [place fullscreen content on a specific screen](https://w3c.github.io/window-management/#usage-overview-place-fullscreen-content-on-a-specific-screen) 35 | *and* 36 | [place a new popup window on a separate specific screen](https://w3c.github.io/window-management/#usage-overview-place-windows-on-a-specific-screen), 37 | but each of these consume the click’s activation signal, and the second script 38 | request is blocked (unless the user grants popups without gestures via a broad 39 | ‘Popups and Redirects’ content setting). 40 | 41 | ## Use Cases 42 | 43 | The aim of this proposal is enable better experiences for web application users 44 | with multiple screens. Here are some use cases that inform the goal below: 45 | * Slideshow app presents fullscreen slides and opens a speaker notes window 46 | * Financial app launches a fullscreen dashboard and a stock tracker window 47 | * Medical app shows a fullscreen x-ray image and opens an image list window 48 | * Creativity app enters a fullscreen preview and opens a separate control window 49 | 50 | ## Goals 51 | 52 | The goal of this document is to explore tractable and incremental solutions for 53 | the stated multi-screen web application use cases, while minimizing any facets 54 | of the capability that would be prone to abuse. The following specific goals and 55 | proposed solutions make incremental extensions of existing window placement APIs 56 | to support initiating a multi-screen experience from a single user gesture. 57 | * Extend `Element.requestFullscreen()`, `Window.open()`, and 58 | `Tracking User Activation` algorithms and concepts to conditionally permit a 59 | fullscreen request and a popup window request from a single user-activation. 60 | 61 | An eventual end-goal (that is not explored here) is to enable scripts to enter 62 | fullscreen on N screens and open M popup windows on M screens from a single user 63 | activation, where N and M are disjoint and potentially empty sets, as long as 64 | the site has the multi-screen `window-management` permission. 65 | 66 | ## Proposal 67 | 68 | Allow sites with the `window-management` permission to 69 | [place fullscreen content on a specific screen](https://w3c.github.io/window-management/#usage-overview-place-fullscreen-content-on-a-specific-screen) 70 | *and* 71 | [place a new popup window on a separate specific screen](https://w3c.github.io/window-management/#usage-overview-place-windows-on-a-specific-screen), 72 | from a single user gesture, when the device has multiple screens and fullscreen 73 | targets a specific screen. 74 | 75 | This fulfills the API partner’s use case in the most narrow manner possible, and 76 | limits the potential for accidental misuse or abuse with the following set of 77 | mitigations: 78 | 79 | - Require the window-management permission and devices with multiple displays 80 | - These are needed to show a popup and fullscreen on separate displays 81 | - Allow opening a popup *after* requesting fullscreen on a specific display 82 | - This ordering prevents basic misuse (showing a popup under fullscreen) 83 | - Pre-existing protections prevent placing popups over fullscreen 84 | - Chrome exits fullscreen (see 85 | [ForSecurityDropFullscreen](https://source.chromium.org/chromium/chromium/src/+/main:content/public/browser/web_contents.h?q=ForSecurityDropFullscreen)) 86 | - Firefox exits fullscreen 87 | - Safari opens the popup in a separate fullscreen space 88 | - Do not automatically activate popups opened from a fullscreen frame 89 | - This leaves input focus on the fullscreen window, for “Press [Esc] to exit” 90 | - Activate popups once the opener exits fullscreen 91 | - This avoids creation of persistent popunders (e.g. Chrome’s 92 | [PopunderPreventer](https://source.chromium.org/chromium/chromium/src/+/main:chrome/browser/ui/blocked_content/popunder_preventer.h)) 93 | 94 | This proposal leverages the flexibility of implementation-specific behavior 95 | (blocking popups, postponing window activation), while enabling a path towards 96 | defining standardized algorithms. It is partly inspired by existing standardized 97 | precedent: requestFullscreen() 98 | [waives its activation requirement](https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen) 99 | on user generated orientation changes. 100 | 101 | Note: the `window-management` permission is requested earlier, as needed, by 102 | [`Window.getScreenDetails()`](https://w3c.github.io/window-management/#dom-window-getscreendetails), 103 | before scripts can request fullscreen (or open a popup) on a specific screen. 104 | So it is expected that scripts making these requests already have permission. 105 | 106 | ### Example Code 107 | 108 | This feature can be used after the site successfully [requests detailed screen information](https://www.w3.org/TR/window-management/#usage-overview-screen-details) by requesting fullscreen on a specific screen of a multi-screen device, and then opening a popup window on another screen of the device, in a single event listener: 109 | 110 | ```js 111 | initiateMultiScreenExperienceButton.addEventListener('click', async () => { 112 | // Find the primary screen, show some content fullscreen there. 113 | const primaryScreen = screenDetails.screens.find(s => s.isPrimary); 114 | await document.documentElement.requestFullscreen({screen : primaryScreen}); 115 | 116 | // Find a different screen, fill its available area with a new window. 117 | const otherScreen = screenDetails.screens.find(s => s !== primaryScreen); 118 | window.open(url, '_blank', `left=${otherScreen.availLeft},` + 119 | `top=${otherScreen.availTop},` + 120 | `width=${otherScreen.availWidth},` + 121 | `height=${otherScreen.availHeight}`); 122 | }); 123 | ``` 124 | 125 | ### Spec Changes 126 | 127 | This proposal can be brought about as algorithmic changes to existing specs: 128 | - [Tracking User Activation](https://html.spec.whatwg.org/multipage/interaction.html#tracking-user-activation) 129 | - [`Element.requestFullscreen()`](https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen) 130 | - [The rules for choosing a browsing context](https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name) 131 | - Invoked by [`Window.open()`](https://html.spec.whatwg.org/multipage/window-object.html#dom-open-dev)'s 132 | [window open steps](https://html.spec.whatwg.org/multipage/window-object.html#window-open-steps) 133 | 134 | Loosely, an internal slot can be added to the window context, activated when a 135 | fullscreen request is made that targets a specific screen of a multi-screen 136 | device, checked and consumed in the rules for choosing a browsing context, when 137 | the document requests openining a new popup window. 138 | 139 | The Window Management Working Draft Spec incorporates these changes: 140 | - [Usage Overview: 1.2.6. Initiate multi-screen experiences](https://www.w3.org/TR/window-management/#usage-overview-initiate-multi-screen-experiences) 141 | - [3.2.3. Window.open() method definition changes](https://www.w3.org/TR/window-management/#api-window-open-method-definition-changes) 142 | - [3.5.1. Element.requestFullscreen() method definition changes](https://www.w3.org/TR/window-management/#api-element-requestfullscreen-method-definition-changes) 143 | 144 | ### Open questions 145 | 146 | #### Feature detection 147 | 148 | There is no obvious way for a web application to detect support for the proposed 149 | feature, in advance of attempting its use. Scripts can attempt to use this 150 | functionality and check the return value of the call to `Window.open()`, to 151 | determine whether the window was created successfully or not. 152 | 153 | It may be possible to expose signals for this transient token akin to the 154 | [proposed JS API for querying User Activation](https://github.com/dtapuska/useractivation). 155 | 156 | See the existing algorithm for 157 | [requesting new browsing contexts](https://html.spec.whatwg.org/multipage/browsers.html#the-rules-for-choosing-a-browsing-context-given-a-browsing-context-name), 158 | invoked from the 159 | [window.open steps](https://html.spec.whatwg.org/multipage/window-object.html#window-open-steps), 160 | which may permit or block popup window requests based on the 161 | [transient activation](https://html.spec.whatwg.org/multipage/interaction.html#transient-activation) 162 | signal, and the user agent’s configuration. 163 | 164 | ## Security Considerations 165 | 166 | This feature enables sites to perform two facets of the Window Management API with a single user activation; i.e. [`1.2.4. Place fullscreen content on a specific screen`](https://www.w3.org/TR/window-management/#usage-overview-place-fullscreen-content-on-a-specific-screen) and [`1.2.5. Place windows on a specific screen`](https://www.w3.org/TR/window-management/#usage-overview-place-windows-on-a-specific-screen) are combined to [`1.2.6. Initiate multi-screen experiences`](https://www.w3.org/TR/window-management/#usage-overview-initiate-multi-screen-experiences). This may exacerbate some documented Window Management [Security Considerations](https://www.w3.org/TR/window-management/#security). 167 | 168 | A notable security consideration is the placement of the popup window in front of, or behind, the fullscreen window, which could be abused by malicious sites to place content in a deceptive or surreptitious fashion. This was a foremost consideration during development of the current [proposal](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md#proposal), which documents the inherent and added mitigations against accidental misuse or abuse. 169 | 170 | Another notable concern is that the user agent's fullscreen message (e.g. Firefox's "\ is now full screen [Exit Full Screen (Esc)]" or Chrome's "Press [Esc] to exit full screen") might go unnoticed when the site first [places fullscreen content on a less keenly observed screen](https://www.w3.org/TR/window-management/#usage-overview-place-fullscreen-content-on-a-specific-screen), especially if the site simultaneously [places a companion popup window on a more keenly observed screen](https://www.w3.org/TR/window-management/#usage-overview-place-windows-on-a-specific-screen) with the same transient user activation signal. This exacerbates the ability for a malicious site to [spoof the OS, browser, or other sites for phishing attacks](https://www.w3.org/TR/window-management/#security:~:text=spoof%20the%20OS%2C%20browser%2C%20or%20other%20sites%20for%20phishing%20attacks). To mitigate this, the user agent could show a similar message when the fullscreen window seems to regain the user's attention; i.e. when it receives an input event (cursor hover, touch down, keyboard event), when the window is activated (or focused or becomes key), when the companion popup window is closed, and/or other events (perhaps only after some time has passed since the window entered fullscreen on that display). 171 | 172 | User agents already offer controls to permit any number of script-initiated popups without any transient user activation requirement whatsoever (e.g. Chrome's "chrome://settings/content/popups" and Firefox's "Block pop-up windows" setting). This proposal fulfills web developer requirements to initiate multi-screen experiences, without asking users to grant those existing overly-permissive controls, by introducing a tightly scoped capability enhancement. 173 | 174 | ## Privacy Considerations 175 | 176 | This feature does not expose any information to sites, and there are no privacy considerations to note beyond those already documented in the Window Management [Privacy Considerations](https://www.w3.org/TR/window-management/#privacy) section. 177 | 178 | ## Alternatives Considered 179 | 180 | - Permit N `Window.open()` calls on a device with N screens 181 | - This doesn't satisfy the goal of also entering fullscreen 182 | - Introduce a new API to support multi-screen fullscreen 183 | - This is a desirable long-term path, but it is not nearly as tractable 184 | - Allow a target-screen fullscreen request after opening a cross-screen popup 185 | - While similar to the active proposal, this has fewer inherent protections 186 | against accidental misuse or abuse regarding popunders 187 | -------------------------------------------------------------------------------- /EXPLAINER_spec_and_permission_rename.md: -------------------------------------------------------------------------------- 1 | ## Window Placement Spec & Permission Rename 2 | ## Background 3 | The Multi-Screen Window Placement [spec](https://w3c.github.io/window-management/) has primarily utilized the terminology "Window Placement" ever since it was initially drafted in 2020. This includes the title of the spec, the spec short name (`window-placement`), and user-facing API components like [permission](https://w3c.github.io/window-management/#api-permission-api-integration) and permission [policy](https://w3c.github.io/window-management/#api-permission-policy-integration) descriptors which gate the API. 4 | 5 | ## Problem 6 | The existing "Window Placement" terminology only describes one specific component of the API that allows web applications to [place browser windows on target displays](https://w3c.github.io/window-management/#api-window-attribute-and-method-definition-changes). It doesn't encompass the entire surface of the API described in the spec, nor will it adequately describe potential future additions to the API. 7 | 8 | ## Goals 9 | Use more generalized wording that encapsulates more of the current API functionality and provides better futureproofing of the API. Specifically, rename all instances of "Window Placement" terminology with "Window Management". This includes: 10 | * Repository names and [URLs](https://github.com/w3c/window-management) 11 | * [Spec](https://w3c.github.io/window-management/) titles, short names and URLs 12 | * Spec definitions: [permission](https://w3c.github.io/window-management/#api-permission-api-integration) and permission [policy](https://w3c.github.io/window-management/#api-permission-policy-integration) descriptors 13 | * Specifically "`window-placement`" will become "`window-management`" 14 | * Other spec text and descriptions 15 | * [Web Platform Tests](https://github.com/web-platform-tests/wpt/tree/master/window-placement) and resulting [URLs](https://wpt.live/window-placement/) 16 | 17 | ## Breaking Changes 18 | A majority of the rename should not be disruptive and URL redirections will be used wherever possible. However renaming the permission and permission policy descriptors require careful migration efforts since they are user-facing strings which are in use by web applications. The following sections provide illustrative examples of what web developers will be required to update. The timeframe of these changes are browser specific; chromium's tentative schedule is outlined in [User Agent API Migration](#user-agent-api-migration) 19 | 20 | ### Permission Descriptor 21 | Web applications that query the permission name to obtain permission to use the API will need to update: 22 | 23 | **From:** 24 | ```js 25 | navigator.permissions.query({name:'window-placement'}) 26 | ``` 27 | 28 | **To:** 29 | ```js 30 | navigator.permissions.query({name:'window-management'}) 31 | ``` 32 | ### Permission Policy 33 | Web applications utilizing the [iframe allow attribute](https://w3c.github.io/webappsec-permissions-policy/#iframe-allow-attribute) to control this feature will need to update: 34 | 35 | **From:** 36 | ```html 37 | 38 | ``` 39 | 40 | **To:** 41 | ```html 42 | 43 | ``` 44 | Web servers utilizing the "[Permissions-Policy](https://w3c.github.io/webappsec-permissions-policy/#permissions-policy-http-header-field)" header to control this feature will need to update: 45 | 46 | **From:** 47 | ``` 48 | Permission-Policy: window-placement 'self' 49 | ``` 50 | 51 | **To:** 52 | ``` 53 | Permission-Policy: window-management 'self' 54 | ``` 55 | 56 | ## Migration Plan 57 | More details on the migration efforts shall be posted and tracked in [Issue #114](https://github.com/w3c/window-management/issues/114). The following sections provide a high level overview of the migration plan. 58 | 59 | 60 | ### User Agent API Migration 61 | User agents are expected to do their own due diligence in carefully migrating user-facing descriptors. However, a general approach is described below and is the plan Chromium will follow: 62 | 1. Add the new descriptor strings "`window-management`" which act as an alias to the old descriptors "`window-placement`", gated behind a browser flag to enable or disable the new aliases. 63 | * Additionally, the browser should log a console deprecation warning when the old aliases are used by a web application. 64 | * Chromium ETA: Q4 2022 65 | 2. Slowly roll out the new alias across users and track metrics on usage of the old vs. new alias. 66 | * Chromium ETA: Q4 2022 67 | 3. Add a browser flag which removes the old alias. 68 | * Chromium ETA: Q1 2023 69 | 4. Slowly roll out the removal of the old alias. 70 | * Chromium ETA: Q2 2023 71 | 72 | ### Spec and Repository 73 | Migration of the repository and spec literature will occur slowly as needed. At a high level, the following will occur or may have already occurred: 74 | * Rename the permission and permission policy strings in the spec. 75 | * Update the permission registry with the new permission name. 76 | * Rename the title of the spec 77 | * Rename the spec repository, and create redirections from the old URL. 78 | * Rename the published spec short name and create redirections from the old URL(s). -------------------------------------------------------------------------------- /HOWTO.md: -------------------------------------------------------------------------------- 1 | # How to use the Window Management API 2 | 3 | The Window Management API is currently available in Chrome: 4 | - Chrome 100+ enables Window Management APIs by default. 5 | - Chrome 93+ supports Window Management APIs with either one of these flags enabled: 6 | - chrome://flags#enable-experimental-web-platform-features 7 | - `chrome --enable-blink-features=WindowPlacement` 8 | 9 | Try these basic API demos, which request permission to use info about your screens to open and place windows: 10 | - https://michaelwasserman.github.io/window-placement-demo 11 | - https://developer.chrome.com/articles/window-management/ has a demo: https://window-placement.glitch.me 12 | 13 | Here is an example of how to use the API: 14 | 15 | ```javascript 16 | async function main() { 17 | // Run feature detection. 18 | if (!('getScreenDetails' in window)) { 19 | console.log('The Window Manamgenet API is not supported.'); 20 | return; 21 | } 22 | // Detect the presence of extended screen areas. 23 | if (window.screen.isExtended) { 24 | // Request extended screen information. 25 | const screenDetails = await window.getScreenDetails(); 26 | 27 | // Find the primary screen, show some content fullscreen there. 28 | const primaryScreen = screenDetails.screens.find(s => s.isPrimary); 29 | document.documentElement.requestFullscreen({screen : primaryScreen}); 30 | 31 | // Find a different screen, fill its available area with a new window. 32 | const otherScreen = screenDetails.screens.find(s => s != primaryScreen); 33 | window.open(url, '_blank', `left=${otherScreen.availLeft},` + 34 | `top=${otherScreen.availTop},` + 35 | `width=${otherScreen.availWidth},` + 36 | `height=${otherScreen.availHeight}`); 37 | } else { 38 | // Arrange content within the traditional single-screen environment. 39 | } 40 | }; 41 | ``` 42 | 43 | ## How to use API enhancements 44 | 45 | [Fullscreen Companion Window](https://chromestatus.com/feature/5173162437246976) permits sites with the window-management permission to [initiate a multi-screen experience](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md) from a single user activation. Specifically, this proposed enhancement allows scripts to open a popup window when requesting fullscreen on a specific screen of a multi-screen device. Test this by invoking "Fullscreen slide and open notes" in the [window-placement-demo](https://michaelwasserman.github.io/window-placement-demo). 46 | - Chrome 104+ enables this enhancement by default. 47 | - Chrome 102+ supports this enhancement with this flag enabled: 48 | - `chrome --enable-features=WindowPlacementFullscreenCompanionWindow` 49 | 50 | [Fullscreen Capability Delegation](https://chromestatus.com/feature/6441688242323456) allows a frame to relinquish its transient user activation, in order to permit another frame (e.g. child, opener, opened popup, sibling) to request fullscreen. This tangential feature enhances multi-screen web applications by enabling a companion window to offer controls for its fullscreen opener. Specifically, fullscreen capability delegation allows a gesture on a companion window to "swap" the displays used for the fullscreen and companion windows. Test this by invoking "Fullscreen slide and open notes" in the [window-placement-demo](https://michaelwasserman.github.io/window-placement-demo), focusing the companion popup window, and pressing the [s] key to swap screens. 51 | - Chrome 104+ enables this enhancement by default. 52 | - Chrome 103+ supports this enhancement with this flag enabled: 53 | - `chrome --enable-blink-features=CapabilityDelegationFullscreenRequest` 54 | 55 | [Accurate Screen Labels](https://chromestatus.com/feature/6317530778959872) refines the `ScreenDetailed.label` implementation by replacing the current placeholder values (e.g. 'External Display 1') with data sourced from display device EDIDs (e.g. 'HP Z27n') and higher-level OS APIs (e.g. language localized 'Built-in Retina Display'). These more accurate labels match those shown by OSes in display settings UI surfaces. Test this by observing the screen label strings displayed in the [window-placement-demo](https://michaelwasserman.github.io/window-placement-demo). 56 | - Chrome 104+ supports this enhancement on some OSes with this flag enabled: 57 | - `chrome --enable-blink-features=WindowPlacementEnhancedScreenLabels` 58 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | All documents in this Repository are licensed by contributors 2 | under the 3 | [W3C Software and Document License](http://www.w3.org/Consortium/Legal/copyright-software). 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Window Management on the Web 4 | 5 | This repository considers web platform functionality to allow scripts to query 6 | the device for information about its screens, and place content on specific 7 | screens. The goals here are to explore background, use cases, and proposals for 8 | extending window placement capabilities of web applications on multi-screen 9 | devices. 10 | 11 | See the [Editor’s Draft](https://w3c.github.io/window-management/) of the proposed specification. 12 | The [Explainer](https://github.com/w3c/window-management/blob/main/EXPLAINER.md), 13 | [Additional Explorations](https://github.com/w3c/window-management/blob/main/additional_explorations.md), 14 | and [Security and Privacy](https://github.com/w3c/window-management/blob/main/security_and_privacy.md) 15 | documents also have historical context and some deeper dives into these topics. 16 | File [new issues](https://github.com/w3c/window-management/issues/new/choose), reply to our 17 | [Discourse posting](https://discourse.wicg.io/t/proposal-supporting-window-placement-on-multi-screen-devices/3948), 18 | or reach out as you see fit with feedback, relevant use cases, and thoughts. 19 | 20 | The specification is being developed by the 21 | [W3C Second Screen Working Group](http://www.w3.org/2014/secondscreen/). Please 22 | refer to the group's [Work Mode](https://www.w3.org/wiki/Second_Screen/Work_Mode) 23 | for instructions on how to contribute. 24 | 25 | 26 | ## Related explainers: 27 | | Name | Link | 28 | |------|------| 29 | | Viewport Segments Property | [Explainer](https://github.com/WICG/visual-viewport/blob/gh-pages/segments-explainer/SEGMENTS-EXPLAINER.md)| 30 | | Visual Viewport API | [Draft Community Group Report](https://wicg.github.io/visual-viewport/), [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API) | 31 | | Form Factors Explained | [Draft Community Group Report](https://webscreens.github.io/form-factors/) 32 | | Device Posture API | [W3C Editor's Draft](https://w3c.github.io/device-posture/) | 33 | -------------------------------------------------------------------------------- /additional_explorations.md: -------------------------------------------------------------------------------- 1 | # Additional Explorations of Window Placement on the Web 2 | 3 | This document explores alternatives, possible supplements, other considerations, 4 | and examples that have helped shape the current proposal, which is described in 5 | [EXPLAINER.md](https://github.com/w3c/window-management/blob/main/explainer.md). 6 | Some explorations here may be included in future iterations of the proposal, or 7 | in separate proposals, but they are **not** part of the current proposal. 8 | 9 | ## Alternatives (or possible future supplements) to the current proposal 10 | 11 | ### New window placement methods or overloads of existing methods 12 | 13 | `window.open()` is generally poorly regarded for its string-based approach to 14 | specifying features, which have been deprecated over the years. Additionally, 15 | current placement information and methods offer synchronous behavior, which does 16 | not match the asynchronous behavior of user agents and OS window managers, and 17 | precludes async permisison prompts or queries. Further, they do not clearly nor 18 | easily support multi-screen environments. 19 | 20 | One alternative or supplemental proposal to extending existing signatures of 21 | Window `open()` and `moveTo|By()` methods is to add new Window Placement methods 22 | with improved ergonomics, asynchronous behavior, user permission affordances, 23 | and more functionality. These could also be designed with multi-screen devices, 24 | new window display modes, and other related functionality in mind. Overloading 25 | existing methods may provide similar benefits, but synchronous methods likely 26 | could not return promises for overloaded signatures. 27 | 28 | This could help move use away from existing synchronous and permissionless APIs, 29 | which have been prone to abuse and inconsistencies over time, and which are 30 | currently the subject of deprecation explorations. 31 | 32 | There are several possible options for new methods or overloads: 33 | * Add a new async method to open windows, or extend 34 | [`Clients.openWindow()`](https://www.w3.org/TR/service-workers-1/#dom-clients-openwindow): 35 | * e.g. window.openWindow(url, {left: x, top: y, width: w, height: h, screen: s, ... }); 36 | * Support requests for specific screens and placement within that screen 37 | * Support requests for window states, e.g. maximized/fullscreen 38 | * Support requests for window display modes, e.g. standalone, minimal-ui 39 | * Support requests for specific inner* or outer* `width` and `height` values 40 | * Support existing `window.open()` features, and/or new features 41 | * Support feature detection via dictionary parameter? 42 | * Support async permission prompts or queries and underlying implementations 43 | * Helps moves usage away from window.open 44 | * Add a new async API to get/set `Window` bounds and other state: 45 | * window.setBounds({left: x, top: y, width: w, height: h, screen: s}); 46 | * window.getBounds() returns a Promise for corresponding information 47 | * Parallels proposed dictionaries for window opening above 48 | * Support states, display modes, etc. here or with parallel APIs 49 | * Support async permission prompts or queries and underlying implementations 50 | * Support feature detection via dictionary parameter? 51 | * Helps moves usage away from window.moveTo/By, screenX/Y, outerWidth/Height 52 | * Overload `window.open()` with a dictionary parameter, modernizing the options 53 | available to callers and offering explicit multi-monitor support: 54 | * e.g. window.open(url, name, {width: w, height: h, screen: s, ... }); 55 | * e.g. window.open(url, { name: 'name', features: '...', screen: s, ... }); 56 | * Similar to above, but overloads cannot return promises for async behavior 57 | * Overload `window.moveTo()` to accept an optional screen argument, treating the 58 | specified `x` and `y` coordinates as local to the target screen: 59 | * window.moveTo(x, y, {screen: s}); 60 | * Similar to above, but overloads cannot return promises for async behavior 61 | 62 | Here are some possible examples of new window placement methods: 63 | 64 | ```js 65 | // NEW: Dictionary of requested features for opening a window. 66 | let windowOptions = { left: 100, top: 100, outerWidth: 300, outerHeight: 500, 67 | screen: targetScreen, state: 'normal', 68 | display: 'standalone', name: 'foo', 69 | /* TODO: consider child/modal/etc. */ }; 70 | 71 | // NEW: Async method supports permissions, async WM/browser implementations. 72 | let myWindow1 = await window.openWindow(url, windowOptions); 73 | // Or perhaps overloading the exisiting synchronous method is sufficient? 74 | let myWindow2 = window.open(url, windowOptions); 75 | 76 | // NEW: async methods support permissions, handle position & size cohesively. 77 | await myWindow1.setBounds({ screen: anotherScreen, screenX: 0, screenY: 0 }); 78 | let myWindowBounds = await myWindow1.getBounds(); 79 | 80 | // NEW: Async method supports permissions, requested WM features beyond bounds. 81 | await myWindow1.setStateAndBounds({ state: 'maximized', /*...*/ }); 82 | let myWindowStateAndBounds = await myWindow1.getStateAndBounds(); 83 | ``` 84 | 85 | ### Alternative names and scopes for proposed screen information methods 86 | 87 | The proposed multi-screen info methods and events aim to offer an API shape that 88 | naturally extends the existing single-screen `window.screen` attribute. Since 89 | `Window` already hosts many attributes, functions and interfaces, care should be 90 | taken not to overburden this surface. Here are some alternative shapes: 91 | 92 | 1. A `Screens` Web IDL namespace encompassing the proposed API and future 93 | additions. For now, the new API surface may not warrant encapsulation. Using a 94 | namespace would be preferable to a non-constructable class or interface. 95 | 96 | 2. Using the `WindowOrWorkerGlobalScope` mixin would expose the proposed API in 97 | both `Window` and `Worker` execution contexts, extending access to service 98 | workers, which may aid potential future work, like opening windows from service 99 | worker launch events. This would not reduce any burden on the Window surface. 100 | 101 | 3. The [`Navigator`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator) 102 | object could be a good potential location for the proposed API, as connected 103 | screens could be considered an aspect of the user agent's environment. 104 | [`WorkerNavigator`](https://developer.mozilla.org/en-US/docs/Web/API/WorkerNavigator) 105 | could also implement the API to extend support to service workers, like above. 106 | 107 | ```js 108 | async () => { 109 | // 1 & 2: Screens namespace on Window[OrWorkerGlobalScope] 110 | // like: WindowOrWorkerGlobalScope.caches.keys() or 111 | // WindowOrWorkerGlobalScope.indexedDB.databases() 112 | // Note: A `screen` namespace may conflict with the existing window.screen. 113 | const screensV1 = await self.screens.getScreens(); 114 | const isMultiScreenV1 = await self.screens.isMultiScreen(); 115 | self.screens.onscreenschange = () => { ... } 116 | 117 | // 3: Screens namespace (or perhaps directly) on [Worker]Navigator 118 | // like: Navigator.bluetooth.requestDevice() (or Navigator.getVRDisplays()) 119 | const screensV2 = await navigator.screens.getScreens(); 120 | const isMultiScreenV2 = await navigator.screens.isMultiScreen(); 121 | navigator.screens.onscreenschange = () => { ... } 122 | 123 | // Alternative names for getScreens(): 124 | foo.getScreenInfo(); // Suitable for limited info or ScreenInfo dictionaries? 125 | foo.getDisplays(); // Suitable for non-Screen dictionaries? 126 | foo.request*(); // Match some existing requestFoo() web platform APIs? 127 | } 128 | ``` 129 | 130 | TODO: Would `onscreenschange` require a non-constructable class or similar? 131 | 132 | ### Alternative synchronous access to new screen information 133 | 134 | The leading proposal is an asynchronous interface. Alternatively, a synchronous 135 | API would match the existing `window.screen` API, but may require implementers 136 | to cache more system information and may preclude permission prompts or queries. 137 | 138 | ```js 139 | // Window (or WindowOrWorkerGlobalScope) attribute, like `window.screen` 140 | const availableScreens = self.screens; 141 | ``` 142 | 143 | With potential privacy concerns of exposing new screen and window placement 144 | information, new APIs should allow user agents to minimize information exposed 145 | without user permission. Asynchronous APIs are preferable, allowing the user 146 | agent to prompt users for permission or perform asynchronous permission model 147 | checks while the script continues processing any logic that does not depend on 148 | the result of the permission check. 149 | 150 | Additionally, system window managers themselves often provide asynchronous APIs, 151 | and this pattern allows implementers to gather the latest available information 152 | without blocking other application processing or requiring a cache. 153 | 154 | ### Exposing new info with the existing `Screen` interface 155 | 156 | The existing `Screen` interface seems like a natural and appropriate object for 157 | conveying information about each connected screen, but this interface and its 158 | attributes are already exposed synchronously via `window.screen`, which yields a 159 | live object that updates as screen properties change, or even when the window is 160 | moved to another screen. 161 | 162 | This proposal aims to return a static array of static objects and an event when 163 | any screen information changes. This seems easy for developers to reason about, 164 | easy for browsers to implement, and follows some general advice in the 165 | [Web Platform Design Principles](https://w3ctag.github.io/design-principles/#live-vs-static). 166 | 167 | Alternatives considered include returning dynamic collections of live objects 168 | (e.g. collection length changes when screens connect/disconnect, and properties 169 | of each Screen in the collection change with device configuration changes), or 170 | static collections of live objects (e.g. indivual Screen properties change, but 171 | the overall collection does not change reflect newly connected screens). There 172 | are tradeoffs to each approach, but these seem more difficult for developers to 173 | reason about, and add significant complexity to the implementation, reducing the 174 | likelihood of obtaining interoperable implementations across browsers. 175 | 176 | The leading proposal is to introduce a new `ScreenInfo` dictionary. While it is 177 | shaped similar to the existing `Screen` interface, it has clear and separate 178 | behavior as a static snapshot of comprehensive information for a particular 179 | screen. Alternatives considered include exposing a `Screen` interface for each 180 | connected screen (via `getScreens()` or `window.screens`) with: 181 | 182 | 1. New synchronously accessible `Screen` properties exposing additional info. 183 | Since user agents could not prompt users or make async permission model 184 | queries amid property access, the new properties could resolve to `undefined` 185 | or placeholder values if permission is denied, to mitigate privacy concerns. 186 | This would likely be confusing and atypical web platform behavior, and could 187 | conflict with existing non-standard `Screen` property behaviors. 188 | 189 | 2. New asynchronous methods on `Screen` exposing additional info. This would use 190 | more typical Promise patterns to support async permission prompts or queries, 191 | but introduces an inconsistency in how Screen information is exposed. 192 | 193 | 3. New asynchronous methods on another interface for additional `Screen` info. 194 | This is similar to (2), but perhaps even less ergonomic. 195 | 196 | ```js 197 | // 1: Properties are undefined or placeholders before access is granted. 198 | value = window.screen.newProperty; // Resolves to `undefined` or . 199 | await window.getScreens(); // Requests access, which is granted. 200 | value = window.screen.newProperty; // Resolves to the actual value. 201 | 202 | // 2: Add asynchronous methods on `Screen` that may prompt for access: 203 | value = await window.screen.getNewProperty(); 204 | value = await window.screen.getDictionaryWithNewProperties(); 205 | 206 | // 3: Add asynchronous methods on a new `Screens` interface: 207 | value = await window.screens.getNewPropertyForScreen(myScreen); 208 | value = await window.screens.getDictionaryWithNewPropertiesForScreen(myScreen); 209 | ``` 210 | 211 | Some of these topics are explored further in these issues: 212 | * Should the API return static or live objects? 213 | ([webscreens/screen-enumeration#12](https://github.com/webscreens/screen-enumeration/issues/12)) 214 | * Should the lifetime of a Screen object be limited? 215 | ([webscreens/screen-enumeration#8](https://github.com/webscreens/screen-enumeration/issues/8)) 216 | 217 | ### Exposing ScreenOrientation via getScreens(). 218 | 219 | Static `ScreenInfo` dictionaries seem unsuitable for exposing the methods and 220 | event handler of the `Screen` interface's 221 | [`Orientation`](https://w3c.github.io/screen-orientation/#screenorientation-interface) 222 | interface member. As such, it seems reasonable to provide static snapshots of 223 | the orientation type and angle in lieu of an `Orientation` interface object. 224 | 225 | Alternatively, `ScreenInfo` objects could provide an `Orientation` interface 226 | object but leave the methods and event handler inoperative; which would be 227 | strange and still require callers to use `window.screen` for this functionality. 228 | 229 | Yet another option would be to support cross-screen handlers, locks, etc., but 230 | there is no known use cases for this functionality. 231 | 232 | ### Comparisons of `ScreenInfo` objects with the existing `Screen` interface 233 | 234 | Given the difference of static `ScreenInfo` dictionaries and the live `Screen` 235 | interface currently exposed via `window.screen`, there should be reliable ways 236 | to compare the two, in order to get additional info for the current screen, or 237 | determine which `ScreenInfo` is for the screen currently hosting the window. 238 | 239 | Unfortunately, language limitations prohibit a staightforward direct comparison 240 | of `ScreenInfo` objects with `window.screen`, like: 241 | 242 | ```js 243 | // Find additional information about the current screen via getScreens(). 244 | const myScreen = (await getScreens()).find((s)=>{return s === window.screen;}); 245 | 246 | // Find a Screen from getScreens that is not the current screen. 247 | const otherScreen = (await getScreens()).find((s)=>{return s != window.screen;}); 248 | ``` 249 | 250 | So, it may prove useful to faciliate comparisons with one of these approaches: 251 | 252 | ```js 253 | // 1. Expose an id on the `Screen` interface, like the `ScreenInfo` id. 254 | const myScreen = (await getScreens()).find((s)=>{return s.id === window.screen.id;}); 255 | const otherScreen = (await getScreens()).find((s)=>{return s.id != window.screen.id;}); 256 | 257 | // 2. Denote the `ScreenInfo` hosting the window via `current` or similar. 258 | const myScreen = (await getScreens()).find((s)=>{return s.current;}); 259 | const otherScreen = (await getScreens()).find((s)=>{return !s.current;}); 260 | 261 | // 3. Expose a separate way to get the window's current ScreenInfo. 262 | const myScreen = await getCurrentScreen(); 263 | const otherScreen = (await getScreens()).find((s)=>{return s != myScreen;}); 264 | ``` 265 | 266 | ### Using `Screen` to represent the entire screen space. 267 | 268 | Representing the entire combined screen space with the existing `Screen` 269 | interface is inadvisable, as it would come with many complications, for example: 270 | - The union of separate physical display bounds may be an irregular shape, 271 | comprised of rectangles with different sizes and un-aligned positions. This 272 | cannot be adequately represented by the current `Screen` interface. 273 | - The set of connected physical displays may have different `Screen` properties. 274 | - Access to multi-screen information could not be easily gated by permission. 275 | 276 | ### Using cross-screen coordinates or per-screen coordinates 277 | 278 | A common convention of most window managers is to use the top-left corner of the 279 | system's primary screen as the origin of the coordinate system used to position 280 | other screens in a two-dimensional plane, relative to the primary screen. In 281 | other cases, an arbitrary point may be used as the multi-screen coordinate space 282 | origin, and all screens are placed relative to that point. 283 | 284 | Standardized aspects of the `Window` interface generally follow this pattern. 285 | The [`screenX`](https://drafts.csswg.org/cssom-view/#dom-window-screenx) and 286 | [`screenY`](https://drafts.csswg.org/cssom-view/#dom-window-screeny) properties 287 | are given "relative to the origin of the 288 | [Web-exposed screen area](https://drafts.csswg.org/cssom-view/#web-exposed-screen-area)", 289 | which is defined in terms of a singular output device, and without context for 290 | multi-screen environments. However, in practice, these values are relative to 291 | the device's multi-screen origin, which may not be the origin of the screen 292 | hosting the content `Window`. 293 | 294 | Similarly, [`moveTo()`](https://drafts.csswg.org/cssom-view/#dom-window-moveto) 295 | specifies coordinates (x, y) "relative to the top left corner of the output 296 | device", which does not account for multiple possible output devices. And 297 | [`open()`](https://drafts.csswg.org/cssom-view/#the-features-argument-to-the-open()-method) 298 | describes optional user-agent-defined clamping and coordinates relative to the 299 | ["Web-exposed \[available\] screen area"](https://drafts.csswg.org/cssom-view/#web-exposed-screen-information), 300 | both of which are defined in terms of a singlular output device. Again, in 301 | practice, these values are typically taken to be relative to the device's 302 | multi-screen origin. 303 | 304 | Unstandardized, but common properties of the 305 | [`Screen`](https://developer.mozilla.org/en-US/docs/Web/API/Screen) interface 306 | also already follow this pattern in many user agents. The values of `top`, 307 | `left`, `availTop`, and `availLeft` are generally given in coordinates relative 308 | to the device's multi-screen origin in practice. 309 | 310 | While the proposal suggests using cross-screen coordinates in existing APIs, 311 | per-screen scaling factors of the window manager (and per-document CSS pixel 312 | differences?) may pose difficulties for reliably specifying these coordinates. 313 | 314 | Further, cross-screen coordinates exposed without permission via existing API 315 | surfaces (e.g. `window.screenX|Y`) pose a privacy concern, but the proposed new 316 | permission could be used to gate access to most window placement and 317 | cross-screen information. 318 | 319 | Overall, it may be reasonable to pursue API shapes that employ per-screen 320 | coordinates with a specific target screen or implicit assumptions regarding the 321 | current screen, but the proposal suggests that the least invasive approach of 322 | using cross-screen coordinates in existing APIs is more likely to match the 323 | existing behaviors of most user agents and the working assumptions of existing 324 | web applications. 325 | 326 | Existing specifications have yielded unreliable APIs with inconsistent 327 | implementation behaviors. Some implementations clamp the requested window bounds 328 | to be within the same `Screen` as the host `Window`, while others do not. 329 | 330 | TODO: Provide a comprehensive description of current behaviors. 331 | 332 | Some proposed ways to improve the existing specifications are: 333 | * Refine existing specification language for screen information, coordinate 334 | systems, clamping behavior, etc. 335 | * Define screen information in the context of multi-screen environments 336 | * Specify coordinates relative to a specific screen or multi-screen origin 337 | * Constrain the allowed user-agent-defined clamping for `Window` methods 338 | * Clarify cross-screen coordinates when multiple scale factors are involved 339 | * Encourage implementers to use reasonable and compatible cross-screen behavior 340 | * Foster broader adoption of interoperable cross-screen behaviors without 341 | making spec changes 342 | * Possibly add non-normative language to specs regarding multi-screen support 343 | 344 | ### Specifying screens with id strings or `ScreenInfo` objects 345 | 346 | The proposed method for requesting element fullscreen on a specific screens is 347 | to specify the ScreenInfo object in the fullscreenOptions dictionary. It may be 348 | reasonable to supply the id string of the ScreenInfo object instead. There are 349 | minor tradeoffs with each option, but neither approach is a clear favorite: 350 | 351 | - Sites are more likely to validate availability when supplying an object? 352 | - Sites could store ids more easily than dictionaries? 353 | - Browsers could optionally validate a dictionary before handling the request? 354 | 355 | ### Extend APIs to control window state, display modes, etc. 356 | 357 | For reference, the space of windows states considered includes: 358 | * `normal`: Normal 'restored' state (a framed window not in another state) 359 | * `fullscreen`: Content fills the display without a frame 360 | * `maximized`: Framed content occupies the available screen space 361 | * `minimized`: Window is hidden and can be re-shown through OS controls 362 | * `snapLeft|Right`: Framed content occupies half of available screen space 363 | 364 | Window [focus](https://developer.mozilla.org/en-US/docs/Web/API/Window/focus) is 365 | a related concept that should be considered in tandem with window state APIs. 366 | 367 | Some possible ways that window state information and controls might be exposed: 368 | * Show a new window with a specific state 369 | * Restore deprecated 'fullscreen="yes"' window.open() feature (w/permission?) 370 | * Apparently deprecated for abuse, poor ergonomics, and lack of support 371 | * Making a user-granted permission a prerequisite for this feature may help 372 | * Extend window.open() feature support for 'maximized="yes"' (w/permission?) 373 | * This may suffer from similar drawbacks as 'fullscreen="yes"' without care 374 | * Extend new openWindow method dictionary parameters with a `state` member 375 | * Query or change an existing window's state 376 | * Support [window.minimize()](https://developer.mozilla.org/en-US/docs/Web/API/Window/minimize) 377 | and add similar methods to get/set individual window states 378 | * Add new methods to get or set the self/child/opener window state value 379 | * Support additional window.focus() scenarios (self, opener, etc.) 380 | * Support explicit z-ordering, such as an `"alwaysOnTop"` window state 381 | * Observe window state changes with a `onwindowstate` event (see goal below too) 382 | 383 | It may be reasonable to extend control and introspection about an application 384 | window's types or display mode, (e.g. requesting a specific type or display mode 385 | on `window.open()`, exposing the type or display mode of an open window, or 386 | requesting to change the type or display mode change for an open window, etc.): 387 | * `tab`: A conventional browser tab 388 | * `popup`: A popup created via window.open() 389 | * PWA Window [display modes](https://developer.mozilla.org/en-US/docs/Web/Manifest/display) 390 | * `fullscreen`: Window content fills the display without a frame 391 | * `standalone`: A standalone application frame 392 | * `minimal-ui`: Similar to `standalone` with a minimal set of UI elements 393 | * `browser`: A conventional browser tab 394 | 395 | There are also proposals/explorations for new display modes or modifiers: 396 | * [Window Controls Overlay](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/master/TitleBarCustomization/explainer.md) 397 | * [Display Mode Override](https://github.com/dmurph/display-mode/blob/master/explainer.md) 398 | * [Tabbed Application Mode](https://github.com/w3c/manifest/issues/737) 399 | * [More precise control over app window features](https://github.com/w3c/manifest/issues/856) 400 | 401 | Some related control over the launching of windows may be explored by: 402 | * [Service Worker Launch Event](https://github.com/WICG/sw-launch) 403 | * [Declarative Link Capturing](https://github.com/WICG/sw-launch/blob/master/declarative_link_capturing.md) 404 | 405 | Here are some possible use cases for the extended window state and display APIs: 406 | * Open a new fullscreen slideshow window on another screen, keep current window 407 | * Minimize/restore/focus associated windows per user control of a 'main' window: 408 | * Doctor minimizes patient case window, app minimizes associated image windows 409 | * Doctor selects patient case entry in a list, app restores minimized windows 410 | * Web application offers settings to show or hide minimal-ui native controls 411 | * Video conferencing window wishes to be [always-on-top](https://github.com/w3c/window-management/issues/10) 412 | 413 | There are open questions around the value and uses cases here: 414 | * Need additional attestation of compelling use cases from developers 415 | * Need to assess the risks and mitigations versus the utility offered 416 | * Consider creation and management of dependent or 'child' window types 417 | * Some capabilities are may warrant additional permission requirements, etc. 418 | 419 | Here are some basic examples of use cases solved by these types of APIs: 420 | 421 | ```js 422 | // Open a new fullscreen slideshow window, use the current window for notes. 423 | // FUTURE: Request fullscreen and a specific screen when opening a window. 424 | window.openWindow(slidesUrl, { state: 'fullscreen', screen: externalScreen }); 425 | // OR: window.open(url, name, `left=${s.left},top=${s.top},fullscreen=1`); 426 | // NEW: Add `screen` parameter on `requestFullscreen()`. 427 | document.getElementById(`notes`).requestFullscreen({ screen: internalScreen }); 428 | ``` 429 | 430 | ```js 431 | // Open a new maximized window with an image preview on a separate display. 432 | // FUTURE: Request maximized and a specific screen when opening a window. 433 | window.openWindow(imageUrl, { state: 'maximized', screen: targetScreen }); 434 | ``` 435 | 436 | TODO: Add additional use cases and examples of how they would be solved. 437 | 438 | ### Surface events on window bounds, state, or display mode changes 439 | 440 | Currently, `Window` fires an event when content is resized: 441 | [onresize](https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onresize). 442 | There may be value in firing events when windows move, when the state changes, 443 | or when the display mode changes: 444 | * Add `"onmove"`, `"onwindowdrag"`, and `"onwindowdrop"` Window events 445 | * Add `"onwindowstate"` Window event for state changes 446 | * Add `"onwindowdisplaymode"` Window event for display mode changes 447 | 448 | This would allow sites to observe window placement, state, and display mode 449 | changes, useful for recognizing, persisting, and restoring user preferences for 450 | specific windows. This would also be useful in scenarios where the relative 451 | placement of windows might inform automated placement of accompanying windows 452 | (e.g. a grid of windows or 'child' window behavior). 453 | 454 | ### Support multiple fullscreen elements from a single document 455 | 456 | As noted in the explainer, it may not be feasible or straightforward for 457 | multiple elements in the same document to show as fullscreen windows on separate 458 | screens simultaneously. This is partly due to the reuse of the underlying 459 | platform window as a rendering surface for the fullscreen window. 460 | 461 | Support for this behavior may solve some multi-screen use cases, for example: 462 | 463 | ```js 464 | const slides = document.querySelector("#slides"); 465 | const notes = document.querySelector("#notes"); 466 | // NEW: Add `screen` parameter on `requestFullscreen()`. 467 | slides.requestFullscreen({ screen: screens[1] }); 468 | // FUTURE: Additional implementer work would be needed to support showing 469 | // multiple fullscreen windows of separate elements in the same document. 470 | notes.requestFullscreen({ screen: screens[0] }); 471 | ``` 472 | 473 | ### Extend placement affordances on transient user activation 474 | 475 | Currently, the transient user activation of a button click is consumed when 476 | opening a window. That complicates or blocks scenarios that might wish to also 477 | request fullscreen from the event handler for a single user click. Relatedly, 478 | most browsers allow sites to open multiple popup windows with a single click if 479 | they have user permission. 480 | 481 | Allowing new behaviors would solve some valuable use cases, for example: 482 | * Requesting fullscreen and opening a separate new window: 483 | ```js 484 | // Open notes on the internal screen and slides on the external screen. 485 | // NEW: `left` and `top` may be outside the window's current screen. 486 | window.open(`./notes`, ``, `left=${s1.availLeft},top=${s1.availTop}`); 487 | // NEW: `screen` on `fullscreenOptions` for `requestFullscreen()`. 488 | document.getElementById(`notes`).requestFullscreen({ screen: s2 }); 489 | ``` 490 | * Opening a new window, and requesting fullscreen for that window 491 | ```js 492 | // Open slides and request that they show fullscreen on the external screen. 493 | // NEW: `left` and `top` may be outside the window's current screen. 494 | const slides = window.open(`./slides`, ``, features); 495 | // NEW: `screen` on `fullscreenOptions` for `requestFullscreen()`. 496 | slides.document.body.requestFullscreen({ screen: externalScreen }); 497 | ``` 498 | 499 | ### Allow placements that span two or more screens 500 | 501 | With the introduction of new foldable devices, and with some affordances of 502 | having a single content window in multi-screen environments, it may become more 503 | common for windows to span multiple displays. This may be worth considering as 504 | new multi-screen aware Window Placement APIs are developed. 505 | 506 | ### Support dependent or 'child' window types 507 | 508 | Dependent or child windows are useful in certain native application contexts: 509 | * Creative apps (image/audio/video) with floating palettes, previews, etc. 510 | * Medical applications with separate windows for case reports and images 511 | 512 | These windows might be grouped with their parent window is some OS entrypoints, 513 | like taskbars and window switchers, and might move and minimize/restore in 514 | tandem with the parent window. 515 | 516 | ```js 517 | // Open a dependent/child window that the OS/browser moves with a parent window. 518 | const palette = window.open("/palette", "palette", "dependent=true"); 519 | // Alternately use a proposed move event to move a companion window in tandem. 520 | window.addEventListener("move", e => { palette.moveBy(e.deltaX, e.deltaY); }); 521 | ``` 522 | 523 | ### New `ScreenInfo` properties to consider as use cases arise 524 | 525 | * `id`: A temporary generated per-origin unique ID; reset when cookies are deleted. 526 | * May be useful for persisting window placement preferences for certain screens. 527 | * `pointerTypes`: The set of PointerTypes supported by the screen. 528 | * May be useful for placing control panels on touch-screens and drawing surfaces on 529 | screens with pen support. 530 | * `accelerometer`: True if the display has an accelerometer. 531 | * May be useful for showing immersive controls (e.g. game steering wheel). 532 | * Not web-exposed 533 | * `dpi`: The display density as the number of pixels per inch. 534 | * May be useful for presenting content with tailored physical scale factors. 535 | * Web-exposed for the window's current screen via 536 | [`Window.devicePixelRatio`](https://drafts.csswg.org/cssom-view/#dom-window-devicepixelratio) 537 | * `subpixelOrder`: The order/orientation of this display's subpixels. 538 | * May be useful for adapting content presentation for some display technology. 539 | * Not web-exposed 540 | * `interlaced`: True if the display's mode is interlaced. 541 | * May be useful for adapting content presentation for some display technology. 542 | * Not web-exposed, but available via the Chrome Apps 543 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 544 | * `refreshRate`: The display's refresh rate in hertz. 545 | * May be useful for adapting content presentation for some display technology. 546 | * Not web-exposed, but available via the Chrome Apps 547 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 548 | * `overscan`: The display's insets within its screen's bounds. 549 | * May be useful for adapting content presentation for some display technology. 550 | * Not web-exposed, but available via the Chrome Apps 551 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 552 | * `mirrored`: True if the display is mirrored to another display. 553 | * May be useful for recognizing when a laptop is mirrored to a projector, etc. 554 | * Not web-exposed, but available via the Chrome Apps 555 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 556 | * `hidden`: True if the display is not visible (e.g. closed laptop). 557 | * May be useful for recognizing when displays may be active but not visible. 558 | * Not web-exposed 559 | * `hdrMetadataTypes`: The display's supported high dynamic range metadata types. 560 | * May be useful for choosing a suitable HDR display or adapting content. 561 | * May also be expressed as minimum luminance, maximum SDR luminance, 562 | maximum HDR luminance, and maximum full frame HDR luminance (see 563 | [#20](https://github.com/w3c/window-management/issues/20#issuecomment-847451686)) 564 | * Similar information is exposed or proposed - see 565 | [High Dynamic Range and Wide Gamut Color on the Web](https://w3c.github.io/ColorWeb-CG) 566 | and [Media Capabilities](https://www.w3.org/TR/media-capabilities) 567 | * `colorGamut`: The display's supported color gamut. 568 | * May be useful for choosing a suitable WCG display or adapting content. 569 | * May also be expressed with red, green, blue, and white point chromaticity 570 | coordinates (see 571 | [#20](https://github.com/w3c/window-management/issues/20#issuecomment-847451686)) 572 | * Similar information is exposed or proposed - see 573 | [High Dynamic Range and Wide Gamut Color on the Web](https://w3c.github.io/ColorWeb-CG) 574 | and [Media Capabilities](https://www.w3.org/TR/media-capabilities) 575 | 576 | ### New `Window` properties to consider exposing 577 | 578 | * The window state: (e.g. maximized, normal/restored, minimized, side-snapped) 579 | * The window type or display (e.g. normal/tab, popup, standalone application) 580 | * Events on changes: (e.g. onmove, onwindowdrag, onwindowdrop, onwindowstate) 581 | * Enumerating the list of existing windows opened for a given worker/origin 582 | 583 | ### Allowing sites to enumerate their windows 584 | 585 | This may be useful as web applications support URL handling or launch events, 586 | perhaps through service worker execution contexts. 587 | * Add `client.Enumerate()` to list existing windows from a Service Worker 588 | 589 | ### User agent screen pickers and limited power APIs 590 | 591 | Alternative API shapes giving less power to sites were considered, but generally 592 | offer poorer experiences for users and developers. For example, 593 | [webscreens/screen-enumeration#23](https://github.com/webscreens/screen-enumeration/issues/23) 594 | asks whether a picker-style API could be simpler, less powerful, and still 595 | fulfill the users cases. While these are highly desirable traits of web platform 596 | APIs, some stated use cases would be cumbersome for users and developers, if not 597 | impossible, if a user-agent screen picker or more strictly limited APIs were the 598 | only tools available. 599 | 600 | Here are some options explored, outside the separate topic of "Supporting 601 | requests for limited information", which is considered below: 602 | 603 | * Show multi-screen users a user-agent controlled screen-picker on window.open() 604 | or element.requestFullscreen(), perhaps only when a site suggests that the 605 | content is intended for certain multi-screen use (e.g. presentation material) 606 | or most suited to a particular type of screens (e.g. HDR, relative position). 607 | * This approach limits cross-screen information initially exposed to sites, 608 | but it still exposes the resulting window.screen info. 609 | * This could be as cumbersome for users as dragging windows to target screens. 610 | * It would be preferable in certain use cases for web applications to select 611 | an optimal screen based on content and available screen traits, or to 612 | specify a screen according to a user's preselected preferences, or past use. 613 | * Requests to open windows with particular bounds could not be easily tailored 614 | for the target screen, if that screen isn't known in advance of the request. 615 | * Scenarios involving presentation of content on multiple screens would 616 | amplify the cumbersome effects of a picker and increase the chances that 617 | web applications could give valuable direction over the resulting layout. 618 | * Show multi-screen users user-agent controls to move windows between screens. 619 | * Again, the resulting window.screen information is likely still available. 620 | * This could be as cumbersome for users as dragging windows to target screens. 621 | * This does not allow web applications to suggest optimal initial placements. 622 | * This does not allow web applications to save or apply user preferences. 623 | * This may conflict with OS-specific paradigms for similar window controls. 624 | * Only provide declarative APIs for web applications to place windows on the 625 | most appropriate screen, without exposing new info about available screens. 626 | * Again, the resulting window.screen information is likely still available. 627 | * It would be difficult to declaratively capture the full expressiveness of 628 | preferences that a web application might wish to convey regarding the 629 | content or circumstances of a fullscreen request. 630 | * Have the user agent apply window placements based on a user's past use. 631 | * Again, the resulting window.screen information is likely still available. 632 | * It is unclear how a user would convey screen preferences without dragging 633 | windows or using an initial picker, and it's unclear how granular these 634 | preferences should be applied, or how a user might convey more nuanced or 635 | updated preferences. 636 | * This could only benefit users on subsequent uses. 637 | 638 | ### Supporting requests for limited information 639 | 640 | It may be beneficial to extend the proposed API with a mechanism to request more 641 | limited or granular multi-screen information. This may allow web developers and 642 | user agents to cooperatively request and provide information required for 643 | specific use cases, proactively reducing the fingerprintable information shared, 644 | and potentially allowing user agents to expose more limited information without 645 | explicit user permission prompts. 646 | 647 | Perhaps getScreens() could request everything by default, and take an optional 648 | dictionary parameter to request limited information. Results could be returned 649 | in a new dictionary that could include a ScreenInfo sequence (perhaps with only 650 | the requested values populated?), and/or ancillary members with the specific 651 | requested information. Here are a couple examples of how that might work, and 652 | replace the proposed `isMultiScreen()` limited information query. 653 | 654 | ```js 655 | // Request a single bit answering the question: are multiple screens available? 656 | // This informs the value of additional information requests (and user prompts). 657 | let screen_info = await getScreens({multiScreen: true}); 658 | if (!screen_info.multiScreen) 659 | return; 660 | // Request the number of connected screens, either returning an array of 'empty' 661 | // Screen objects with undefined property values, or as a named member of a 662 | // returned dictionary, eg: { multi-screen: true, count: 2, ... }. 663 | screen_info = await getScreens({count: true}); 664 | if (screen_info.count <= 1) // OR: |if (screen_info.screens.length <= 1)| 665 | return; 666 | 667 | // Screen ids alone may suffice for some proposed Window Placement uses. 668 | screen_info = await getScreens({id: true}); 669 | document.body.requestFullscreen(screen_info.screens[1].id); 670 | 671 | // OR: call getScreens() again to request additional information, with only the 672 | // requested information available via corresponding `Screen` attributes. 673 | screen_info = await getScreens({availWidth: true, colorDepth: true}); 674 | // Use availWidth and colorDepth to determine the appropriate display. 675 | // TODO: Refine this naive example with something more realistic. 676 | document.body.requestFullscreen( 677 | (screen_info.screens[1].availWidth > screen_info.screens[0].availWidth || 678 | screen_info.screens[1].colorDepth > screen_info.screens[0].colorDepth) 679 | ? screen_info.screens[1] : screen_info.screens[0]); 680 | } 681 | ``` 682 | 683 | ## Additional topics and considerations 684 | 685 | ### Nomenclature 686 | 687 | Existing native APIs use a variety of nomenclatures to describe the distinction 688 | between physical display devices and the overall space composed by their virtual 689 | arrangement. As the web platform already uses the `Screen` interface to describe 690 | a single physical unit of rendering space, it seems natural to follow this 691 | convention and work in terms of a multi-`Screen` display environment. 692 | 693 | ### Changes to `colorDepth` and `pixelDepth` 694 | 695 | The [W3C Working Draft](https://www.w3.org/TR/cssom-view/#dom-screen-colordepth) 696 | states that `Screen.colorDepth` and `Screen.pixelDepth` "must return 24" and 697 | even explains that these "attributes are useless", but the latest 698 | [Editor's Draft](https://drafts.csswg.org/cssom-view/#dom-screen-colordepth) 699 | provides a more useful specification for these values. There is a clear signal 700 | from developers that having meaningful and accurate accurate values for these 701 | properties is useful for selecting the optimal display to present medical and 702 | creative content. 703 | 704 | ### Relation to Presentation and Remote Playback APIs 705 | 706 | The [Presentation](https://www.w3.org/TR/presentation-api/) and 707 | [Remote Playback](https://www.w3.org/TR/remote-playback/) APIs provide access to 708 | displays connected on remote devices, and to device-local secondary displays, 709 | but they are geared towards showing a single fullscreen content window on each 710 | external display and have other limitations regarding our described use cases. 711 | 712 | This proposal aims to offer compelling features that complement and extend 713 | existing Web Platform APIs. For example this proposal would offer sites the 714 | ability to show their own list of displays to the user, open non-fullscreen 715 | windows, limit display selection to those directly connected to controller 716 | device (not those on remote devices), instantly show content on multiple 717 | displays without separate user interaction steps for each display, and to swap 718 | the displays hosting each content window without re-selecting displays. 719 | 720 | ### Handling subsequent calls to `Element.requestFullscreen()` 721 | 722 | Subsequent calls targetting a different screen could move the fullscreen window 723 | to another screen. This allows web applications to offer users a simple way 724 | to swap screens used for fullscreen. For example: 725 | 726 | ```js 727 | // Step 1: Slideshow starts fullscreen on the current screen (nothing new). 728 | document.body.requestFullscreen(); 729 | ... 730 | // Step 2: User invokes a slideshow control setting to use another screen. 731 | // NEW: `requestFullscreen()` supports subsequent calls with different screens. 732 | document.body.requestFullscreen({ screen: selectedScreen }); 733 | ``` 734 | 735 | Other prospective solutions (like exiting fullscreen, moving the window across 736 | displays, and re-requesting fullscreen) may fail due to the consumption of 737 | transient user activation or suffer from undesirable flickering of intermediate 738 | states, not to mention the poor developer ergonomics of that process. 739 | 740 | Note: It may not be feasible or straightforward for multiple elements in the 741 | same document to show as fullscreen windows on separate screens simultaneously. 742 | 743 | ### Permission requirements to receive `screenschange` events 744 | 745 | Sites that have called `isMultiScreen()` may be interested in `screenschange` 746 | events that would result in a different `isMultiScreen()` value (e.g. a second 747 | screen was connected or disconnected). This avoids the need for such sites to 748 | poll `isMultiScreen()` and obviates the need for a `multiscreenchanged` event. 749 | 750 | Sites that have called `getScreens()` may be additonally interested in 751 | `screenschange` events that would yield updated screen information snapshots 752 | (e.g. the display properties of a connected screen have changed). 753 | 754 | Browser implementations may require permissions for any proposed functionality, 755 | and may choose to require a basic permission to fulfill `isMultiscreen()` calls 756 | and send corresponding `screenschange` events, while requiring a more strict 757 | permission to fulfill `getScreens()` calls and send corresponding 758 | `screenschange` events. 759 | 760 | TODO: Explore additional permission and privacy considerations here? 761 | 762 | ### Window placement affordances around `screenschange` events 763 | 764 | This proposal aims to allow some window placement actions on screen change 765 | events. For example, it may be reasonable for a site to move a fullscreen window 766 | onto a newly connected display: 767 | 768 | ```js 769 | self.addEventListener('screenschange', function(event) { 770 | // Ensure the best screen is used for fullscreen on screen change events. 771 | // NEW: screenschange event handlers may call `requestFullscreen()`. 772 | if (document.fullscreenElement) 773 | document.body.requestFullscreen({ screen: getBestScreen() }); 774 | }); 775 | ``` 776 | 777 | Since user-generated screen change events are not user activations of the site, 778 | we suggest specifically allowing Element.requestFullscreen() when the algorithm 779 | is triggered by a user-generated screen change. This parallels the existing 780 | [spec](https://fullscreen.spec.whatwg.org/#dom-element-requestfullscreen) 781 | allowance when triggered by a "user generated orientation change". 782 | 783 | ### Working with inner size versus outer size 784 | 785 | window.open() treats supplied width and height feature string values as the 786 | inner/content size, while window.resizeTo() treats supplied width and height 787 | values as outer/window sizes. Ideally developers could supply either inner or 788 | outer dimensions for either method. 789 | 790 | There is likely no meaningful reason for a site to supply the inner location of 791 | a window, (i.e. the top and left screen coordinates of the content, inset inside 792 | the window frame). 793 | 794 | ### Window placement limitations 795 | 796 | Changes allowing cross-screen window placements should still be subject to 797 | reasonable limitations, and some may be left to the discretion of implementers. 798 | 799 | Implementers generally restrict window movement to certain windows types, (e.g. 800 | standalone web app windows and popup windows, not tabbed browser windows) and 801 | only under certain circumstances (e.g. secure contexts, with transient user 802 | activation, maybe limiting the number or frequency of interactions, etc.). 803 | 804 | Window placements could be clamped to the available bounds of a single target 805 | screen, or perhaps allowed to span multiple screens. It seems reasonable for 806 | implementers to restrict window placements that would make some portion of 807 | the window appear outsides the aggregate available screen bounds. 808 | 809 | It may be valuable to provide clearly specified behaviors for some cases, or to 810 | offer non-normative guidance for how such cases could be handled. 811 | 812 | ### Respecting intents around user-agent-defined behaviors 813 | 814 | Reasonable caution should be exercised when changing implementation-specific 815 | behavior of existing Web Platform APIs, to avoid breaking existing users. The 816 | leading proposal aims to align behavior around the existing behavior of some 817 | implementers, and honor perceived intent. 818 | 819 | Still, it may be prudent for implementers to retain elements of old behavior 820 | that sites might rely upon. For example, if developers expect window placements 821 | to be clamped within the current `Screen` and supply bounds outside the overall 822 | `Screen` space (e.g. "left=99999999"), then it may be reasonable to clamp 823 | window placements within the current `Screen`, rather than within the `Screen` 824 | nearest those coordinates. 825 | 826 | ### TODO: Explore additional topics 827 | 828 | - Multi-screen media query (no clear permission support?) 829 | - Move ScreenInfo orientation* properties into a separate/nested dictionary? 830 | - Should window.screen ultimately be a static snapshot, instad of a live object? 831 | - Is ScreenOrientation access and functionality via `window.screen` appropriate? 832 | - Cross-screen window placements may be difficult to express in CSS Pixels? 833 | - Use hardware pixels or DIPs in ScreenInfo, existing or new placement APIs? 834 | - Take Screen object/id and screen-local CSS Pixel coordinates in new APIs? 835 | 836 | ## Other miscellaneous use cases and explorations 837 | 838 | ### Financial dashboard web application 839 | 840 | A financial dashboard opening multiple windows across multiple screens, using 841 | the overall screen-space information to produce a grid-like window arrangement. 842 | The application can persist and restore the layout between user sessions. 843 | 844 | TODO: Update this outdated exploration 845 | 846 | Starting the app opens all the dashboards across multiple screens: 847 | ```js 848 | // Service worker script 849 | self.addEventListener("launch", event => { 850 | event.waitUntil(async () => { 851 | const screens = self.screens; 852 | const maxDashboardCount = 5; 853 | const usedScreenCount = Math.min(screens.length, maxDashboardCount); 854 | for (let screen = 1; screen < usedScreenCount; ++screen) { 855 | await clients.openWindow(`/dashboard/${screen}`, screens[screen]); 856 | } 857 | }); 858 | }); 859 | ``` 860 | 861 | Starting the app restores all dashboards' positions from the prior session: 862 | ```js 863 | self.addEventListener("launch", event => { 864 | event.waitUntil(async () => { 865 | // Initialize IndexedDB database. 866 | const db = idb.open("db", 1, upgradeDb => { 867 | if (!upgradeDb.objectStoreNames.contains("windowConfigs")) { 868 | upgradeDb.createObjectStore("windowConfigs", { keyPath: "name" }); 869 | } 870 | }); 871 | 872 | // Retrieve preferred dashboard configurations. 873 | const configs = db.transaction(["windowConfigs"]) 874 | .objectStore("windowConfigs") 875 | .getAll(); 876 | for (let config : configs) { 877 | // Open each dashboard, assuming the user's screen setup hasn't changed. 878 | const dashboard = await clients.openWindow(config.url, config.screen); 879 | dashboard.postMessage(config.options); 880 | } 881 | }); 882 | }); 883 | 884 | // Record the latest configuration relayed by a dashboard that was just closed. 885 | self.addEventListener("message", event => { 886 | idb.open("db", 1) 887 | .transaction(["windowConfigs"], "readwrite") 888 | .objectStore("windowConfigs") 889 | .put(event.data); 890 | }); 891 | ``` 892 | 893 | ```js 894 | // Dashboard script 895 | window.name = window.location; 896 | 897 | // Configure dashboard according to preferences relayed by the Service Worker. 898 | window.addEventListener("message", event => { 899 | window.moveTo(event.data.left, event.data.top); 900 | window.resizeTo(event.data.width, event.data.height); 901 | }); 902 | 903 | // Send dashboard's configuration to the Service Worker just before closing. 904 | window.addEventListener("beforeunload", event => { 905 | const windowConfig = { 906 | name: window.name, 907 | url: window.location, 908 | options: { 909 | left: window.screenLeft, 910 | top: window.screenTop, 911 | width: window.outerWidth, 912 | height: window.outerHeight, 913 | }, 914 | screen: window.screen, 915 | }; 916 | navigator.serviceWorker.controller.postMessage(windowConfig); 917 | }); 918 | ``` 919 | 920 | Snap dashboards into place when moved, according to a pre-defined configuration: 921 | ```js 922 | // Reposition/resize window into the nearest left/right half of the screen when 923 | // programatically moved or manually dragged then dropped. 924 | window.addEventListener("windowDrop", event => { 925 | const windowCenter = window.screenLeft + window.outerWidth / 2; 926 | const screenCenter = window.screen.availLeft + window.screen.availWidth / 2; 927 | const newLeft = (windowCenter < screenCenter) ? 0 : screenCenter; 928 | window.moveTo(newLeft, 0); 929 | window.resizeTo(window.screen.width, window.screen.height); 930 | }); 931 | ``` 932 | 933 | ### Small form-factor applications, e.g. calculator, mini music player 934 | 935 | Launch the app with specific (or bounded) dimensions: 936 | ```js 937 | // Service worker script 938 | self.addEventListener("launch", event => { 939 | event.waitUntil(async () => { 940 | // At most 800px wide. 941 | const width = Math.min(window.screen.availWidth * 0.5, 800); 942 | // At least 200px tall. 943 | const height = Math.max(window.screen.availHeight * 0.3, 200); 944 | 945 | window.resizeTo(width, height); 946 | }); 947 | }); 948 | ``` 949 | -------------------------------------------------------------------------------- /logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /mdn-drafts/ScreenDetailed.md: -------------------------------------------------------------------------------- 1 | --- 2 | recipe: api-interface 3 | title: 'ScreenDetailed' 4 | mdn_url: /en-US/docs/Web/API/ScreenDetailed 5 | specifications: https://w3c.github.io/window-management/#screendetailed 6 | browser_compatibility: api.ScreenDetailed 7 | --- 8 | 9 | ## Description 10 | 11 | The `ScreenDetailed` interface of the Window Management API extends the 12 | `Screen` interface and provides additional per-screen information. 13 | 14 | The `ScreenDetailed` interface is a child of `Screen` and inherits its members. 15 | 16 | ## Constructor 17 | 18 | None. 19 | 20 | ## Properties 21 | 22 | _Inherits properties from its parent, `Screen`._ 23 | 24 | **`ScreenDetailed.left`** 25 | 26 | Returns the distance in pixels to the left edge of the screen from the primary screen origin. 27 | 28 | **`ScreenDetailed.top`** 29 | 30 | Returns the distance in pixels to the top edge of the screen from the primary screen origin. 31 | 32 | **`ScreenDetailed.isPrimary`** 33 | 34 | Returns true if this screen is the primary screen. 35 | 36 | **`ScreenDetailed.isInternal`** 37 | 38 | Returns true if this screen is built into the device, like a laptop display. 39 | 40 | **`ScreenDetailed.devicePixelRatio`** 41 | 42 | Returns the ratio of this screen's resolution in physical pixels to its resolution in CSS pixels. 43 | 44 | **`ScreenDetailed.label`** 45 | 46 | Returns a user-friendly label string for the screen, determined by the user agent and OS. 47 | 48 | ## Examples 49 | 50 | ### Detailed information about the current screen 51 | 52 | The following example shows how to query the browser for more 53 | information about the current screen. The example assumes that 54 | permission is granted. 55 | 56 | ```js 57 | 58 | window.getScreenDetails().then( 59 | screenDetails => { 60 | var screen = screenDetails.currentScreen; 61 | console.log("Label: " + screen.label); 62 | console.log("Size: " + screen.width + " x " + screen.height); 63 | console.log("Position: " + screen.left + " x " + screen.top); 64 | console.log("Scale: " + screen.devicePixelRatio); 65 | console.log("Primary? " + screen.isPrimary); 66 | console.log("Internal? " + screen.isInternal); 67 | } 68 | ); 69 | ``` 70 | 71 | ### Detailed information about the available screens 72 | 73 | The following example shows how to query the browser for more 74 | information about all available screens. The example assumes that 75 | permission is granted. 76 | 77 | ```js 78 | 79 | window.getScreenDetails().then( 80 | screenDetails => { 81 | var availableScreens = screenDetails.screens; 82 | availableScreens.forEach(screen => { 83 | console.log("Label: " + screen.label); 84 | console.log(" Size: " + screen.width + " x " + screen.height); 85 | console.log(" Position: " + screen.left + " x " + screen.top); 86 | console.log(" Scale: " + screen.devicePixelRatio); 87 | console.log(" Primary? " + screen.isPrimary); 88 | console.log(" Internal? " + screen.isInternal); 89 | }); 90 | } 91 | ); 92 | ``` 93 | -------------------------------------------------------------------------------- /mdn-drafts/ScreenDetails.md: -------------------------------------------------------------------------------- 1 | --- 2 | recipe: api-interface 3 | title: 'ScreenDetails' 4 | mdn_url: /en-US/docs/Web/API/ScreenDetails 5 | specifications: https://w3c.github.io/window-management/#screendetails 6 | browser_compatibility: api.ScreenDetails 7 | --- 8 | 9 | ## Description 10 | 11 | The `ScreenDetails` interface of the Window Management API provides multi-screen information and change events. 12 | 13 | ## Constructor 14 | 15 | None. 16 | 17 | ## Properties 18 | 19 | **`ScreenDetails.screens`** 20 | 21 | Returns an array of `ScreenDetailed` objects, which describe each connected screen. 22 | 23 | **`ScreenDetails.currentScreen`** 24 | 25 | Returns a `ScreenDetailed` object for the current screen. 26 | 27 | ## Eventhandlers 28 | 29 | **`ScreenDetails.onscreenschange`** 30 | 31 | Called when `screens` changes. 32 | 33 | Note that this is not called on changes to the attributes of individual screens. Use `Screen.onchange` to observe those changes. 34 | 35 | **`ScreenDetails.oncurrentscreenchange`** 36 | 37 | Called when any attribute on `currentScreen` changes. 38 | 39 | ## Examples 40 | 41 | ### Logging the number of connected screens 42 | 43 | The following example shows how to count the number of connected screens, 44 | or log a warning if the permission is denied. The `getScreenDetails()` call 45 | may show a permission prompt if necessary. 46 | 47 | ```js 48 | if (screen.isExtended) { 49 | window.getScreenDetials().then( 50 | screenDetails => { 51 | console.log("Screens: " + screenDetails.screens.length); 52 | }, 53 | error => { 54 | console.warn("Permission denied"); 55 | } 56 | ); 57 | } 58 | ``` 59 | 60 | ### Detecting when the set of screens change 61 | 62 | The following example logs a message if the set of available screens 63 | changes. This example assumes the permission was granted. 64 | 65 | ```js 66 | window.getScreenDetails().then( 67 | screenDetails => { 68 | screenDetails.onscreenchange = event => { 69 | console.log("screens changed"); 70 | }; 71 | } 72 | ); 73 | ``` 74 | 75 | ### Detecting when the current screen changes 76 | 77 | The following example logs a message if the current screen changes, 78 | such as when the window has moved to another screen. 79 | 80 | ```js 81 | window.getScreenDetails().then( 82 | screenDetails => { 83 | let currentScreen = screenDetails.currentScreen; 84 | screenDetails.oncurrentscreenchange = event => { 85 | if (currentScreen !== screenDetails.currentScreen) { 86 | console.log("current screen changed"); 87 | currentScreen = screenDetails.currentScreen; 88 | } 89 | }; 90 | } 91 | ); 92 | ``` 93 | -------------------------------------------------------------------------------- /mdn-drafts/currentScreen.md: -------------------------------------------------------------------------------- 1 | --- 2 | recipe: api-interface 3 | title: 'ScreenDetails.currentScreen' 4 | mdn_url: /en-US/docs/Web/API/ScreenDetails/currentScreen 5 | specifications: https://w3c.github.io/window-management/#dom-screendetails-currentscreen 6 | browser_compatibility: api.ScreenDetails.currentScreen 7 | --- 8 | 9 | ## Description 10 | 11 | The `currentScreen` read-only property of the `ScreenDetails` interface returns 12 | a `ScreenDetailed` object giving more details about the current screen 13 | than is available on the `window.screen` object. 14 | 15 | ## Syntax 16 | 17 | `var _screen_ = ScreenDetails.currentScreen` 18 | 19 | ### Value 20 | 21 | A `ScreenDetailed` object. 22 | 23 | ## Examples 24 | 25 | ### Detailed information about the current screen 26 | 27 | The following example shows how to query the browser for more 28 | information about the current screen. The example assumes that 29 | permission is granted. 30 | 31 | ```js 32 | window.getScreenDetails().then( 33 | screenDetails => { 34 | var screen = screenDetails.currentScreen; 35 | 36 | console.log("Label: " + screen.label); 37 | console.log("Size: " + screen.width + " x " + screen.height); 38 | console.log("Position: " + screen.left + " x " + screen.top); 39 | console.log("Scale: " + screen.devicePixelRatio); 40 | console.log("Primary? " + screen.isPrimary); 41 | console.log("Internal? " + screen.isInternal); 42 | } 43 | ); 44 | ``` 45 | -------------------------------------------------------------------------------- /mdn-drafts/isExtended.md: -------------------------------------------------------------------------------- 1 | --- 2 | recipe: api-interface 3 | title: 'Screen.isExtended' 4 | mdn_url: /en-US/docs/Web/API/Screen/isExtended 5 | specifications: https://w3c.github.io/window-management/#dom-screen-isextended 6 | browser_compatibility: api.Screen.isExtended 7 | --- 8 | 9 | ## Description 10 | 11 | The `isExtended` read-only property of the `Screen` interface returns true if the device has multiple screens that can be used for window placement. 12 | 13 | ## Syntax 14 | 15 | `var _extended_ = screen.isExtended` 16 | 17 | ### Value 18 | 19 | A boolean. 20 | 21 | ## Examples 22 | 23 | The following example shows how to only query for screens if the 24 | system has multiple screens that can be used for window placement, to 25 | avoid showing a permission prompt if the system only has one. 26 | 27 | ```js 28 | if (screen.isExtended) { 29 | console.log("Multiple screens available"); 30 | window.getScreenDetails().then(screenDetails => { 31 | // ... 32 | }); 33 | } 34 | ``` 35 | -------------------------------------------------------------------------------- /mdn-drafts/screens_property.md: -------------------------------------------------------------------------------- 1 | --- 2 | recipe: api-interface 3 | title: 'ScreenDetails.screens' 4 | mdn_url: /en-US/docs/Web/API/ScreenDetails/screens 5 | specifications: https://w3c.github.io/window-management/#dom-screendetails-screens 6 | browser_compatibility: api.ScreenDetails.screens 7 | --- 8 | 9 | ## Description 10 | 11 | The `screens` read-only property of the `ScreenDetails` interface returns an array of `ScreenDetailed` objects that describe the available screens. 12 | 13 | ## Syntax 14 | 15 | `var _availableScreens_ = ScreenDetails.screens` 16 | 17 | ### Value 18 | 19 | A frozen array of `ScreenDetailed` objects. 20 | 21 | ## Examples 22 | 23 | ### Detailed information about the available screens 24 | 25 | The following example shows how to query the browser for more 26 | information about all available screens. The example assumes 27 | that permission is granted. 28 | 29 | ```js 30 | window.getScreenDetails().then( 31 | screenDetails => { 32 | var availableScreens = screenDetails.screens; 33 | availableScreens.forEach(screen => { 34 | console.log("Label: " + screen.label); 35 | console.log(" Size: " + screen.width + " x " + screen.height); 36 | console.log(" Position: " + screen.left + " x " + screen.top); 37 | console.log(" Scale: " + screen.devicePixelRatio); 38 | console.log(" Primary? " + screen.isPrimary); 39 | console.log(" Internal? " + screen.isInternal); 40 | }); 41 | } 42 | ); 43 | ``` 44 | -------------------------------------------------------------------------------- /multi_screen_origin.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/w3c/window-management/2cafe16157d95ab94189a5ec57b2d5a25069d880/multi_screen_origin.psd -------------------------------------------------------------------------------- /multi_screen_origin.svg: -------------------------------------------------------------------------------- 1 | (0,0) 2 | 1280x1024 3 | Primary 4 | (1280,0) 5 | 1280x1024 6 | (0,0) 7 | (-1280,0) 8 | 1280x1024 9 | (0,0) 10 | 1280x1024 11 | Primary 12 | (0,0) 13 | (0,256) 14 | 1280x1024 15 | Primary 16 | (1280,0) 17 | 1280x1024 18 | (0,0) 19 | (0,0) 20 | 1280x1024 21 | Primary 22 | (-320,-1080) 23 | 1920x1080 24 | (0,0) 25 | (0,0) 26 | 1280x1024 27 | Primary 28 | (1300,256) 29 | 640x768 30 | (0,0) 31 | -------------------------------------------------------------------------------- /security_and_privacy.md: -------------------------------------------------------------------------------- 1 | # Security & Privacy 2 | 3 | The following considerations are taken from the [W3C Security and Privacy 4 | Self-Review Questionnaire](https://www.w3.org/TR/security-privacy-questionnaire). 5 | 6 | ## 2.1 What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary? 7 | 8 | This feature exposes information about screens connected to the device, which is 9 | necessary for multi-screen window placement use cases explored in the explainer. 10 | 11 | Currently, some limited information about the screen that each window currently 12 | occupies is available through its Screen interface and related media queries. 13 | Information about the window's placement on the current screen (or in more rich 14 | cross-screen coordinates) is already available through the Window interface. 15 | 16 | This feature provides a surface to optionally expose information about all 17 | connected screens, additional display properties of each screen, and events when 18 | the set of screens or their properties change. It also allows window placements 19 | to be exposed in multi-screen coordinates. The newly exposed information has 20 | been tailored to what would typically be required for the most essential 21 | multi-screen window placement features. See the ScreenDetailed definition for 22 | the full set of new screen properties exposed and their respective utility. 23 | 24 | It should be noted that existing `Window.screenLeft`, `screenTop`, and 25 | non-standard `Screen.left` and `top` values, are generally given in cross-screen 26 | coordinates, so it may already be possible for sites to infer the presence of, 27 | and limited information about, screens other than the one its window currently 28 | occupies. Also, some user agent implementations already allow cross-screen 29 | window placement without permission, making it possible to gather multi-screen 30 | information through brute-force movement of a window outside the current 31 | screen's bounds, checking the resulting position and `window.screen` object. 32 | 33 | If `Screen`, accessed via `Window.screen` does not expose non-standard 34 | [`left`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/left) and 35 | [`top`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/top) values, 36 | then specifying `Window.screenX` and `screenY` in multi-screen coordinates 37 | (rather than relative to the current screen) may allow sites to infer the 38 | presence of, and limited information about, screens other than the one its 39 | window currently occupies. 40 | 41 | ## 2.2 Is this specification exposing the minimum amount of information necessary to power the feature? 42 | 43 | Generally, yes. The information exposed is widely useful to a variety of window 44 | placement use cases, but not all information will be relevant to every use case. 45 | Further limiting what overall information could be exposed, may be a valuable 46 | [general principle](https://w3ctag.github.io/design-principles/#device-enumeration), 47 | but would either render this API useless or add nontrivial implementer work and 48 | API complexity for questionable utility and protections. 49 | 50 | For example, user agents could show a UI to select the screen used for element 51 | fullscreen, but this has no real advantage for users over the cumbersome current 52 | pattern of dragging windows between screens before entering fullscreen, and 53 | existing APIs like `window.screen` would expose most of the same information 54 | about that screen anyway. Additionally, user agents lack the context around a 55 | web application's window placement actions, and declarative arrangements 56 | specified by a site are unlikely to provide the requisite expressiveness for 57 | most use cases. 58 | 59 | All newly exposed information could be gated by the proposed `window-management` 60 | permission, limited to secure contexts, top-level frames, gated by user gesture, 61 | active window contexts, and other protections to help mitigate concerns around 62 | [fingerprinting](https://w3c.github.io/fingerprinting-guidance). 63 | 64 | The amount of information exposed to a given site would be at the discretion of 65 | users and their agents. Exposing the full set of proposed information (with user 66 | permission) enables web applications to offer compelling functionality, but 67 | exposing a limited subset of new information may be useful in some scenarios. 68 | 69 | Supporting queries for limited pieces of information is not directly useful to 70 | sites conducting window placement use cases, and does not specifically prohibit 71 | abusive sites from requesting all available information. Broad filters or making 72 | multiple calls with opposite filters wouldn't constrain the information returned 73 | (e.g. getScreenDetails({minWidth:10}) or getScreenDetails({internal:true}) + 74 | getscreens({internal:false})). 75 | 76 | ## 2.3 How does this specification deal with personal information or personally-identifiable information or information derived thereof? 77 | 78 | Information about the device's screens and the placement of a site's windows are 79 | exposed to the site when the user grants permission, and when other conditions 80 | are satisfied (e.g. secure context). 81 | 82 | ## 2.4 How does this specification deal with sensitive information? 83 | 84 | This API does not expose any sensitive information, beyond that described above. 85 | 86 | ## 2.5 Does this specification introduce new state for an origin that persists across browsing sessions? 87 | 88 | The user agent could persist screen permission grants. 89 | 90 | ## 2.6 What information from the underlying platform, e.g. configuration data, is exposed by this specification to an origin? 91 | 92 | This API proposes exposing about 10-18 new properties for each connected screen, 93 | most of which directly correlate with underlying platform configuration data. 94 | See `ScreenDetailed` for all properties exposed and their respective utility. 95 | 96 | ## 2.7 Does this specification allow an origin access to sensors on a user’s device? 97 | 98 | No. If anything, this API may expose the presence of touch or pen sensors 99 | associated with each display, but not access to sensor data itself. 100 | 101 | ## 2.8 What data does this specification expose to an origin? Please also document what data is identical to data exposed by other features, in the same or different contexts. 102 | 103 | The API exposes a new attribute and event on the `Screen` interface: 104 | * Whether the visual workspace extends over 2+ screens 105 | * Not web-exposed, but inferrable when a site has windows on multiple screens 106 | * Events fired when Screen attributes change 107 | * Not web-exposed, but observable with polling 108 | 109 | The API exposes a set of `ScreenDetailed` objects in a `ScreenDetails` interface, 110 | providing info about each connected display, extending the singular 111 | [`Screen`](https://developer.mozilla.org/en-US/docs/Web/API/Screen) object 112 | currently available to each window, and similar to the set of `Screen` objects 113 | available to an origin if separate windows for that origin were placed on each 114 | of the connected screens, by aggregating the respective `window.screen` objects. 115 | 116 | This API proposes exposing these properties on each `ScreenDetailed` object: 117 | * The width of the available screen area 118 | * Standardized as [Screen.availWidth](https://drafts.csswg.org/cssom-view/#dom-screen-availwidth) 119 | * The height of the available screen area 120 | * Standardized as [Screen.availHeight](https://drafts.csswg.org/cssom-view/#dom-screen-availheight) 121 | * The width of the screen area 122 | * Standardized as [Screen.width](https://drafts.csswg.org/cssom-view/#dom-screen-width) 123 | * The height of the screen area 124 | * Standardized as [Screen.height](https://drafts.csswg.org/cssom-view/#dom-screen-height) 125 | * The bits allocated to colors for a pixel of the screen 126 | * Standardized as [Screen.colorDepth](https://drafts.csswg.org/cssom-view/#dom-screen-colordepth) 127 | * The bits allocated to colors for a pixel of the screen 128 | * Standardized as [Screen.pixelDepth](https://drafts.csswg.org/cssom-view/#dom-screen-pixeldepth) 129 | * The orientation type of the screen 130 | * Standardized as [Screen.orientation.type](https://w3c.github.io/screen-orientation/#dom-screenorientation-type) 131 | * The orientation angle of the screen 132 | * Standardized as [Screen.orientation.angle](https://w3c.github.io/screen-orientation/#dom-screenorientation-angle) 133 | * The left screen coordinate 134 | * Not standardized, but already exposed by some browsers via 135 | [`Screen.left`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/left) 136 | * The top screen coordinate 137 | * Not standardized, but already exposed by some browsers via 138 | [`Screen.top`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/top) 139 | * The left available coordinate 140 | * Not standardized, but already exposed by some browsers via 141 | [`Screen.availLeft`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/availLeft) 142 | * The top available coordinate 143 | * Not standardized, but already exposed by some browsers via 144 | [`Screen.availTop`](https://developer.mozilla.org/en-US/docs/Web/API/Screen/availTop) 145 | * Whether it is internal (built-in) or external 146 | * Not web-exposed, but available via the Chrome Apps 147 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo), 148 | * Whether it is the primary display or a secondary display 149 | * Not web-exposed, but available via the Chrome Apps 150 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 151 | * The device pixel ratio for the screen 152 | * Not standardized, but already exposed by some browsers via 153 | [`Window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) 154 | * A generated identifier for the screen 155 | * Not web-exposed, but a more persistent id is available via the Chrome Apps 156 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 157 | * Whether the screen supports touch or pen input 158 | * Not web-exposed, but available via the Chrome Apps 159 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 160 | * A user-friendly label for the screen 161 | * Not web-exposed, but available via the Chrome Apps 162 | [`system.display` API](https://developer.chrome.com/apps/system_display#method-getInfo) 163 | 164 | Some window placement information is already exposed by the 165 | [`Window`](https://drafts.csswg.org/cssom-view/#extensions-to-the-window-interface) 166 | interface, but the proposal requires that bounds be specified in a cross-screen 167 | coordinate space, not relative to the window's current screen: 168 | * Bounds (in the web-exposed screen space), i.e. 169 | [`screenLeft`](https://developer.mozilla.org/en-US/docs/Web/API/Window/screenLeft), 170 | [`screenTop`](https://developer.mozilla.org/en-US/docs/Web/API/Window/screenTop), 171 | [`innerWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth), 172 | [`outerWidth`](https://developer.mozilla.org/en-US/docs/Web/API/Window/outerWidth), 173 | [`innerHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Window/innerHeight), 174 | [`outerHeight`](https://developer.mozilla.org/en-US/docs/Web/API/Window/outerHeight) 175 | * scaling factor (unstandardized), i.e. 176 | [`devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) 177 | 178 | ## 2.9 Does this specification enable new script execution/loading mechanisms? 179 | 180 | No. 181 | 182 | ## 2.10 Does this specification allow an origin to access other devices? 183 | 184 | This API allows an origin to read properties of screens connected to the device. 185 | The screen may be internally connected (e.g. the built-in display of a laptop) 186 | or externally connected (e.g. an external monitor). 187 | 188 | An origin cannot use this API to send commands to the displays, so hardening 189 | against malicious input is not a concern. 190 | 191 | Enumerating the screens connected to the device does provide significant 192 | entropy. If multiple computers are connected to the same set of screens, an 193 | attacker may use the display information to deduce that those computers are in 194 | the same physical vicinity. To mitigate this issue, user permission is required 195 | to access the display list, the API is only available on secure contexts, and 196 | the ids of each screen are generated on a per-user per-origin basis, reset when 197 | cookies are cleared. 198 | 199 | ## 2.11 Does this specification allow an origin some measure of control over a user agent’s native UI? 200 | 201 | No. 202 | 203 | ## 2.12 What temporary identifiers might this specification create or expose to the web? 204 | 205 | None. 206 | 207 | ## 2.13 How does this specification distinguish between behavior in first-party and third-party contexts? 208 | 209 | Only first-party contexts can generally control the window's placement. Third 210 | party contexts in iframes can already discern the dimensions of their frame; 211 | nothing in this proposal should affect that. Additionally, third party contexts 212 | can request element fullscreen (with the `allowfullscreen` feature policy) and 213 | open and place popup windows; this proposal extends those functionalities for 214 | cross-screen requests, with similar permission requirements to the first-party 215 | context of the main frame. 216 | 217 | ## 2.14 How does this specification work in the context of a user agent’s Private \ Browsing or "incognito" mode? 218 | 219 | The behavior should be the same as for regular mode, except that the user agent 220 | should not persist permission data and should request permission every session. 221 | 222 | ## 2.15 Does this specification have a "Security Considerations" and "Privacy Considerations" section? 223 | 224 | Yes. 225 | 226 | ## 2.16 Does this specification allow downgrading default security characteristics? 227 | 228 | No. 229 | 230 | ## 2.17. What should this questionnaire have asked? 231 | 232 | The questionnaire could ask if implementing the proposal would yield or enable 233 | any additional Security and Privacy protections. 234 | 235 | By adding the proposed `window-management` permission, browsers could further 236 | limit unpermissioned access to existing information and capabilities. 237 | 238 | For example, without the permission, browsers could: 239 | * Disregard `left` and `top` values requested via window.open()'s 240 | [features](https://developer.mozilla.org/en-US/docs/Web/API/Window/open#Window_features) 241 | argument string to reduce clickjacking risks. 242 | * Disregard requests to move popup and web application windows via 243 | [`window.moveTo(x, y)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/moveTo) 244 | to reduce clickjacking risks. 245 | * Return the corresponding innerWidth and innerHeight values for Window's 246 | [`outerWidth`](https://drafts.csswg.org/cssom-view/#dom-window-outerwidth) 247 | and 248 | [`outerHeight`](https://drafts.csswg.org/cssom-view/#dom-window-outerheight) 249 | to limit information exposed about the window frame size, which can be used to 250 | infer more granular information about the user agent, its version, and the 251 | window frame type used than would otherwise be exposed. 252 | * Return 0 for Window's 253 | [`screenX`](https://drafts.csswg.org/cssom-view/#dom-window-screenx) and 254 | [`screenY`](https://drafts.csswg.org/cssom-view/#dom-window-screeny) 255 | attributes to limit similar unnecessary information exposure. 256 | * Perhaps limit other existing Screen and Window information and capabilities. 257 | 258 | The questionnaire could also dig deeper into potential security concerns of the 259 | API, which are explored in the Privacy & Security section of the explainer. 260 | -------------------------------------------------------------------------------- /security_and_privacy_fullscreen_popups.md: -------------------------------------------------------------------------------- 1 | 2 | # 🟥 Obsolete 🟥 3 | 4 | This feature is no longer being pursued as of March 27, 2024. See [explainer](EXPLAINER_fullscreen_popups.md#obsolete). 5 | 6 | # Security & Privacy 7 | 8 | The following considerations are taken from the [W3C Security and Privacy 9 | Self-Review Questionnaire](https://www.w3.org/TR/security-privacy-questionnaire). 10 | 11 | ## 2.1. What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary? 12 | 13 | This feature does not directly expose information to web sites that [`element.requestFullscreen`](https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0) doesn't already expose. 14 | 15 | ## 2.2. Do features in your specification expose the minimum amount of information necessary to enable their intended uses? 16 | 17 | No new information is exposed to web sites. 18 | 19 | ## 2.3. How do the features in your specification deal with personal information, personally-identifiable information (PII), or information derived from them? 20 | 21 | No new information is exposed to web sites or collected from users. 22 | 23 | ## 2.4. How do the features in your specification deal with sensitive information? 24 | 25 | This API does not expose any sensitive information, beyond that described above. 26 | 27 | ## 2.5. Do the features in your specification introduce new state for an origin that persists across browsing sessions? 28 | 29 | No. 30 | 31 | ## 2.6. Do the features in your specification expose information about the underlying platform to origins? 32 | 33 | No information is exposed to web sites and the usage of the feature is gated on `window-management` permission which already exposes data that could be indirectly obtained from this API (e.g. the dimensions of a screen.). See [Window Management Security & Privacy](https://github.com/w3c/window-management/blob/main/security_and_privacy.md). 34 | 35 | ## 2.7. Does this specification allow an origin to send data to the underlying platform? 36 | 37 | No. 38 | 39 | ## 2.8. Do features in this specification enable access to device sensors? 40 | No. 41 | 42 | ## 2.9. Do features in this specification enable new script execution/loading mechanisms? 43 | 44 | No. 45 | 46 | ## 2.10. Do features in this specification allow an origin to access other devices? 47 | 48 | No. 49 | 50 | ## 2.11. Do features in this specification allow an origin some measure of control over a user agent’s native UI? 51 | 52 | Not directly, but invoking HTML Fullscreen, may [change user agent UI](https://fullscreen.spec.whatwg.org/#ui). This proposal introduces an alternative method for invoking HTML fullscreen on a new window. 53 | 54 | ## 2.12. What temporary identifiers do the features in this specification create or expose to the web? 55 | 56 | None. 57 | 58 | ## 2.13. How does this specification distinguish between behavior in first-party and third-party contexts? 59 | 60 | This feature requires the `fullscreen` [permission policy](https://w3c.github.io/webappsec-permissions-policy/#permissions-policy-http-header-field) in both the opener and the opened content (which will enter fullscreen). Additionally, the opener must be allowed the `window-management` permission policy. 61 | 62 | ## 2.14. How do the features in this specification work in the context of a browser’s Private Browsing or Incognito mode? 63 | 64 | The behavior should be the same as for regular mode, except that the user agent should not persist permission data and should request permission every session. 65 | 66 | ## 2.15. Does this specification have both "Security Considerations" and "Privacy Considerations" sections? 67 | 68 | Yes. 69 | 70 | ## 2.16. Do features in your specification enable origins to downgrade default security protections? 71 | 72 | No. 73 | 74 | ## 2.17. How does your feature handle non-"fully active" documents? 75 | 76 | This feature builds upon the existing [`window.open()`](https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-open-dev) function and inherits `window.open()`'s user activation requirements for initiating the request. The algorithm ultimately invokes [`element.requestFullscreen`](https://fullscreen.spec.whatwg.org/#ref-for-dom-element-requestfullscreen%E2%91%A0) on the [document element](https://dom.spec.whatwg.org/#ref-for-dom-document-documentelement%E2%91%A0) once it is available but skips checking user activation requirements since it was already checked in this code path by the `window.open()` algorithm. -------------------------------------------------------------------------------- /security_and_privacy_initiating_multi_screen_experiences.md: -------------------------------------------------------------------------------- 1 | # Security & Privacy of Initiating Multi-Screen Experiences 2 | 3 | The following considerations are taken from the [W3C Security and Privacy 4 | Self-Review Questionnaire](https://www.w3.org/TR/security-privacy-questionnaire). 5 | 6 | The answers pertain to the [Initiating Multi-Screen Experiences](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md) enhancement. That explainer contains pertinent 7 | [Security Considerations](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md#security-considerations) and 8 | [Privacy Considerations](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md#privacy-considerations) sections. 9 | 10 | See [security_and_privacy.md](https://github.com/w3c/window-management/blob/main/security_and_privacy.md) for answers pertaining to the underlying [Window Management API](https://www.w3.org/TR/window-management/). 11 | 12 | ## 2.1 What information might this feature expose to Web sites or other parties, and for what purposes is that exposure necessary? 13 | This feature enhancement does not expose any additional information; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#21-what-information-might-this-feature-expose-to-web-sites-or-other-parties-and-for-what-purposes-is-that-exposure-necessary). 14 | ## 2.2 Do features in your specification expose the minimum amount of information necessary to enable their intended uses? 15 | This feature enhancement does not expose any additional information; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#22-is-this-specification-exposing-the-minimum-amount-of-information-necessary-to-power-the-feature). 16 | ## 2.3 How do the features in your specification deal with personal information, personally-identifiable information (PII), or information derived from them? 17 | No additional PII is collected; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#23-how-does-this-specification-deal-with-personal-information-or-personally-identifiable-information-or-information-derived-thereof). 18 | ## 2.4 How do the features in your specification deal with sensitive information? 19 | This feature enhancement does not expose any additional sensitive information; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#24-how-does-this-specification-deal-with-sensitive-information). 20 | ## 2.5 Do the features in your specification introduce new state for an origin that persists across browsing sessions? 21 | This feature enhancement does not introduce any additional state that persists across browser sessions. The proposed capability to open a new companion window is limited by the [transient activation duration](https://html.spec.whatwg.org/multipage/interaction.html#transient-activation-duration), and fullscreen companion windows left open when a browsing session ends may be restored by the user agent at the start of the next browsing session, in the same manner as any other windows managed by the user agent. See the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#25-does-this-specification-introduce-new-state-for-an-origin-that-persists-across-browsing-sessions) 22 | ## 2.6 Do the features in your specification expose information about the underlying platform to origins? 23 | No additional information is exposed; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#26-what-information-from-the-underlying-platform-eg-configuration-data-is-exposed-by-this-specification-to-an-origin). 24 | ## 2.7 Does this specification allow an origin to send data to the underlying platform? 25 | No; the use of the platform's window manager APIs to open and place windows using this enhancement is essentially equivalent to the use of the same platform APIs without this enhancement. 26 | ## 2.8 Do features in this specification enable access to device sensors? 27 | No additional access is enabled; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#27-does-this-specification-allow-an-origin-access-to-sensors-on-a-users-device). 28 | ## 2.9 Do features in this specification enable new script execution/loading mechanisms? 29 | No; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#29-does-this-specification-enable-new-script-executionloading-mechanisms). 30 | ## 2.10 Do features in this specification allow an origin to access other devices? 31 | No additional access is allowed; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#210-does-this-specification-allow-an-origin-to-access-other-devices). 32 | ## 2.11 Do features in this specification allow an origin some measure of control over a user agent’s native UI? 33 | No; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#211-does-this-specification-allow-an-origin-some-measure-of-control-over-a-user-agents-native-ui). 34 | ## 2.12 What temporary identifiers do the features in this specification create or expose to the web? 35 | None; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#212-what-temporary-identifiers-might-this-specification-create-or-expose-to-the-web). 36 | ## 2.13 How does this specification distinguish between behavior in first-party and third-party contexts? 37 | The capability is currently limited to a same-frame context, whether that pertains to the first-party top-level context, or a third-party context of an embedded frame. The frame making the initial fullscreen request will only be granted the proposed capability when it has the required permission (and permission policy). See the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#213-how-does-this-specification-distinguish-between-behavior-in-first-party-and-third-party-contexts). 38 | ## 2.14 How do the features in this specification work in the context of a browser’s Private Browsing or Incognito mode? 39 | The behavior should be the same as for regular mode, except that the user agent should not persist permission data and should request permission every session. See the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#214-how-does-this-specification-work-in-the-context-of-a-user-agents-private--browsing-or-incognito-mode). 40 | ## 2.15 Does this specification have both "Security Considerations" and "Privacy Considerations" sections? 41 | Yes; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#215-does-this-specification-have-a-security-considerations-and-privacy-considerations-section). 42 | ## 2.16 Do features in your specification enable origins to downgrade default security protections? 43 | No; see the base API's [corresponding answer](https://github.com/w3c/window-management/blob/main/security_and_privacy.md#216-does-this-specification-allow-downgrading-default-security-characteristics). 44 | ## 2.17 How does your feature handle non-"fully active" documents? 45 | This capability can only be triggered from a "fully active" document. 46 | ## 2.18 What should this questionnaire have asked? 47 | Perhaps "What usable-security considerations does this feature raise? (e.g. risks related to spoofing or phishing)". This topic is considered thoroughly in the proposal's [Security Considerations](https://github.com/w3c/window-management/blob/main/EXPLAINER_initiating_multi_screen_experiences.md#security-considerations) section. 48 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [ 3 | "74168" 4 | ], 5 | "contacts": [ 6 | "tidoust" 7 | ], 8 | "repo-type": "rec-track" 9 | } --------------------------------------------------------------------------------