Beheer meerdere beeldschermen met de Window Management API.

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

Gepubliceerd: 14 september 2020

Window Management API

Met de Window Management API kunt u de op uw computer aangesloten beeldschermen opsommen en vensters op specifieke schermen plaatsen.

Voorgestelde gebruiksscenario's

Voorbeelden van sites die deze API kunnen gebruiken zijn:

  • Grafische editors met meerdere vensters, zoals GIMP, kunnen verschillende bewerkingshulpmiddelen in nauwkeurig gepositioneerde vensters plaatsen.
  • Virtuele handelsdesks kunnen markttrends in meerdere vensters weergeven, die allemaal in volledig scherm kunnen worden bekeken.
  • Diashow-apps kunnen sprekersnotities op het interne hoofdscherm weergeven en de presentatie op een externe projector.

Hoe gebruik je de Window Management API?

De beproefde methode voor het beheren van vensters, Window.open() , houdt helaas geen rekening met extra schermen. Hoewel sommige aspecten van deze API wat archaïsch lijken, zoals de DOMString parameter windowFeatures , heeft deze ons door de jaren heen goed van dienst bewezen. Om de positie van een venster te specificeren, kunt u de coördinaten doorgeven als left en top (of screenX en screenY respectievelijk) en de gewenste grootte als width en height (of innerWidth en innerHeight respectievelijk). Om bijvoorbeeld een venster van 400×300 pixels te openen op 50 pixels van links en 50 pixels van boven, kunt u de volgende 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 de eigenschap window.screen te bekijken, 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 techsector werken, heb ik me moeten aanpassen aan de realiteit van het werken in 2020 en mijn eigen thuiskantoor ingericht. Dat van mij ziet eruit zoals op de foto (als je geïnteresseerd bent, kun je de volledige details over mijn opstelling lezen). De iPad naast mijn MacBook is via Sidecar met de laptop verbonden, zodat ik de iPad snel als tweede scherm kan gebruiken wanneer dat nodig is.

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

Als ik optimaal gebruik wil maken van het grotere scherm, kan ik de pop-up uit het codevoorbeeld op het tweede scherm plaatsen. Dat doe ik als volgt:

popup.moveTo(2500, 50);

Dit is een ruwe schatting, aangezien de afmetingen van het tweede scherm niet bekend zijn. De informatie van window.screen heeft alleen betrekking op het ingebouwde scherm, niet op het iPad-scherm. De gerapporteerde width van het ingebouwde scherm was 1680 pixels, dus een breedte van 2500 pixels zou wellicht werken om het venster naar de iPad te verplaatsen, aangezien ik weet dat deze zich aan de rechterkant van mijn MacBook bevindt. Hoe kan ik dit in het algemeen doen? Het blijkt dat er een betere manier is dan gokken. Die manier is de Window Management API.

Kenmerkdetectie

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

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

De window-management

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

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

