Receber informações sobre telas conectadas e posicionar janelas em relação a elas.
API Window Management
A API Window Management permite enumerar as telas conectadas à sua máquina e colocar janelas em telas específicas.
Casos de uso sugeridos
Exemplos de sites que podem usar essa API:
- Editores gráficos com várias janelas, como o Gimp, podem colocar várias ferramentas de edição em janelas posicionadas com precisão.
- As mesas de negociação virtuais podem mostrar tendências de mercado em várias janelas, e qualquer uma delas pode ser visualizada em modo de tela cheia.
- Os apps de apresentação de slides podem mostrar as anotações do apresentador na tela principal interna e a apresentação em um projetor externo.
Como usar a API Window Management
O problema
A abordagem testada para controlar janelas, Window.open()
, infelizmente não reconhece telas adicionais. Embora alguns aspectos dessa API pareçam um pouco arcaicos, como o parâmetro windowFeatures
DOMString
, ela nos atendeu bem ao longo dos anos. Para especificar a posição de uma janela, transmita as coordenadas como left
e top
(ou screenX
e screenY
, respectivamente) e o tamanho desejado como width
e height
(ou innerWidth
e innerHeight
, respectivamente). Por exemplo, para abrir uma janela de 400 × 300 a 50 pixels da esquerda e 50 pixels da parte de cima, use este código:
const popup = window.open(
'https://example.com/',
'My Popup',
'left=50,top=50,width=400,height=300',
);
Para saber mais sobre a tela atual, consulte a propriedade
window.screen
, que
retorna um objeto Screen
. Esta é a saída no meu MacBook Pro de 13 polegadas:
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
*/
Como a maioria das pessoas que trabalham com tecnologia, precisei me adaptar à nova realidade do trabalho e montar meu escritório em casa. O meu é como o da foto abaixo. Se quiser, leia os detalhes completos sobre minha configuração. O iPad ao lado do meu MacBook está conectado ao notebook via Sidecar. Assim, sempre que preciso, posso transformar rapidamente o iPad em uma segunda tela.

Se eu quiser aproveitar a tela maior, posso colocar o pop-up da amostra de código acima na segunda tela. Faço assim:
popup.moveTo(2500, 50);
Essa é uma estimativa aproximada, já que não há como saber as dimensões da segunda tela. As informações de window.screen
abrangem apenas a tela integrada, e não a do iPad. A width
informada da tela integrada era de 1680
pixels. Portanto, passar para 2500
pixels pode funcionar para mover a janela para o iPad, já que eu sei que ele está localizado à direita do meu MacBook. Como posso fazer isso no caso geral? Acontece que existe uma maneira melhor do que adivinhar. Essa maneira é a
API Window Management.
Detecção de recursos
Para verificar se a API Window Management é compatível, use:
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
A permissão window-management
Antes de usar a API Window Management, preciso pedir permissão ao usuário para fazer isso.
A permissão window-management
pode ser consultada com a
API Permissions da seguinte maneira:
let granted = false;
try {
const { state } = await navigator.permissions.query({ name: 'window-management' });
granted = state === 'granted';
} catch {
// Nothing.
}
Enquanto navegadores com o nome de permissão antigo e novo estiverem em uso, use código de defesa ao solicitar permissão, como no exemplo abaixo.
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;
});
O navegador pode mostrar a solicitação de permissão de forma dinâmica na primeira tentativa de usar qualquer um dos métodos da nova API. Continue lendo para saber mais.
A propriedade window.screen.isExtended
Para saber se mais de uma tela está conectada ao meu dispositivo, acesso a propriedade
window.screen.isExtended
. Ele retorna true
ou false
. Para minha configuração, ela retorna true
.
window.screen.isExtended;
// Returns `true` or `false`.
O método getScreenDetails()
Agora que sei que a configuração atual é de várias telas, posso obter mais informações sobre a
segunda tela usando Window.getScreenDetails()
. Ao chamar essa função, uma solicitação de permissão será mostrada, perguntando se o site pode abrir e posicionar janelas na minha tela. A função retorna uma promessa
que é resolvida com um objeto ScreenDetailed
. No meu MacBook Pro 13 com um iPad conectado, isso inclui um campo screens
com dois objetos 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
}]
}
*/
As informações sobre as telas conectadas estão disponíveis na matriz screens
. Observe como o valor de left
para o iPad começa em 1680
, que é exatamente o width
da tela integrada. Isso me permite determinar exatamente como as telas são organizadas logicamente (uma ao lado da outra, uma em cima da outra etc.). Agora também há dados para cada tela que mostram se ela é isInternal
e se é isPrimary
. A tela integrada não é necessariamente a tela principal.
O campo currentScreen
é um objeto ativo correspondente ao window.screen
atual. O objeto é atualizado em posicionamentos de janela entre telas ou mudanças de dispositivo.
O evento screenschange
A única coisa que falta agora é uma maneira de detectar quando a configuração da tela muda. Um novo evento, screenschange
, faz exatamente isso: ele é disparado sempre que a constelação de tela é modificada. Observe que "screens" está no plural no nome do evento. Isso significa que o evento é acionado sempre que uma nova tela ou uma
tela existente é conectada ou desconectada (fisicamente ou virtualmente no caso do Sidecar).
É necessário pesquisar os detalhes da nova tela de forma assíncrona. O evento screenschange
não fornece esses dados. Para consultar os detalhes da tela, use o objeto ativo de uma interface Screens
em 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;
}
});
O evento currentscreenchange
Se eu estiver interessado apenas em mudanças na tela atual (ou seja, o valor do objeto ativo
currentScreen
), posso detectar o evento currentscreenchange
.
const screenDetails = await window.getScreenDetails();
screenDetails.addEventListener('currentscreenchange', async (event) => {
const details = screenDetails.currentScreen;
console.log('The current screen has changed.', event, details);
});
O evento change
Por fim, se eu tiver interesse apenas em mudanças em uma tela específica, posso detectar o evento
change
dessa tela.
const firstScreen = (await window.getScreenDetails())[0];
firstScreen.addEventListener('change', async (event) => {
console.log('The first screen has changed.', event, firstScreen);
});
Novas opções de tela cheia
Até agora, era possível solicitar que os elementos fossem exibidos no modo tela cheia usando o método
requestFullScreen()
com nome apropriado. O método usa um parâmetro options
em que é possível transmitir
FullscreenOptions
. Até agora, a única propriedade foi navigationUI
.
A API Window Management adiciona uma nova propriedade screen
que permite determinar
em qual tela iniciar a visualização em tela cheia. Por exemplo, se você quiser colocar a tela principal em tela cheia:
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
Não é possível fazer polyfill da API Window Management, mas você pode fazer shim da forma dela para codificar exclusivamente na nova 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;
}
Os outros aspectos da API, ou seja, os vários eventos de mudança de tela e a propriedade screen
do FullscreenOptions
, nunca seriam disparados ou seriam ignorados silenciosamente pelos navegadores não compatíveis.
Demonstração
Se você é como eu, acompanha de perto o desenvolvimento das várias criptomoedas. Na realidade, eu não quero isso porque amo este planeta, mas, para fins deste artigo, vamos fingir que sim. Para acompanhar as criptomoedas que tenho, desenvolvi um app da Web que me permite acompanhar os mercados em todas as situações da vida, como no conforto da minha cama, onde tenho uma configuração de tela única decente.

