Mehrere Bildschirme mit der Window Management API verwalten

Informationen zu verbundenen Displays abrufen und Fenster relativ zu diesen Displays 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.

die sich mit der Darstellung der Bereiche des Fensters befasst, die sich auf separaten (benachbarten) Displays befinden, z. B. auf faltbaren Geräten.

Empfohlene Anwendungsfälle

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

  • Grafikeditoren mit mehreren Fenstern wie GIMP können verschiedene Bearbeitungstools in genau positionierten Fenstern platzieren.
  • Auf virtuellen Trading-Desktops können Markttrends in mehreren Fenstern angezeigt werden, die jeweils im Vollbildmodus betrachtet werden können.
  • In Diashow-Apps können Vortragsnotizen auf dem internen Hauptbildschirm und die Präsentation auf einem externen Projektor angezeigt werden.

Window Management API verwenden

Das Problem

Die bewährte Methode zum Steuern von Fenstern, Window.open(), berücksichtigt leider keine zusätzlichen Bildschirme. Einige Aspekte dieser API wirken etwas veraltet, z. B. der Parameter windowFeatures DOMString. Dennoch hat sie uns ü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) übergeben und die gewünschte Größe als width und height (bzw. innerWidth und innerHeight). Wenn Sie beispielsweise ein 400 × 300 Pixel großes Fenster öffnen möchten, das 50 Pixel vom linken und 50 Pixel vom oberen Rand entfernt ist, können 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 erhalten Sie über die Property window.screen, die ein Screen-Objekt zurückgibt. Das ist die Ausgabe auf meinem 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
*/

Wie die meisten Menschen, die in der Technologiebranche arbeiten, musste ich mich an die neue Arbeitsrealität anpassen und mein persönliches Homeoffice einrichten. Meine sieht so aus wie auf dem Foto unten. Hier findest du alle Details zu meinem Setup. Das iPad neben meinem MacBook ist über Sidecar mit dem Laptop verbunden. So kann ich das iPad bei Bedarf schnell in einen zweiten Bildschirm verwandeln.

Schulbank auf zwei Stühlen. Auf einer Schulbank stehen Schuhkartons, auf denen ein Laptop und zwei iPads liegen.
Einrichtung mit mehreren Bildschirmen

Wenn ich den größeren Bildschirm nutzen möchte, kann ich das Pop-up aus dem Codebeispiel oben auf den zweiten Bildschirm verschieben. So gehe ich vor:

popup.moveTo(2500, 50);

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

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 die Berechtigung dazu bitten. Die Berechtigung window-management kann mit der Permissions API so 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 von Berechtigungen 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 die Berechtigungsaufforderung dynamisch beim ersten Versuch anzeigen, eine der Methoden der neuen API zu verwenden. Lesen Sie weiter, um zusätzliche Informationen zu erhalten!

Die window.screen.isExtended-Property

Um herauszufinden, ob mehr als ein Bildschirm mit meinem Gerät verbunden ist, greife ich auf die Property window.screen.isExtended zu. Es wird true oder false zurückgegeben. Für meine Konfiguration wird true zurückgegeben.

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

Die Methode getScreenDetails()

Da ich jetzt weiß, dass es sich bei der aktuellen Einrichtung um eine Einrichtung mit mehreren Bildschirmen handelt, kann ich mit Window.getScreenDetails() weitere Informationen zum zweiten Bildschirm abrufen. Wenn ich diese Funktion aufrufe, wird eine 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 finden Sie im Array screens. Beachten Sie, dass der Wert von left für das iPad bei 1680 beginnt, was genau der width des integrierten Displays entspricht. So kann ich genau festlegen, wie die Bildschirme logisch angeordnet werden (nebeneinander, übereinander usw.). Außerdem sind jetzt Daten für jeden Bildschirm verfügbar, aus denen hervorgeht, 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 der Platzierung in geräteübergreifenden Fenstern oder bei Geräteänderungen aktualisiert.

Das screenschange-Ereignis

Das Einzige, was jetzt noch fehlt, ist eine Möglichkeit, Änderungen an meiner Bildschirmeinrichtung zu erkennen. Ein neues Ereignis, screenschange, tut genau das: Es wird immer dann ausgelöst, wenn sich die Bildschirmkonstellation ändert. Beachten Sie, dass „screens“ im Ereignisnamen im Plural steht. Das bedeutet, dass das Ereignis immer dann ausgelöst wird, wenn ein neuer Bildschirm oder ein vorhandener Bildschirm (physisch oder virtuell im Fall von Sidecar) angeschlossen oder getrennt wird.

