Beheer meerdere beeldschermen met de Window Management API

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

API voor vensterbeheer

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

Voorgestelde gebruiksscenario's

Voorbeelden van sites die deze API kunnen gebruiken zijn:

  • Grafische editors met meerdere vensters à la Gimp kunnen verschillende bewerkingstools in nauwkeurig gepositioneerde vensters plaatsen.
  • Virtuele handelsdesks kunnen markttrends in meerdere vensters weergeven, die allemaal op volledig scherm kunnen worden bekeken.
  • Slideshow-apps kunnen sprekernotities weergeven op het interne primaire scherm en de presentatie op een externe projector.

Hoe de Window Management API te gebruiken

Het probleem

De beproefde benadering voor het besturen van vensters, Window.open() , kent helaas geen extra schermen. Hoewel sommige aspecten van deze API een beetje archaïsch lijken, zoals de windowFeatures DOMString parameter, heeft deze ons door de jaren heen toch goed van dienst geweest. Om de positie van een venster op te geven, kunt u de coördinaten doorgeven als left en top (of respectievelijk screenX en screenY ) en de gewenste grootte doorgeven als width en height (of respectievelijk innerWidth en innerHeight ). Om bijvoorbeeld een venster van 400×300 te openen op 50 pixels vanaf de linkerkant en 50 pixels vanaf de bovenkant, is dit de code die u zou kunnen gebruiken:

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

U kunt informatie over het huidige scherm krijgen door naar de eigenschap window.screen te kijken, 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
*/

Zoals de meeste mensen die in de techniek werken, heb ik mezelf moeten aanpassen aan de nieuwe werkrealiteit en mijn persoonlijke thuiskantoor moeten opzetten. De mijne 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 met de laptop verbonden, dus wanneer het nodig is, verander ik de iPad snel in een tweede scherm.

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

Als ik wil profiteren van het grotere scherm, kan ik de pop-up uit het bovenstaande codevoorbeeld op het tweede scherm plaatsen. Ik doe het zo:

popup.moveTo(2500, 50);

Dit is een ruwe schatting, aangezien er geen manier is om de afmetingen van het tweede scherm te kennen. De informatie van window.screen heeft alleen betrekking op het ingebouwde scherm, maar niet op het iPad-scherm. De gerapporteerde width van het ingebouwde scherm was 1680 pixels, dus het verplaatsen naar 2500 pixels zou kunnen werken om het venster naar de iPad te verschuiven, aangezien ik toevallig weet dat dit zich aan de rechterkant van mijn MacBook bevindt. Hoe kan ik dit in het algemeen doen? Blijkbaar is er een betere manier dan raden. Op 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 hiervoor 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.
}

Terwijl browsers met de oude en de nieuwe toestemmingsnaam in gebruik zijn, moet u defensieve code gebruiken wanneer u om toestemming vraagt, 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 erachter te komen of er meer dan één scherm op mijn apparaat is aangesloten, gebruik ik de eigenschap window.screen.isExtended . Het retourneert true of false . Voor mijn opstelling retourneert het true .

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

De getScreenDetails() -methode

Nu ik weet dat de huidige opstelling meerdere schermen bevat, kan ik meer informatie over het tweede scherm verkrijgen met behulp van Window.getScreenDetails() . Als u deze functie aanroept, wordt er een toestemmingsprompt weergegeven waarin wordt gevraagd of de site mag worden geopend en vensters op mijn scherm mogen worden geplaatst. De functie retourneert een belofte die wordt opgelost met een ScreenDetailed -object. Op mijn MacBook Pro 13 met een aangesloten iPad omvat dit een 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 screens . Merk op dat de waarde van left voor de iPad begint bij 1680 , wat precies de width is van het ingebouwde scherm. Hierdoor kan ik precies bepalen hoe de schermen logisch gerangschikt zijn (naast elkaar, boven elkaar, etc.). Er zijn nu ook gegevens voor elk scherm om aan te geven of het een isInternal en of het een isPrimary is. Houd er rekening mee dat het ingebouwde scherm niet noodzakelijkerwijs het primaire scherm is .

Het currentScreen veld is een live-object dat overeenkomt met het huidige window.screen . Het object wordt bijgewerkt bij vensterplaatsingen op meerdere schermen of apparaatwijzigingen.

De screenschange

