Gestion de plusieurs écrans avec l'API de gestion des fenêtres

Obtenez des informations sur les écrans connectés et positionnez les fenêtres par rapport à ces écrans.

API Window Management

L'API Window Management vous permet d'énumérer les écrans connectés à votre ordinateur et de placer des fenêtres sur des écrans spécifiques.

Cas d'utilisation suggérés

Voici quelques exemples de sites qui peuvent utiliser cette API:

  • Éditeurs graphiques multifenêtres à la Gimp peut placer diverses dans les fenêtres positionnées avec précision.
  • Les bureaux de négociation virtuels peuvent afficher les tendances du marché dans plusieurs fenêtres, chacune pouvant être visualisée dans mode plein écran.
  • Les applications de diaporama peuvent afficher les commentaires du présentateur sur l'écran principal interne et la présentation sur un projecteur externe.

Utiliser l'API Window Management

Problème

L'approche éprouvée du contrôle des fenêtres, Window.open(), est malheureusement sans tenir compte des écrans supplémentaires. Si certains aspects de cette API semblent un peu archaïques, comme son windowFeatures DOMString, il nous a néanmoins été utiles au fil des ans. Pour spécifier la taille position, vous pouvez transmettre la valeur comme left et top (ou screenX et screenY, respectivement), et transmettre les valeurs size en tant que width et height (ou innerWidth et innerHeight respectivement). Par exemple, pour ouvrir un une fenêtre de 400 × 300 à 50 pixels de la gauche et 50 pixels du haut, il s'agit du code que vous pourrait utiliser:

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

Vous pouvez obtenir des informations sur l'écran actuel en consultant les window.screen, qui renvoie un objet Screen. Il s'agit de la sortie sur mon 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
*/

Comme la plupart des personnes travaillant dans le secteur des technologies, j'ai dû m'adapter à la nouvelle réalité du travail et mettre en place votre bureau à domicile. Le mien ressemble sur la photo ci-dessous (si cela vous intéresse, vous pouvez lire le tous les détails de ma configuration). L'iPad situé à côté de mon MacBook est connecté à l'ordinateur portable via Sidecar. Ainsi, chaque fois que j'en ai besoin, je peux tourner le bouton un iPad en deuxième écran.

<ph type="x-smartling-placeholder">
</ph> Banc d&#39;école sur deux chaises. Au-dessus du banc de l&#39;école se trouvent des boîtes à chaussures sur lesquelles s&#39;appuient un ordinateur portable, entourée de deux iPads.
Une configuration multi-écran

Pour profiter d'un écran plus grand, je peux placer la fenêtre pop-up du exemple de code ci-dessus sur le deuxième écran. Je le fais comme ceci:

popup.moveTo(2500, 50);

Il s'agit d'une estimation approximative, car il n'y a aucun moyen de connaître les dimensions du deuxième écran. Les informations de window.screen ne couvre que l'écran intégré, mais pas l'écran de l'iPad. width signalé de l'écran intégré mesurait 1680 pixels. Passer à 2500 pixels pourrait peut-être déplacer la sur l'iPad, car je sait qu'il se trouve sur la droite de mon MacBook. Comment puis-je le faire dans le cas général ? En fait, il existe un meilleur moyen que de deviner. De cette façon, de l'API Window Management.

Détection de caractéristiques

Pour vérifier si l'API Window Management est compatible, utilisez:

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

L'autorisation window-management

Avant de pouvoir utiliser l'API de gestion des fenêtres, je dois demander à l'utilisateur l'autorisation de le faire. L'autorisation window-management peut être interrogée avec le API Permissions comme suit:

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

Lorsque des navigateurs avec l’ancien et le nouveau nom d’autorisation sont utilisés, veillez à utiliser du code défensif lorsque vous demandez l’autorisation, comme dans l’exemple ci-dessous.

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

Le navigateur peut choisir d'afficher l'invite d'autorisation de manière dynamique lors de la première tentative d'utilisation de l'une des méthodes de la nouvelle API. Pour en savoir plus, poursuivez votre lecture !

Propriété window.screen.isExtended