Die neuen Bildschirmdetails müssen asynchron abgerufen werden, da das screenschange-Ereignis selbst diese Daten nicht enthält. 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 Live-Objekts currentScreen), kann ich auf das Ereignis currentscreenchange warten.

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 mich nur für Änderungen an einem bestimmten Bildschirm interessiere, 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 Sie mit der Methode requestFullScreen(), die ihren Namen verdient, anfordern, dass Elemente im Vollbildmodus angezeigt werden. Die Methode verwendet einen options-Parameter, an den Sie FullscreenOptions übergeben können. Bisher hatte sie nur die Property navigationUI. Die Window Management API fügt eine neue screen-Eigenschaft hinzu, mit der Sie festlegen können, auf welchem Bildschirm die Vollbildansicht gestartet werden soll. Wenn Sie beispielsweise den primären Bildschirm im Vollbildmodus anzeigen möchten, gehen Sie so vor:

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 zu polyfillen, aber Sie können ihre Form shimmen, damit Sie ausschließlich für die neue API codieren 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, d. h. die verschiedenen Ereignisse für Bildschirmänderungen und die screen-Eigenschaft von FullscreenOptions, würden in Browsern, die die API nicht unterstützen, einfach nicht ausgelöst oder ignoriert.

Demo

Wenn es Ihnen wie mir geht, behalten Sie die Entwicklung der verschiedenen Kryptowährungen genau im Auge. (In Wirklichkeit ist das natürlich nicht so, weil ich diesen Planeten liebe, aber für diesen Artikel tun wir einfach so.) Um den Überblick über meine Kryptowährungen zu behalten, habe ich eine Web-App entwickelt, mit der ich die Märkte in allen Lebenslagen im Blick behalten kann, z. B. bequem von meinem Bett aus, wo ich einen guten Einzelbildschirm habe.

Am Ende eines Bettes steht ein riesiger Fernseher. Die Beine des Autors sind teilweise zu sehen. Auf dem Bildschirm ist ein gefälschter Kryptowährungshandelsplatz zu sehen.
Entspannen und die Märkte beobachten.

Da es sich um Kryptowährungen handelt, können die Märkte jederzeit hektisch werden. Sollte das passieren, kann ich schnell an meinen Schreibtisch wechseln, wo ich mehrere Bildschirme habe. Ich kann auf das Fenster einer beliebigen Währung klicken und mir auf dem gegenüberliegenden Bildschirm schnell alle Details im Vollbildmodus ansehen. Unten sehen Sie ein aktuelles Foto von mir, das während des letzten YCY-Blutbads aufgenommen wurde. Es hat mich völlig überrascht und ich stand mit den Händen vor dem Gesicht da.

Der Autor mit den Händen vor dem panischen Gesicht, der auf den gefälschten Kryptowährungshandelsplatz starrt.
Panisch, angesichts des YCY-Blutbads.

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 gemäß den in Controlling Access to Powerful Web Platform Features definierten Grundprinzipien entwickelt und implementiert, darunter Nutzerkontrolle, Transparenz und Ergonomie. Die Window Management API stellt neue Informationen zu den mit einem Gerät verbundenen Bildschirmen bereit. Dadurch wird die Fingerprinting-Oberfläche von Nutzern vergrößert, insbesondere bei Nutzern, die mehrere Bildschirme mit ihren Geräten verbunden haben. Um diese Datenschutzbedenken zu minimieren, sind die offengelegten Bildschirmeigenschaften auf das für gängige Platzierungsanwendungsfälle erforderliche Minimum beschränkt. Für Websites ist eine Nutzerberechtigung erforderlich, um Informationen zu mehreren Bildschirmen abzurufen und Fenster auf anderen Bildschirmen zu platzieren. Während Chromium detaillierte Bildschirm-Labels zurückgibt, können Browser weniger beschreibende oder sogar leere Labels zurückgeben.

Kontrolle durch Nutzer

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

Einstellungen für Unternehmen

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, wird in den Websiteinformationen des Browsers angezeigt und kann auch über die Permissions API abgefragt werden.

Beibehalten von Berechtigungen

Der Browser speichert erteilte Berechtigungen. 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 Umsetzung Ihrer Idee benötigen? Haben Sie Fragen oder Anmerkungen zum Sicherheitsmodell?

  • Melden Sie ein Spezifikationsproblem im entsprechenden GitHub-Repository oder fügen Sie Ihre Gedanken zu einem bestehenden 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 an, fügen Sie eine einfache Anleitung zur Reproduktion hinzu und geben Sie Blink>Screen>MultiScreen in das Feld Components (Komponenten) ein.

API-Support zeigen

Planen 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 die API verwenden möchten.
  • Senden Sie einen Tweet an @ChromiumDev mit dem Hashtag #WindowManagement und teilen Sie uns mit, wo und wie Sie die Funktion verwenden.
  • Andere Browseranbieter bitten, 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.