Het enige dat nu ontbreekt, is een manier om te detecteren wanneer mijn scherminstellingen veranderen. Een nieuwe gebeurtenis, screenschange , doet precies dat: het wordt geactiveerd wanneer de schermconstellatie wordt gewijzigd. (Merk op dat 'schermen' een 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 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 in 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

Ten slotte, als ik alleen geïnteresseerd ben in wijzigingen aan een concreet scherm, kan ik luisteren naar 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 verzoeken om elementen op volledig scherm weer te geven via de toepasselijk genaamde requestFullScreen() -methode. De methode gebruikt een options waar u FullscreenOptions kunt doorgeven. Tot nu toe is de enige eigenschap navigationUI . De Window Management API voegt een nieuwe screen toe waarmee u kunt bepalen op welk scherm de weergave op volledig scherm moet worden gestart. Als u bijvoorbeeld het primaire scherm op volledig scherm 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);
}

Polyvulling

Het is niet mogelijk om de Window Management API te polyfillen, maar u kunt de vorm ervan opvullen, zodat u exclusief 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 de FullscreenOptions , zouden eenvoudigweg nooit worden geactiveerd of stilzwijgend worden genegeerd door niet-ondersteunende browsers.

Demo

Als je op mij lijkt, houd je de ontwikkeling van de verschillende cryptocurrencies nauwlettend in de gaten. (In werkelijkheid doe ik dat niet omdat ik van deze planeet houd, maar ga ik er omwille van dit artikel gewoon vanuit dat ik dat wel deed.) Om bij te houden welke cryptocurrencies ik bezit, heb ik een webapp ontwikkeld waarmee ik kan kijken de markten in alle levenssituaties, bijvoorbeeld vanuit het comfort van mijn bed, waar ik een fatsoenlijke opstelling met één scherm heb.

Groot tv-scherm aan het voeteneinde van een bed, waarbij de benen van de auteur gedeeltelijk zichtbaar zijn. Op het scherm een ​​nep-crypto-valutahandel.
Ontspannen en naar de markten kijken.

Omdat dit over crypto gaat, kunnen de markten op elk moment hectisch worden. Mocht dit gebeuren, dan kan ik snel naar mijn bureau gaan waar ik een opstelling met meerdere schermen heb. Ik kan op het venster van elke valuta klikken en snel de volledige details bekijken in een volledig scherm op het tegenoverliggende scherm. Hieronder staat een recente foto van mij, genomen tijdens het laatste YCY-bloedbad . Het overrompelde me volledig en liet me achter met mijn handen voor mijn gezicht .

De auteur staart met zijn handen op zijn paniekerige gezicht naar de nep-crypto-valutahandel.
Paniekachtig, 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 met behulp van de kernprincipes die zijn gedefinieerd in Toegangscontrole tot krachtige webplatformfuncties , waaronder gebruikerscontrole, transparantie en ergonomie. De Window Management API onthult nieuwe informatie over de schermen die op een apparaat zijn aangesloten, waardoor het vingerafdrukoppervlak van gebruikers wordt vergroot, vooral degenen met meerdere schermen die consequent op hun apparaten zijn aangesloten. Als een oplossing voor dit privacyprobleem zijn de eigenschappen van het blootgestelde scherm beperkt tot het minimum dat nodig is voor veelvoorkomende gebruikssituaties. Er is gebruikerstoestemming vereist voor sites om informatie op meerdere schermen te krijgen en vensters op andere schermen te plaatsen. Terwijl Chromium gedetailleerde schermlabels retourneert, staat het browsers vrij om minder beschrijvende (of zelfs lege labels) te retourneren.

Gebruikerscontrole

De gebruiker heeft volledige controle over de belichting van zijn opstelling. Ze kunnen de toestemmingsprompt accepteren of weigeren, en een eerder verleende toestemming intrekken via de site-informatiefunctie in de browser.

Enterprise-controle

Chrome Enterprise-gebruikers kunnen verschillende aspecten van de Window Management API beheren, zoals beschreven in het relevante gedeelte van de Atomic Policy Groups- instellingen.

Transparantie

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

Persistentie van toestemming

De browser houdt toestemmingsverleningen vast. De toestemming kan worden ingetrokken via de site-informatie van de browser.

Feedback

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

Vertel ons over het API-ontwerp

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

  • Dien een spec issue in op de corresponderende GitHub repo , of voeg uw gedachten toe aan een bestaand issue.

Meld een probleem met de implementatie

Heeft u een bug gevonden in de implementatie van Chrome? Of wijkt de uitvoering af van de specificaties?

  • Dien een bug in op new.crbug.com . Zorg ervoor dat u zoveel mogelijk details en eenvoudige reproductie-instructies opneemt en typ Blink>Screen>MultiScreen in het vak Componenten . Glitch werkt uitstekend voor het delen van snelle en gemakkelijke reproducties.

Toon ondersteuning voor de API

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

Handige 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.