Mehrere Bildschirme mit der Window Management API verwalten

Sie können Informationen zu verbundenen Bildschirmen abrufen und Fenster relativ zu diesen Bildschirmen positionieren.

Window Management API

Mit der Window Management API können Sie die mit Ihrem Computer verbundenen Displays auflisten und Fenster auf bestimmten Bildschirmen platzieren.

Empfohlene Anwendungsfälle

Beispiele für Websites, die diese API verwenden können:

  • Mit Grafikeditoren mit mehreren Fenstern wie Gimp können Sie verschiedene Bearbeitungstools in genau positionierten Fenstern platzieren.
  • Virtuelle Trading Desks können Markttrends in mehreren Fenstern anzeigen, die alle im Vollbildmodus geöffnet werden können.
  • Mit einer Bildschirmpräsentations-App können Sie die Vortragsnotizen auf dem internen Hauptbildschirm und die Präsentation auf einem externen Projektor anzeigen.

Window Management API verwenden

Das Problem

Die bewährte Methode zur Steuerung von Fenstern, Window.open(), erkennt leider keine zusätzlichen Bildschirme. Einige Aspekte dieser API wirken etwas archaisch, z. B. der Parameter windowFeatures DOMString. Sie hat uns jedoch über die Jahre gute Dienste geleistet. Um die Position eines Fensters anzugeben, können Sie die Koordinaten als left und top (bzw. screenX und screenY) und die gewünschte Größe als width und height (bzw. innerWidth und innerHeight) übergeben. Um beispielsweise ein 400 × 300-Fenster mit 50 Pixeln von links und 50 Pixel von oben zu öffnen, könnten Sie folgenden Code verwenden:

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

Informationen zum aktuellen Bildschirm finden Sie in der Property window.screen, die ein Screen-Objekt zurückgibt. So sieht die Ausgabe auf meinem MacBook Pro 13" aus:

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
*/

Wie die meisten Menschen, die in der Technologiebranche arbeiten, musste ich mich an die neue Arbeitsumgebung anpassen und mein persönliches Homeoffice einrichten. Meine sieht wie auf dem Foto unten aus (bei Interesse können Sie sich die vollständigen Details zu meiner Einrichtung ansehen). Das iPad neben meinem MacBook ist über Sidecar mit dem Laptop verbunden. Wenn nötig, kann ich das iPad also bei Bedarf schnell in einen zweiten Bildschirm verwandeln.

Schulbank auf zwei Stühlen. Oben auf der Schulbank befinden sich Schuhkartons, die einen Laptop und zwei iPads umgeben.
Eine Mehrfachbildschirm-Einrichtung

Wenn ich den größeren Bildschirm nutzen möchte, kann ich das Pop-up aus dem Codebeispiel oben auf dem zweiten Bildschirm platzieren. Ich mache das so:

popup.moveTo(2500, 50);

Das ist eine grobe Schätzung, da die Abmessungen des zweiten Bildschirms nicht bekannt sind. Die Informationen von window.screen decken nur den integrierten Bildschirm ab, nicht aber den iPad-Bildschirm. Die gemeldete width des integrierten Bildschirms betrug 1680 Pixel. Wenn Sie also zu 2500 Pixeln wechseln, könnte das Fenster auf das iPad verschoben werden, da ich weiß, dass es sich rechts neben meinem MacBook befindet. Wie kann ich das im Allgemeinen tun? Es gibt aber eine bessere Lösung als das Raten. Das ist die Window Management API.

Funktionserkennung

So prüfen Sie, ob die Window Management API unterstützt wird:

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

Die Berechtigung window-management

Bevor ich die Window Management API verwenden kann, muss ich den Nutzer um Erlaubnis bitten. Die Berechtigung window-management kann so mit der Permissions API abgefragt werden:

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

Solange Browser mit dem alten und dem neuen Berechtigungsnamen verwendet werden, sollten Sie beim Anfordern der Berechtigung unbedingt defensiven Code verwenden, wie im Beispiel unten.

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;
});

Der Browser kann festlegen, dass die Berechtigungsaufforderung dynamisch beim ersten Versuch angezeigt wird, eine der Methoden der neuen API zu verwenden. Lesen Sie weiter, um zusätzliche Informationen zu erhalten!

Das window.screen.isExtended-Attribut

Um herauszufinden, ob mehr als ein Bildschirm mit meinem Gerät verbunden ist, greife ich auf das Attribut window.screen.isExtended zu. Es wird true oder false zurückgegeben. Bei meiner Einrichtung wird true zurückgegeben.

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

Die Methode getScreenDetails()