Pour savoir si plusieurs écrans sont connectés à mon appareil, j'accède à la window.screen.isExtended. Elle renvoie true ou false. Pour ma configuration, il renvoie true.

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

La méthode getScreenDetails()

Maintenant que je sais que la configuration actuelle est multi-écran, je peux obtenir plus d'informations sur la deuxième écran à l'aide de Window.getScreenDetails(). L'appel de cette fonction affichera une invite d'autorisation qui me demande si le site peut ouvrir et placer des fenêtres sur mon écran. La fonction renvoie une promesse qui est résolu avec un objet ScreenDetailed. Sur mon MacBook Pro 13 avec un iPad connecté, Cela inclut un champ screens avec deux objets ScreenDetailed:

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

Les informations sur les écrans connectés sont disponibles dans le tableau screens. Notez que la valeur left pour l'iPad commence à 1680, ce qui correspond exactement à la valeur width de l'écran intégré. Ce me permet de déterminer exactement comment les écrans sont disposés logiquement (ceux-ci, au-dessus les uns les autres, etc.). Des données sont maintenant disponibles pour chaque écran afin de savoir s'il s'agit d'un écran isInternal. et s'il s'agit d'un isPrimary. Notez que l'écran intégré n'est pas nécessairement l'écran principal.

Le champ currentScreen est un objet actif correspondant au window.screen actuel. L'objet est mis à jour en cas de modification de l'emplacement des fenêtres multi-écrans ou de l'appareil.

L'événement screenschange

La seule chose qui manque maintenant, c'est un moyen de détecter quand la configuration de mon écran change. Un nouvel événement, C'est exactement ce que fait screenschange: elle se déclenche chaque fois que le groupe d'écrans est modifié. (Avertissement qui "filtre" est au pluriel dans le nom de l'événement.) Cela signifie que l'événement se déclenche dès qu'un nouvel écran ou l'écran existant est branché ou débranché (physiquement ou virtuellement dans le cas d'un side-car).

Notez que vous devez rechercher les détails du nouvel écran de manière asynchrone. L'événement screenschange ne fournit pas ces données. Pour rechercher les détails de l'écran, utilisez l'objet actif d'un cache Screens.

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

L'événement currentscreenchange

Si je ne suis intéressé que par les modifications apportées à l'écran actuel (c'est-à-dire, la valeur de l'objet actif currentScreen), je peux écouter l'événement currentscreenchange.

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

L'événement change

Enfin, si je ne m'intéresse qu'aux modifications apportées à un écran concret, je peux écouter Événement change.

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

Nouvelles options plein écran

Jusqu'à présent, vous pouviez demander que les éléments s'affichent en mode plein écran via la commande requestFullScreen() . La méthode utilise un paramètre options que vous pouvez transmettre FullscreenOptions Jusqu’à présent, sa seule propriété a été navigationUI L'API Window Management ajoute une nouvelle propriété screen qui vous permet de déterminer sur l'écran sur lequel le mode plein écran doit s'afficher. Par exemple, si vous souhaitez que l'écran principal plein écran:

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

Il n'est pas possible d'émuler l'API Window Management, mais vous pouvez ajuster sa forme afin qu'elle vous pouvez coder exclusivement avec la nouvelle API:

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

Les autres aspects de l'API, à savoir les différents événements de changement d'écran et la propriété screen de FullscreenOptions, ne se déclencheraient jamais, et seront ignorés silencieusement respectivement par des navigateurs non compatibles.

Démo

