Beheer meerdere beeldschermen met de Window Management API

Ontvang informatie over aangesloten beeldschermen en positioneer vensters ten opzichte van die beeldschermen.

API voor vensterbeheer

Met de API voor vensterbeheer kunt u de beeldschermen op uw computer opsommen en vensters op specifieke schermen plaatsen.

Voorgestelde gebruiksscenario's

Voorbeelden van sites die deze API kunnen gebruiken zijn:

  • Met grafische editors met meerdere vensters zoals Gimp kunt u verschillende bewerkingshulpmiddelen in nauwkeurig gepositioneerde vensters plaatsen.
  • Virtuele handelsdesks kunnen markttrends in meerdere vensters weergeven, die u allemaal in de volledig scherm-modus kunt bekijken.
  • Met diavoorstelling-apps kunt u sprekersnotities weergeven op het interne primaire scherm en de presentatie op een externe projector.

Hoe de Window Management API te gebruiken

Het probleem

De beproefde aanpak voor het besturen van vensters, Window.open() , is helaas niet op de hoogte van extra schermen. Hoewel sommige aspecten van deze API wat ouderwets lijken, zoals de parameter windowFeatures DOMString , heeft deze ons desondanks al jarenlang goed van dienst geweest. Om de positie van een venster te specificeren, kunt u de coördinaten doorgeven als left en top (of respectievelijk screenX en screenY ) en de gewenste grootte als width en height (of respectievelijk innerWidth en innerHeight ). Om bijvoorbeeld een venster van 400×300 te openen op 50 pixels van links en 50 pixels van boven, kunt u deze code gebruiken:

const popup = window.open(
  'https://example.com/',
  'My Popup',
  'left=50,top=50,width=400,height=300',
);

Je kunt informatie over het huidige scherm verkrijgen door te kijken naar de eigenschap window.screen , die een Screen object retourneert. Dit is de uitvoer op mijn MacBook Pro 13":

window.screen;
/* Output from my MacBook Pro 13″:
  availHeight: 969
  availLeft: 0
  availTop: 25
  availWidth: 1680
  colorDepth: 30
  height: 1050
  isExtended: true
  onchange: null
  orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
  pixelDepth: 30
  width: 1680
*/

Net als de meeste mensen die in de techwereld werken, heb ik me moeten aanpassen aan de nieuwe werkrealiteit en mijn eigen thuiskantoor moeten inrichten. Mijn thuiskantoor ziet eruit zoals op de onderstaande foto (als je geïnteresseerd bent, kun je de volledige details over mijn opstelling lezen). De iPad naast mijn MacBook is via Sidecar verbonden met de laptop, zodat ik de iPad snel kan omtoveren tot een tweede scherm wanneer ik dat nodig heb.

Schoolbank op twee stoelen. Bovenop de schoolbank staan ​​schoenendozen met een laptop en twee iPads eromheen.
Een opstelling met meerdere schermen.

Als ik het grotere scherm wil benutten, kan ik de pop-up uit het bovenstaande codevoorbeeld op het tweede scherm plaatsen. Ik doe dat als volgt:

popup.moveTo(2500, 50);

Dit is een ruwe schatting, aangezien er geen manier is om de afmetingen van het tweede scherm te achterhalen. De informatie van window.screen betreft alleen het ingebouwde scherm, maar niet het iPad-scherm. De gerapporteerde width van het ingebouwde scherm was 1680 pixels, dus een overstap naar 2500 pixels zou kunnen werken om het venster naar de iPad te verplaatsen, aangezien ik toevallig weet dat deze zich rechts op mijn MacBook bevindt. Hoe kan ik dit in het algemeen doen? Blijkt dat er een betere manier is dan gokken. Die manier is de Window Management API.

Functiedetectie

Om te controleren of de Window Management API wordt ondersteund, gebruikt u:

if ('getScreenDetails' in window) {
  // The Window Management API is supported.
}

De toestemming window-management