Como se trata de criptomoedas, os mercados podem ficar agitados a qualquer momento. Se isso acontecer, posso rapidamente ir para minha mesa, onde tenho uma configuração de várias telas. Posso clicar na janela de qualquer moeda e ver rapidamente todos os detalhes em uma visualização de tela cheia na tela oposta. Abaixo está uma foto minha tirada durante o último banho de sangue do YCY. Me pegou totalmente desprevenido e me deixou com as mãos no rosto.

Você pode testar a demonstração incorporada abaixo ou conferir o código-fonte no GitHub.
Segurança e permissões
A equipe do Chrome projetou e implementou a API Window Management usando os princípios básicos definidos em Controlling Access to Powerful Web Platform Features (em inglês), incluindo controle do usuário, transparência e ergonomia. A API Window Management expõe novas informações sobre as telas conectadas a um dispositivo, aumentando a superfície de impressão digital dos usuários, especialmente aqueles com várias telas conectadas aos dispositivos. Como uma mitigação dessa questão de privacidade, as propriedades de tela expostas são limitadas ao mínimo necessário para casos de uso comuns de posicionamento. É necessária a permissão do usuário para que os sites recebam informações de multitelas e posicionem janelas em outras telas. Embora o Chromium retorne rótulos de tela detalhados, os navegadores podem retornar rótulos menos descritivos ou até mesmo vazios.
Controle do usuário
O usuário tem controle total sobre a exposição da configuração. Eles podem aceitar ou recusar a solicitação de permissão e revogar uma permissão concedida anteriormente usando o recurso de informações do site no navegador.
Controle empresarial
Os usuários do Chrome Enterprise podem controlar vários aspectos da API Window Management, conforme descrito na seção relevante das configurações de Grupos de políticas atômicas.
Transparência
O fato de a permissão para usar a API Window Management ter sido concedida é exposto nas informações do site do navegador e também pode ser consultado pela API Permissions.
Permanência de permissões
O navegador mantém as concessões de permissão. A permissão pode ser revogada nas informações do site do navegador.
Feedback
A equipe do Chrome quer saber sobre suas experiências com a API Window Management.
Fale sobre o design da API
Há algo na API que não funciona como esperado? Ou há métodos ou propriedades ausentes que você precisa implementar sua ideia? Tem uma dúvida ou um comentário sobre o modelo de segurança?
- Registre um problema de especificação no repositório do GitHub correspondente ou adicione suas ideias a um problema existente.
Informar um problema com a implementação
Você encontrou um bug na implementação do Chrome? Ou a implementação é diferente da especificação?
- Registre um bug em new.crbug.com. Inclua o máximo de detalhes possível, instruções simples para reprodução e insira
Blink>Screen>MultiScreen
na caixa Componentes.
Mostrar suporte para a API
Você planeja usar a API Window Management? Seu apoio público ajuda a equipe do Chrome a priorizar recursos e mostra a outros fornecedores de navegadores a importância de oferecer suporte a eles.
- Compartilhe como você planeja usar esse recurso na thread do WICG Discourse (em inglês).
- Envie um tweet para @ChromiumDev usando a hashtag
#WindowManagement
e informe onde e como você está usando. - Peça a outros fornecedores de navegadores para implementar a API.
Links úteis
- Rascunho de especificação
- Explicação para o público
- Demonstração da API Window Management | Fonte da demonstração da API Window Management
- Bug de rastreamento do Chromium
- Entrada do ChromeStatus.com
- Componente Blink:
Blink>Screen>MultiScreen
- Revisão da TAG
- Intenção de experimentar
Agradecimentos
A especificação da API Window Management foi editada por Victor Costan, Joshua Bell e Mike Wasserman. A API foi implementada por Mike Wasserman e Adrienne Walker. Este artigo foi revisado por Joe Medley, François Beaufort e Kayce Basques. Agradecemos a Laura Torrent Puig pelas fotos.