Si vous êtes comme moi, vous devez surveiller de près le développement les cryptomonnaies. (Je ne le fais pas du tout parce que j'aime cette planète, mais pour les besoins de cet article, supposons simplement did.) Pour effectuer le suivi des cryptomonnaies que je possède, j'ai développé une application Web qui me permet regarder les marchés dans toutes les situations, par exemple confortablement assis au lit, où j'ai un bon configuration sur un seul écran.

<ph type="x-smartling-placeholder">
</ph> Immense écran de télévision au bout d&#39;un lit, avec les jambes de l&#39;auteur partiellement visibles. À l&#39;écran, on voit une fausse plate-forme d&#39;échange de cryptomonnaies.
Se détendre et observer les marchés

Concernant les cryptomonnaies, les marchés peuvent être agités à tout moment. Si cela se produit, je peux rapidement me déplacer vers mon bureau où j'ai une configuration multi-écran. Je peux cliquer sur la fenêtre de n'importe quelle devise et voir rapidement tous les détails en mode plein écran sur l'écran opposé. Vous trouverez ci-dessous une photo récente de prises lors du dernier battage de sang sur YCY. Ça m'a surpris complètement au dépourvu et m’a laissé avec les mains sur le visage.

<ph type="x-smartling-placeholder">
</ph> L&#39;auteur, les mains sur le visage paniqué, regarde le bureau de bourse de cryptomonnaies factices.
Panique, témoin du bain de sang sur YCY.

Vous pouvez jouer avec la démonstration intégrée ci-dessous ou consulter son code source en cas de glitch.

Sécurité et autorisations

L'équipe Chrome a conçu et implémenté l'API Window Management à l'aide des fonctionnalités définis dans l'article Contrôler l'accès à des fonctionnalités de plate-forme Web performantes, y compris le contrôle de l'utilisateur, la transparence et l'ergonomie. L'API Window Management expose de nouvelles informations sur les écrans connectés à un appareil, ce qui augmente la surface de fingerprinting des utilisateurs, en particulier ceux qui ont plusieurs écrans connectés en permanence à leurs appareils. Comme un seul atténué ce problème de confidentialité, les propriétés de l'écran exposé sont limitées au minimum requis pour les cas d'utilisation d'emplacement courants. L'autorisation de l'utilisateur est requise pour que les sites puissent passer en mode multi-écran des informations et placer des fenêtres sur d’autres écrans. Alors que Chromium renvoie des libellés d'écran détaillés, les navigateurs sont libres de renvoyer des libellés moins descriptifs (voire des libellés vides).

Contrôle des utilisateurs

L'utilisateur contrôle entièrement l'exposition de sa configuration. Il peut accepter ou refuser les demande d'autorisation et révoquez une autorisation précédemment accordée via la fonctionnalité d'informations sur le site dans le navigateur.

Contrôle à l'échelle de l'entreprise

Les utilisateurs de Chrome Enterprise peuvent contrôler plusieurs aspects de l'API Window Management comme décrits dans la section correspondante du Groupes de règles atomiques paramètres.

Transparence

L'autorisation d'utiliser l'API Window Management a ou non été accordée exposé dans les informations du site du navigateur et peut également être interrogé via l'API Permissions.

Persistance des autorisations

Le navigateur conserve les autorisations accordées. L'autorisation peut être révoquée via le site du navigateur des informations.

Commentaires

L'équipe Chrome souhaite en savoir plus sur votre expérience avec l'API Window Management.

Présentez-nous la conception de l'API

Y a-t-il un aspect de l'API qui ne fonctionne pas comme prévu ? Ou manque-t-il des méthodes ou les propriétés dont vous avez besoin pour mettre en œuvre votre idée ? Vous avez une question ou un commentaire sur la sécurité ?

  • Signalez un problème de spécification dans le dépôt GitHub correspondant ou ajoutez vos commentaires à un problème.

Signaler un problème d'implémentation

Avez-vous détecté un bug dans l'implémentation de Chrome ? Ou l'implémentation est-elle différente des spécifications ?

  • Signalez un bug sur new.crbug.com. Assurez-vous d'inclure autant de détails que vous le code, des instructions simples pour le reproduire et saisissez Blink>Screen>MultiScreen dans Composants. Glitch est idéal pour partager des répétitions rapidement et facilement.

Apportez votre soutien à l'API

Prévoyez-vous d'utiliser l'API de gestion des fenêtres ? Votre assistance publique permet au Chrome de priorisation des fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.

Liens utiles

Remerciements

La spécification de l'API de gestion des fenêtres a été modifiée par Victor Costan, Joshua Bell et Mike Wasserman L'API a été implémentée par Mike Wasserman et Adrienne Walker. Cet article a été examiné par Joe Medley, François Beaufort, et des Kayces basques. Merci à Laura Torrent Puig pour ces photos.