Obtenez des informations sur les écrans connectés et positionnez les fenêtres par rapport à ces écrans.
Publié le 14 septembre 2020
API Window Management
L'API Window Management vous permet de lister les écrans connectés à votre machine et de placer des fenêtres sur des écrans spécifiques.
Cas d'utilisation suggérés
Voici quelques exemples de sites pouvant utiliser cette API :
- Les éditeurs graphiques multifenêtres tels que Gimp peuvent placer divers outils d'édition dans des fenêtres positionnées avec précision.
- Les bureaux de trading virtuels peuvent afficher les tendances du marché dans plusieurs fenêtres, dont l'une peut être affichée en mode plein écran.
- Les applications de diaporama peuvent afficher les notes du présentateur sur l'écran principal interne et la présentation sur un projecteur externe.
Utiliser l'API Window Management
L'approche éprouvée pour contrôler les fenêtres, Window.open(), ne tient malheureusement pas compte des écrans supplémentaires. Bien que certains aspects de cette API semblent un peu archaïques, comme son paramètre DOMString windowFeatures, elle nous a néanmoins bien servi au fil des ans. Pour spécifier la position d'une fenêtre, vous pouvez transmettre les coordonnées sous la forme left et top (ou screenX et screenY respectivement), et transmettre la taille souhaitée sous la forme width et height (ou innerWidth et innerHeight respectivement). Par exemple, pour ouvrir une fenêtre de 400 x 300 à 50 pixels de la gauche et 50 pixels du haut, vous pouvez utiliser le code suivant :
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 examinant la propriété window.screen, qui renvoie un objet Screen. Voici le résultat 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 de la technologie, j'ai dû m'adapter à la réalité du travail en 2020 et aménager mon bureau personnel à la maison. La mienne ressemble à celle de la photo (si cela vous intéresse, vous pouvez lire tous les détails sur ma configuration). L'iPad à côté de mon MacBook est connecté à l'ordinateur portable via Sidecar. Je peux donc rapidement transformer l'iPad en deuxième écran quand j'en ai besoin.
Si je veux profiter du grand écran, je peux placer le pop-up de l'exemple de code sur le deuxième écran. Voici comment je procède :
popup.moveTo(2500, 50);
Il s'agit d'une estimation approximative, car il n'existe aucun moyen de connaître les dimensions du deuxième écran. Les informations de window.screen ne couvrent que l'écran intégré, mais pas l'écran de l'iPad. La width signalée de l'écran intégré était de 1680 pixels. Passer à 2500 pixels pourrait permettre de déplacer la fenêtre vers l'iPad, car je sais qu'elle se trouve à droite de mon MacBook. Comment puis-je faire cela dans le cas général ? Il existe une meilleure solution que la devinette. Il s'agit de l'API Window Management.
Détection de fonctionnalités
Pour vérifier si l'API Window Management est compatible, utilisez :
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
Autorisation window-management
Avant de pouvoir utiliser l'API Window Management, je dois demander l'autorisation à l'utilisateur.
L'autorisation window-management peut être demandée avec l'API Permissions comme suit :
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-management' });
granted = state === 'granted';
} catch {
// Nothing.
}
Tant que des navigateurs utilisant l'ancien et le nouveau nom d'autorisation sont utilisés, veillez à utiliser un code défensif lorsque vous demandez l'autorisation, comme dans l'exemple.
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 propriété window.screen.isExtended. Elle renvoie true ou false. Pour ma configuration, elle 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 le deuxième écran à l'aide de Window.getScreenDetails(). L'appel de cette fonction affiche une invite d'autorisation me demandant si le site peut ouvrir et placer des fenêtres sur mon écran. La fonction renvoie une promesse qui se résout 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
}]
}
*/
Des informations sur les écrans connectés sont disponibles dans le tableau screens. Notez que la valeur de left pour l'iPad commence à 1680, ce qui correspond exactement à la width de l'écran intégré. Cela me permet de déterminer exactement comment les écrans sont disposés de manière logique (les uns à côté des autres, les uns au-dessus des autres, etc.). Des données sont également disponibles pour chaque écran afin d'indiquer s'il s'agit d'un écran isInternal ou isPrimary. Notez que l'écran intégré n'est pas nécessairement l'écran principal.
Le champ currentScreen est un objet actif correspondant à la window.screen actuelle. L'objet est mis à jour lors des placements de fenêtres multi-écrans ou des changements d'appareil.
Événement screenschange
Il ne manque plus qu'un moyen de détecter quand la configuration de mon écran change. Un nouvel événement, screenschange, fait exactement cela : il se déclenche chaque fois que la constellation d'écrans est modifiée. (Notez que "screens" est au pluriel dans le nom de l'événement.) Cela signifie que l'événement se déclenche chaque fois qu'un nouvel écran ou un écran existant est branché ou débranché (physiquement ou virtuellement dans le cas de Sidecar).
Vous devez rechercher les détails du nouvel écran de manière asynchrone. L'événement screenschange lui-même ne fournit pas ces données. Pour rechercher les détails de l'écran, utilisez l'objet actif à partir d'une interface Screens mise en cache.
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;
}
});
É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);
});
Événement change
Enfin, si je ne suis intéressé que par les modifications apportées à un écran spécifique, je peux écouter l'événement change de cet écran.
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 à ce que des éléments s'affichent en mode plein écran à l'aide de la méthode requestFullScreen(). La méthode utilise un paramètre options dans lequel vous pouvez transmettre FullscreenOptions. Jusqu'à présent, sa seule propriété était navigationUI.
L'API Window Management ajoute une nouvelle propriété screen qui vous permet de déterminer sur quel écran démarrer la vue plein écran. Par exemple, si vous souhaitez afficher l'écran principal en 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 de polyfill l'API Window Management, mais vous pouvez shimer sa forme afin de coder exclusivement sur la nouvelle API :
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;
}
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 ou seraient ignorés silencieusement par les navigateurs non compatibles.
Démo
Si vous suivez de près le développement des différentes crypto-monnaies, vous pouvez surveiller les marchés depuis le confort de votre lit avec une configuration à un seul écran dans mon application. (Je ne le fais pas du tout, car j'aime cette planète, mais pour les besoins de cet article, supposons que je l'ai fait.)
Comme il s'agit de crypto, les marchés peuvent devenir agités à tout moment. Si cela se produit, je peux rapidement me rendre à mon bureau, où j'ai une configuration multi-écrans. Je peux cliquer sur la fenêtre d'une devise et voir rapidement tous les détails en plein écran sur l'écran opposé. Voici une photo récente de moi prise lors du dernier bain de sang YCY. J'ai été complètement pris au dépourvu et je me suis retrouvé les mains sur le visage.
Testez la démonstration ou consultez son code source sur GitHub.
Sécurité et autorisations
L'équipe Chrome a conçu et implémenté l'API Window Management en utilisant les principes de base définis dans Controlling Access to Powerful Web Platform Features, y compris le contrôle 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 d'empreinte numérique des utilisateurs, en particulier ceux qui ont plusieurs écrans constamment connectés à leurs appareils. Pour atténuer ce problème de confidentialité, les propriétés d'écran exposées sont limitées au minimum requis pour les cas d'utilisation courants de placement.
L'autorisation de l'utilisateur est requise pour que les sites obtiennent des informations multi-écrans et placent 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 vides).
Contrôle des utilisateurs
L'utilisateur contrôle entièrement l'exposition de sa configuration. Ils peuvent accepter ou refuser l'invite d'autorisation, et révoquer une autorisation précédemment accordée via la fonctionnalité d'informations sur le site dans le navigateur.
Contrôle de l'entreprise
Les utilisateurs de Chrome Enterprise peuvent contrôler plusieurs aspects de l'API Window Management, comme indiqué dans la section correspondante des paramètres des groupes de règles atomiques.
Transparence
Le fait que l'autorisation d'utiliser l'API Window Management ait été accordée ou non est indiqué dans les informations sur le site du navigateur et peut également être interrogé avec l'API Permissions.
Persistance des autorisations
Le navigateur conserve les autorisations accordées. L'autorisation peut être révoquée via les informations sur le site du navigateur.
Commentaires
Y a-t-il quelque chose dans l'API qui ne fonctionne pas comme prévu ? Ou bien manque-t-il des méthodes ou des propriétés dont vous avez besoin pour implémenter votre idée ? Vous avez une question ou un commentaire sur le modèle de sécurité ?
- Signalez un problème de spécification dans le dépôt GitHub correspondant ou ajoutez vos commentaires à un problème existant.
- Signaler un bug concernant l'implémentation de Chrome Veillez à inclure autant de détails que possible, ainsi que les instructions pour reproduire le problème, et saisissez
Blink>Screen>MultiScreendans la zone Composants.
Soutenir l'API
Comptez-vous utiliser l'API Window Management ? Votre soutien public aide l'équipe Chrome à hiérarchiser les fonctionnalités et montre aux autres fournisseurs de navigateurs à quel point il est essentiel de les prendre en charge.
- Expliquez comment vous prévoyez de l'utiliser dans le fil de discussion WICG.
- Envoyez un tweet à @ChromiumDev avec le hashtag
#WindowManagementpour nous indiquer où et comment vous l'utilisez. - Demandez à d'autres fournisseurs de navigateurs d'implémenter l'API.
Ressources
- Brouillon de spécification
- Explication publique
- Démonstration de l'API Window Management | Source de la démonstration de l'API Window Management
- Bug de suivi Chromium
- Entrée ChromeStatus.com
- Composant Blink :
Blink>Screen>MultiScreen - Examen du TAG
- Intention de tester
Remerciements
Les spécifications de l'API Window Management ont été modifiées 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 Kayce Basques. Merci à Laura Torrent Puig pour les photos.