Voordat ik de Window Management API kan gebruiken, moet ik de gebruiker om toestemming vragen. De toestemming window-management kan als volgt worden opgevraagd met de Permissions API :

let granted = false;
try {
  const { state } = await navigator.permissions.query({ name: 'window-management' });
  granted = state === 'granted';
} catch {
  // Nothing.
}

Zolang browsers met de oude en de nieuwe toestemmingsnaam in gebruik zijn, moet u ervoor zorgen dat u defensieve code gebruikt bij het aanvragen van toestemming, zoals in het onderstaande voorbeeld.

async function getWindowManagementPermissionState() {
  let state;
  // The new permission name.
  try {
    ({ state } = await navigator.permissions.query({
      name: "window-management",
    }));
  } catch (err) {
    return `${err.name}: ${err.message}`;
  }
  return state;
}

document.querySelector("button").addEventListener("click", async () => {
  const state = await getWindowManagementPermissionState();
  document.querySelector("pre").textContent = state;
});

De browser kan ervoor kiezen om de toestemmingsprompt dynamisch weer te geven bij de eerste poging om een ​​van de methoden van de nieuwe API te gebruiken. Lees verder voor meer informatie.

De eigenschap window.screen.isExtended

Om te achterhalen of er meer dan één scherm op mijn apparaat is aangesloten, open ik de eigenschap window.screen.isExtended . Deze retourneert true of false . Voor mijn configuratie retourneert hij true .

window.screen.isExtended;
// Returns `true` or `false`.

De getScreenDetails() methode

Nu ik weet dat de huidige configuratie meerdere schermen omvat, kan ik meer informatie over het tweede scherm verkrijgen met behulp van Window.getScreenDetails() . Als ik deze functie aanroep, verschijnt er een toestemmingsprompt met de vraag of de site vensters op mijn scherm mag openen en plaatsen. De functie retourneert een promise die wordt omgezet in een ScreenDetailed object. Op mijn MacBook Pro 13 met een aangesloten iPad bevat dit een screens veld met twee ScreenDetailed -objecten:

await window.getScreenDetails();
/* Output from my MacBook Pro 13″ with the iPad attached:
{
  currentScreen: ScreenDetailed {left: 0, top: 0, isPrimary: true, isInternal: true, devicePixelRatio: 2, …}
  oncurrentscreenchange: null
  onscreenschange: null
  screens: [{
    // The MacBook Pro
    availHeight: 969
    availLeft: 0
    availTop: 25
    availWidth: 1680
    colorDepth: 30
    devicePixelRatio: 2
    height: 1050
    isExtended: true
    isInternal: true
    isPrimary: true
    label: "Built-in Retina Display"
    left: 0
    onchange: null
    orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
    pixelDepth: 30
    top: 0
    width: 1680
  },
  {
    // The iPad
    availHeight: 999
    availLeft: 1680
    availTop: 25
    availWidth: 1366
    colorDepth: 24
    devicePixelRatio: 2
    height: 1024
    isExtended: true
    isInternal: false
    isPrimary: false
    label: "Sidecar Display (AirPlay)"
    left: 1680
    onchange: null
    orientation: ScreenOrientation {angle: 0, type: "landscape-primary", onchange: null}
    pixelDepth: 24
    top: 0
    width: 1366
  }]
}
*/

Informatie over de aangesloten schermen is beschikbaar in de screens . Merk op hoe de waarde van left voor de iPad begint bij 1680 , wat exact de width van het ingebouwde scherm is. Dit stelt me ​​in staat om precies te bepalen hoe de schermen logisch zijn gerangschikt (naast elkaar, boven elkaar, enz.). Er zijn nu ook gegevens voor elk scherm om aan te geven of het een isInternal scherm is en of het een isPrimary scherm is. Merk op dat het ingebouwde scherm niet per se het primaire scherm is .

Het veld currentScreen is een live-object dat overeenkomt met het huidige window.screen . Het object wordt bijgewerkt bij plaatsing van vensters op meerdere schermen of bij wijzigingen in het apparaat.