Zorg ervoor dat u, terwijl browsers met zowel de oude als de nieuwe toestemmingsnaam in gebruik zijn, defensieve code gebruikt bij het aanvragen van toestemming, zoals in het 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, raadpleeg ik de eigenschap ` window.screen.isExtended . Deze retourneert true of false . In mijn geval retourneert deze true .

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

De getScreenDetails() methode

Nu ik weet dat de huidige configuratie meerdere schermen ondersteunt, kan ik meer informatie over het tweede scherm verkrijgen met behulp van Window.getScreenDetails() . Het aanroepen van deze functie zal een toestemmingsprompt weergeven waarin mij wordt gevraagd of de site vensters op mijn scherm mag openen en plaatsen. De functie retourneert een promise die wordt opgelost met een ScreenDetailed object. Op mijn MacBook Pro 13 met een aangesloten iPad bevat dit een veld screens 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 array screens . Let op hoe de waarde van left voor de iPad begint bij 1680 , wat precies 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 die aangeven of het een ` isInternal of een ` isPrimary scherm is. Merk op dat het ingebouwde scherm niet per se het primaire scherm is .

Het veld currentScreen is een dynamisch object dat overeenkomt met het huidige window.screen . Dit object wordt bijgewerkt wanneer vensters over meerdere schermen worden geplaatst of wanneer er van apparaat wordt gewisseld.

De 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" in het meervoud staat in de naam van de gebeurtenis.) 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.

Je moet de details van het nieuwe scherm asynchroon opzoeken; de screenschange gebeurtenis zelf levert deze gegevens niet. Gebruik hiervoor het `live`-object van een in de cache opgeslagen 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;
  }
});

De currentscreenchange

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

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 specifiek scherm, kan ik luisteren naar de change van 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 via de toepasselijk genaamde methode requestFullScreen() verzoeken om elementen in de volledige schermmodus weer te geven. Deze methode accepteert een parameter options waaraan je FullscreenOptions kunt doorgeven. Tot nu toe was de enige eigenschap navigationUI . De Window Management API voegt een nieuwe eigenschap screen toe waarmee je kunt bepalen op welk scherm de volledige schermweergave moet beginnen. Als je bijvoorbeeld het primaire scherm in de volledige schermmodus wilt weergeven:

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 te polyfillen, maar je kunt de structuur ervan aanpassen zodat je uitsluitend met de nieuwe API kunt programmeren:

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

De andere aspecten van de API, namelijk de verschillende gebeurtenissen voor schermwisselingen en de screen van de FullscreenOptions , zouden nooit worden geactiveerd of respectievelijk stilzwijgend worden genegeerd door browsers die deze niet ondersteunen.

Demo

Als u de ontwikkelingen van de verschillende cryptovaluta op de voet volgt, kunt u de markten vanuit uw luie stoel in de gaten houden met één scherm in mijn applicatie. (Ik doe dat zelf absoluut niet, want ik ben dol op deze planeet, maar laten we voor dit artikel even aannemen dat ik dat wel deed.)

Een enorm tv-scherm aan het voeteneinde van een bed, waarbij de benen van de auteur gedeeltelijk zichtbaar zijn. Op het scherm is een nep-handelsplatform voor cryptovaluta te zien.
Ontspannen en de markten bekijken.

Omdat het hier om crypto gaat, kunnen de markten op elk moment hectisch worden. Mocht dat gebeuren, dan kan ik snel naar mijn bureau gaan waar ik een opstelling met meerdere schermen heb. Ik kan op het venster van een willekeurige valuta klikken en snel alle details in een volledig scherm op het andere scherm bekijken. Hier is een recente foto van mij, genomen tijdens de laatste YCY-crash . Het overviel me volledig en ik sloeg mijn handen voor mijn gezicht .

Ik, in paniek, was getuige van het bloedbad bij YCY.

Speel de demo uit of bekijk de broncode op GitHub.

Beveiliging en machtigingen

Het Chrome-team heeft de Window Management API ontworpen en geïmplementeerd op basis van de kernprincipes die zijn vastgelegd in Controlling Access to Powerful Web Platform Features , waaronder gebruikerscontrole, transparantie en ergonomie. De Window Management API onthult nieuwe informatie over de schermen die op een apparaat zijn aangesloten, waardoor de mogelijkheden voor het identificeren van gebruikersprofielen toenemen, met name voor gebruikers met meerdere schermen die continu op hun apparaten zijn aangesloten. Om deze privacyproblematiek te beperken, worden de weergegeven schermeigenschappen beperkt tot het minimum dat nodig is voor gangbare plaatsingsscenario's.

Gebruikers moeten toestemming geven om informatie over meerdere schermen op te halen en vensters op andere schermen te plaatsen. Hoewel Chromium gedetailleerde schermlabels weergeeft, kunnen browsers ook minder beschrijvende (of zelfs lege) labels gebruiken.

Gebruikersbesturing

De gebruiker heeft volledige controle over de openbaarheid van zijn of haar instellingen. De gebruiker kan de toestemmingsprompt accepteren of weigeren en een eerder verleende toestemming intrekken via de site-informatie in de browser.

Bedrijfsbeheer

Chrome Enterprise-gebruikers 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 voor het gebruik van de Window Management API is verleend, wordt weergegeven in de site-informatie van de browser en kan ook worden opgevraagd met de Permissions API.

Persistentie van toestemming

De browser bewaart verleende toestemmingen. Deze toestemming kan worden ingetrokken via de site-informatie van de browser.

Feedback

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

Toon je steun voor de API

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

  • Deel op het WICG-discussieforum hoe je van plan bent het te gebruiken.
  • Stuur een tweet naar @ChromiumDev met de hashtag #WindowManagement en laat ons weten waar en hoe je het gebruikt.
  • Vraag andere browserleveranciers om de API te implementeren.

Bronnen

Dankbetuigingen

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