Da ich jetzt weiß, dass die aktuelle Konfiguration ein Multi-Screen-System ist, kann ich mit Window.getScreenDetails() weitere Informationen zum zweiten Bildschirm abrufen. Wenn ich diese Funktion aufrufe, wird ein Berechtigungsaufforderung angezeigt, in der ich gefragt werde, ob die Website Fenster auf meinem Bildschirm öffnen und platzieren darf. Die Funktion gibt ein Promise zurück, das mit einem ScreenDetailed-Objekt aufgelöst wird. Auf meinem MacBook Pro 13 mit einem verbundenen iPad enthält dies ein screens-Feld mit zwei ScreenDetailed-Objekten:

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
  }]
}
*/

Informationen zu den verbundenen Bildschirmen sind im screens-Array verfügbar. Beachten Sie, dass der Wert von left für das iPad bei 1680 beginnt, was genau dem width des integrierten Bildschirms entspricht. So kann ich genau festlegen, wie die Bildschirme logisch angeordnet sind (nebeneinander, übereinander usw.). Außerdem gibt es jetzt Daten für jeden Bildschirm, die anzeigen, ob es sich um einen isInternal- oder einen isPrimary-Bildschirm handelt. Beachten Sie, dass der integrierte Bildschirm nicht unbedingt der primäre Bildschirm ist.

Das Feld currentScreen ist ein Live-Objekt, das dem aktuellen window.screen entspricht. Das Objekt wird bei geräteübergreifenden Placements oder Geräteänderungen aktualisiert.

Das screenschange-Ereignis

Es fehlt nur noch eine Möglichkeit, zu erkennen, wenn sich meine Bildschirmkonfiguration ändert. Genau das passiert mit dem neuen Ereignis screenschange: Es wird immer dann ausgelöst, wenn sich die Bildschirmkonstellation ändert. Beachten Sie, dass „Bildschirme“ im Ereignisnamen im Plural steht. Das Ereignis wird also ausgelöst, wenn ein neuer oder ein vorhandener Bildschirm (physisch oder virtuell im Fall von Sidecar) angeschlossen oder getrennt wird.

Die Details zum neuen Bildschirm müssen asynchron abgerufen werden, da das Ereignis screenschange diese Daten nicht selbst bereitstellt. Verwenden Sie das Live-Objekt aus einer im Cache gespeicherten Screens-Schnittstelle, um die Bildschirmdetails abzurufen.

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;
  }
});

Das currentscreenchange-Ereignis

Wenn ich nur an Änderungen am aktuellen Bildschirm interessiert bin (d. h. am Wert des Liveobjekts currentScreen), kann ich das Ereignis currentscreenchange überwachen.

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

Das change-Ereignis

Wenn ich schließlich nur an Änderungen an einem konkreten Bildschirm interessiert bin, kann ich auf das change-Ereignis dieses Bildschirms warten.

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

Neue Vollbildoptionen

Bisher konnten Elemente über die entsprechend benannte Methode requestFullScreen() im Vollbildmodus angezeigt werden. Die Methode nimmt einen options-Parameter entgegen, für den du FullscreenOptions übergeben kannst. Bisher war navigationUI die einzige Property. Die Window Management API fügt die neue screen-Eigenschaft hinzu, mit der Sie festlegen können, auf welchem Bildschirm die Vollbildansicht gestartet werden soll. So maximieren Sie beispielsweise den Hauptbildschirm:

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

Es ist nicht möglich, die Window Management API mit Polyfill zu füllen. Sie können jedoch ihre Form anpassen, um ausschließlich mit der neuen API programmieren zu können:

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;
}

Die anderen Aspekte der API, also die verschiedenen Bildschirmwechselereignisse und die screen-Eigenschaft der FullscreenOptions, werden von nicht unterstützten Browsern einfach nie ausgelöst oder stumm ignoriert.

Demo

Wenn es Ihnen wie mir geht, verfolgen Sie die Entwicklung der verschiedenen Kryptowährungen genau. (In Wirklichkeit tue ich das nicht, weil ich diesen Planeten liebe, aber für diesen Artikel nehmen wir an, dass ich es tue.) Um den Überblick über meine Kryptowährungen zu behalten, habe ich eine Web-App entwickelt, mit der ich die Märkte in allen Lebenssituationen beobachten kann, z. B. bequem von meinem Bett aus, wo ich einen guten Singlescreen-Setup habe.

Riesiger Fernseher am Ende eines Bettes, auf dem die Beine des Autors teilweise zu sehen sind. Auf dem Bildschirm ist ein gefälschter Kryptowährungs-Handelsdesk zu sehen.
Entspannt die Märkte beobachten.

Da es um Kryptowährungen geht, können die Märkte jederzeit hektisch werden. Sollte das passieren, kann ich schnell zu meinem Schreibtisch wechseln, wo ich eine Multiscreen-Einrichtung habe. Ich kann auf das Fenster einer Währung klicken und sehr schnell alle Details in einer Vollbildansicht auf der Unten ist ein aktuelles Foto von mir zu sehen, das während des letzten YCY-Massakers aufgenommen wurde. Ich war völlig überrascht und hielt mir die Hände vors Gesicht.