Het screenschange

Het enige wat nu nog ontbreekt, is een manier om te detecteren wanneer mijn schermconfiguratie verandert. Een nieuwe gebeurtenis, screenschange , doet precies dat: deze wordt geactiveerd wanneer de schermconfiguratie wordt gewijzigd. (Merk op dat "screens" meervoud is in de gebeurtenisnaam.) Dit betekent dat de gebeurtenis wordt geactiveerd wanneer een nieuw scherm of een bestaand scherm (fysiek of virtueel in het geval van Sidecar) wordt aangesloten of losgekoppeld.

Houd er rekening mee dat u de nieuwe schermdetails asynchroon moet opzoeken; de screenschange gebeurtenis zelf levert deze gegevens niet. Om de schermdetails op te zoeken, gebruikt u het live-object uit een gecachte Screens interface.

const screenDetails = await window.getScreenDetails();
let cachedScreensLength = screenDetails.screens.length;
screenDetails.addEventListener('screenschange', (event) => {
  if (screenDetails.screens.length !== cachedScreensLength) {
    console.log(
      `The screen count changed from ${cachedScreensLength} to ${screenDetails.screens.length}`,
    );
    cachedScreensLength = screenDetails.screens.length;
  }
});

Het currentscreenchange schermveranderingsevenement

Als ik alleen geïnteresseerd ben in wijzigingen in het huidige scherm (dat wil zeggen, de waarde van het live-object currentScreen ), kan ik luisteren naar de gebeurtenis currentscreenchange .

const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
  const details = screenDetails.currentScreen;
  console.log('The current screen has changed.', event, details);
});

De change

Als ik ten slotte alleen geïnteresseerd ben in wijzigingen aan een concreet scherm, kan ik luisteren naar change op dat scherm.

const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
  console.log('The first screen has changed.', event, firstScreen);
});

Nieuwe opties voor volledig scherm

Tot nu toe kon je elementen in volledig scherm weergeven via de toepasselijk genaamde requestFullScreen() methode. Deze methode accepteert een options -parameter waaraan je FullscreenOptions kunt doorgeven. Tot nu toe was de enige eigenschap navigationUI . De Window Management API voegt een nieuwe screen -eigenschap toe waarmee je kunt bepalen op welk scherm de volledige schermweergave moet starten. Als je bijvoorbeeld het primaire scherm volledig scherm wilt maken:

try {
  const primaryScreen = (await getScreenDetails()).screens.filter((screen) => screen.isPrimary)[0];
  await document.body.requestFullscreen({ screen: primaryScreen });
} catch (err) {
  console.error(err.name, err.message);
}

Polyfill

Het is niet mogelijk om de Window Management API aan te passen aan de nieuwe API, maar u kunt de vorm ervan wel aanpassen zodat u uitsluitend voor de nieuwe API kunt coderen:

if (!('getScreenDetails' in window)) {
  // Returning a one-element array with the current screen,
  // noting that there might be more.
  window.getScreenDetails = async () => [window.screen];
  // Set to `false`, noting that this might be a lie.
  window.screen.isExtended = false;
}

De andere aspecten van de API, dat wil zeggen de verschillende schermwijzigingsgebeurtenissen en de screen van FullscreenOptions , zouden respectievelijk nooit worden geactiveerd of stilletjes worden genegeerd door browsers die deze niet ondersteunen.

Demonstratie

Als je net als ik bent, volg je de ontwikkelingen van de verschillende cryptovaluta nauwlettend. (In werkelijkheid doe ik dat niet omdat ik van deze planeet houd, maar voor dit artikel neem ik aan dat ik dat wel deed.) Om de cryptovaluta die ik bezit bij te houden, heb ik een webapp ontwikkeld waarmee ik de markten in alle levenssituaties kan volgen, bijvoorbeeld vanuit mijn comfortabele bed, waar ik een degelijke opstelling met één scherm heb.