Der Autor hält sich die Hände vor das Gesicht und starrt auf den gefälschten Kryptowährungs-Handelsdesk.
Panikiert, weil ich das YCY-Massaker miterlebe.

Sie können die unten eingebettete Demo ausprobieren oder sich den Quellcode auf glitch ansehen.

Sicherheit und Berechtigungen

Das Chrome-Team hat die Window Management API anhand der in Controlling Access to Powerful Web Platform Features (Zugriff auf leistungsstarke Funktionen der Webplattform steuern) definierten Grundprinzipien entwickelt und implementiert, einschließlich Nutzersteuerung, Transparenz und Ergonomie. Die Window Management API stellt neue Informationen zu den Bildschirmen bereit, die mit einem Gerät verbunden sind. Dadurch wird die Fläche für den Fingerabdruck von Nutzern vergrößert, insbesondere bei Nutzern mit mehreren Bildschirmen, die ständig mit ihren Geräten verbunden sind. Zur Entschärfung des Datenschutzes sind die angezeigten Bildschirmeigenschaften auf das Minimum beschränkt, das für gängige Placement-Anwendungsfälle erforderlich ist. Websites benötigen die Nutzerberechtigung, um Informationen zu mehreren Bildschirmen abzurufen und Fenster auf anderen Bildschirmen zu platzieren. Chromium gibt zwar detaillierte Bildschirmlabels zurück, Browser können aber auch weniger beschreibende oder sogar leere Labels zurückgeben.

Nutzersteuerung

Der Nutzer hat die volle Kontrolle darüber, wie seine Konfiguration präsentiert wird. Sie können die Aufforderung zur Einwilligung akzeptieren oder ablehnen und eine zuvor erteilte Einwilligung über die Funktion „Websiteinformationen“ im Browser widerrufen.

Unternehmenssteuerung

Chrome Enterprise-Nutzer können verschiedene Aspekte der Window Management API steuern, wie im entsprechenden Abschnitt der Einstellungen für atomare Richtliniengruppen beschrieben.

Transparenz

Ob die Berechtigung zur Verwendung der Window Management API erteilt wurde, ist in den Websiteinformationen des Browsers zu sehen und kann auch über die Permissions API abgefragt werden.

Berechtigungsspeicherung

Der Browser speichert die Berechtigungsfreigaben. Die Berechtigung kann über die Websiteinformationen des Browsers widerrufen werden.

Feedback

Das Chrome-Team möchte mehr über Ihre Erfahrungen mit der Window Management API erfahren.

Informationen zum API-Design

Gibt es etwas an der API, das nicht wie erwartet funktioniert? Oder fehlen Methoden oder Eigenschaften, die Sie für die Implementierung Ihrer Idee benötigen? Haben Sie Fragen oder Kommentare zum Sicherheitsmodell?

  • Reichen Sie ein Problem mit der Spezifikation im entsprechenden GitHub-Repository ein oder fügen Sie Ihre Gedanken zu einem vorhandenen Problem hinzu.

Problem mit der Implementierung melden

Haben Sie einen Fehler in der Chrome-Implementierung gefunden? Oder weicht die Implementierung von der Spezifikation ab?

  • Melden Sie einen Fehler unter new.crbug.com. Geben Sie so viele Details wie möglich und eine einfache Anleitung für die Reproduktion an. Geben Sie Blink>Screen>MultiScreen in das Feld Komponenten ein. Glitch eignet sich hervorragend, um schnell und einfach Reproduktionen zu teilen.

Unterstützung für die API anzeigen

Beabsichtigen Sie, die Window Management API zu verwenden? Ihre öffentliche Unterstützung hilft dem Chrome-Team, Funktionen zu priorisieren, und zeigt anderen Browseranbietern, wie wichtig es ist, sie zu unterstützen.

  • Teilen Sie im WICG-Discourse-Thread mit, wie Sie es verwenden möchten.
  • Senden Sie einen Tweet mit dem Hashtag #WindowManagement an @ChromiumDev und teilen Sie uns mit, wo und wie Sie den Tweet verwenden.
  • Bitten Sie andere Browseranbieter, die API zu implementieren.

Nützliche Links

Danksagungen

Die Spezifikation der Window Management API wurde von Victor Costan, Joshua Bell und Mike Wasserman bearbeitet. Die API wurde von Mike Wasserman und Adrienne Walker implementiert. Dieser Artikel wurde von Joe Medley, François Beaufort und Kayce Basques geprüft. Vielen Dank an Laura Torrent Puig für die Fotos.