Een enorm tv-scherm aan het voeteneind van een bed, met de benen van de auteur gedeeltelijk zichtbaar. Op het scherm een ​​nep-handelsbalie voor cryptovaluta.
Ontspannen en de markten bekijken.

Omdat het om crypto gaat, kunnen de markten op elk moment hectisch worden. Mocht dit gebeuren, dan kan ik snel naar mijn bureau gaan waar ik een multi-screen setup heb. Ik kan op het venster van een valuta klikken en snel de volledige details in een volledig scherm op het andere scherm bekijken. Hieronder zie je een recente foto van mij, genomen tijdens het laatste YCY-bloedbad . Ik was er compleet door verrast en zat met mijn handen op mijn gezicht .

De auteur staart met zijn handen op zijn paniekerige gezicht naar de nep-cryptovaluta-handelstafel.
In paniek, getuige van het YCY-bloedbad.

Je kunt spelen met de onderstaande demo , of de broncode bekijken op glitch.

Beveiliging en machtigingen

Het Chrome-team heeft de Window Management API ontworpen en geïmplementeerd op basis van de kernprincipes die zijn gedefinieerd in 'Toegang tot krachtige webplatformfuncties beheren' , waaronder gebruikerscontrole, transparantie en ergonomie. De Window Management API maakt nieuwe informatie beschikbaar over de schermen die met een apparaat zijn verbonden, waardoor het vingerafdrukoppervlak van gebruikers wordt vergroot, met name gebruikers die consistent meerdere schermen met hun apparaten hebben verbonden. Om dit privacyprobleem te beperken, worden de beschikbare schermeigenschappen beperkt tot het minimum dat nodig is voor veelvoorkomende plaatsingsscenario's. Gebruikerstoestemming is vereist voor websites om informatie over meerdere schermen te verkrijgen en vensters op andere schermen te plaatsen. Chromium retourneert gedetailleerde schermlabels, maar browsers kunnen ook minder beschrijvende (of zelfs lege) labels retourneren.

Gebruikerscontrole

De gebruiker heeft volledige controle over de zichtbaarheid van zijn of haar instellingen. Hij of zij kan de toestemmingsvraag accepteren of weigeren en een eerder verleende toestemming intrekken via de site-informatiefunctie in de browser.

Bedrijfscontrole

Gebruikers van Chrome Enterprise kunnen verschillende aspecten van de Window Management API beheren, zoals beschreven in het betreffende gedeelte van de instellingen voor Atomic Policy Groups .

Transparantie

Of de toestemming om de Window Management API te gebruiken is verleend, is zichtbaar in de site-informatie van de browser en kan ook worden opgevraagd via de Permissions API.

Permissiepersistentie

De browser behoudt de verleende toestemmingen. De toestemming kan worden ingetrokken via de sitegegevens van de browser.

Feedback

Het Chrome-team wil graag uw ervaringen met de Window Management API horen.

Vertel ons over het API-ontwerp

Werkt er iets aan de API dat niet werkt zoals u verwachtte? Of ontbreken er methoden of eigenschappen die u nodig hebt om uw idee te implementeren? Heeft u een vraag of opmerking over het beveiligingsmodel?

  • Dien een spec-probleem in op de bijbehorende GitHub-repository of voeg uw mening toe over een bestaand probleem.

Meld een probleem met de implementatie

Heb je een bug gevonden in de implementatie van Chrome? Of wijkt de implementatie af van de specificatie?

Toon ondersteuning voor de API

Bent u van plan de Window Management API te gebruiken? Uw publieke steun helpt het Chrome-team om functies te prioriteren en laat andere browserleveranciers zien hoe belangrijk het is om deze te ondersteunen.

Nuttige links

Dankbetuigingen

De Window Management API-specificatie is bewerkt door Victor Costan , Joshua Bell en Mike Wasserman . De API is geïmplementeerd door Mike Wasserman en Adrienne Walker . Dit artikel is beoordeeld door Joe Medley , François Beaufort en Kayce Basques . Met dank aan Laura Torrent Puig voor de foto's.