Como gerenciar várias telas com a API Window Management

Receba informações sobre telas conectadas e posicione janelas em relação a essas telas.

API Window Management

Com a API Window Management, você pode enumerar as telas conectadas à sua máquina. e posicionar janelas em telas específicas.

Casos de uso sugeridos

Exemplos de sites que podem usar essa API incluem:

  • Editores gráficos de várias janelas à la O Gimp pode colocar vários ferramentas de edição em janelas posicionadas com precisão.
  • As mesas de operações virtuais podem mostrar tendências de mercado em várias janelas, e qualquer uma delas pode ser visualizada em modo de tela cheia.
  • Os aplicativos de apresentação de slides podem mostrar as anotações do apresentador na tela principal interna e na apresentação em um projetor externo.

Como usar a API Window Management

O problema

A abordagem testada para controlar janelas, Window.open(), não conhece outras telas. Embora alguns aspectos dessa API pareçam um pouco arcaicos, como a windowFeatures DOMString, ele nos ajudou muito ao longo dos anos. Para especificar o tamanho position, será possível transmitir o coordenadas como left e top (ou screenX e screenY, respectivamente) e transmita as coordenadas tamanho como width e height (ou innerWidth e innerHeight, respectivamente). Por exemplo, para abrir uma janela de 400×300 a 50 pixels da esquerda e a 50 pixels do topo. Esse é o código poderia usar:

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

Para mais informações sobre a tela atual, consulte o propriedade window.screen, que retorna um objeto Screen. Esta é a saída no meu 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
*/

Como a maioria das pessoas que trabalham com tecnologia, tive que me adaptar à nova realidade do trabalho e me preparar home office pessoal. O meu aparece na foto abaixo (se tiver interesse, leia todos os detalhes sobre minha configuração). O iPad ao lado do MacBook está conectado ao laptop via Sidecar para que, sempre que eu precisar, eu possa ativar rapidamente o o iPad em uma segunda tela.

Banco em duas cadeiras. Em cima do banco da escola estão caixas de sapatos que apoiam um laptop e dois iPads ao redor.
Uma configuração para várias telas.

Se eu quiser aproveitar a tela maior, posso colocar o pop-up o exemplo de código acima para a segunda tela. Eu faço isso assim:

popup.moveTo(2500, 50);

Este é um palpite, já que não há como saber as dimensões da segunda tela. Informações do window.screen cobre apenas a tela integrada, mas não a do iPad. width denunciado da tela integrada era de 1680 pixels, então mover para 2500 pixels pode funcionar para mudar a para o iPad, já que eu sei que ele está localizado à direita do meu MacBook. Como posso fazer isso no caso geral? Acontece que há uma maneira melhor do que adivinhar. Dessa forma, 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. A permissão window-management pode ser consultada com o API Permissions da seguinte forma:

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

Enquanto os navegadores com o nome de permissão antigo e novo estiverem em uso, não deixe de usar o 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 optar por mostrar a solicitação de permissão de forma dinâmica na primeira tentativa de usar qualquer um dos métodos de a nova API. Continue lendo para saber mais.

A propriedade window.screen.isExtended

Para descobrir se mais de uma tela está conectada ao meu dispositivo, acesso o window.screen.isExtended. Ele retorna true ou false. Para minha configuração, ele retorna true.

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

Método getScreenDetails()

Agora que sei que a configuração atual é para várias telas, posso obter mais informações sobre a segunda tela usando Window.getScreenDetails(). Chamar esta função mostrará uma solicitação de permissão que me pergunta se o site pode abrir e colocar janelas na minha tela. A função retorna uma promessa que é resolvido 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 O left para iPad começa em 1680, que é exatamente o width da tela integrada. Isso me permite determinar exatamente como as telas são organizadas de maneira lógica (próximas umas das outras, em cima entre si etc.). Agora, também existem dados para que cada tela mostre se é isInternal e se é do tipo isPrimary. A tela integrada não é necessariamente a tela principal.

O campo currentScreen é um objeto ativo correspondente ao window.screen atual. O objeto é atualizada nas posições de janela entre telas ou em alterações no dispositivo.

O evento screenschange

A única coisa que falta agora é uma forma de detectar quando a configuração da minha tela muda. Um novo evento, screenschange faz exatamente isso: dispara sempre que a constelação de telas é modificada. (Aviso que "tela" é plural no nome do evento.) Isso significa que o evento é disparado sempre que uma nova tela ou um a tela existente está (física ou virtualmente, no caso do arquivo secundário) conectada ou desconectada.

É necessário pesquisar os detalhes da nova tela de forma assíncrona, o evento screenschange. em si não fornece esses dados. Para procurar os detalhes da tela, use o objeto ativo de um cache interface 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;
  }
});

O evento currentscreenchange

Se eu só tiver interesse nas alterações da tela atual (ou seja, o valor do objeto ativo currentScreen), posso escutar 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 só estiver interessado nas alterações de uma tela concreta, posso ouvir o change.

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, você poderia solicitar que os elementos fossem exibidos em modo de tela cheia por meio do comando requestFullScreen() . O método usa um parâmetro options em que você pode transmitir FullscreenOptions. Até aqui, sua ú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 tornar a tela principal 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 aplicar o polyfill à API Window Management, mas é possível corrigir a forma dela para é possível codificar exclusivamente para a 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;
}

Outros aspectos da API, ou seja, os vários eventos de mudança de tela e a propriedade screen de o FullscreenOptions simplesmente nunca seria acionado ou seria ignorado silenciosamente pelo método, respectivamente. navegadores não compatíveis.

Demonstração

Se você é como eu, pode acompanhar de perto o desenvolvimento das várias criptomoedas. Na verdade, eu não gosto muito desse planeta, mas para fins deste artigo, presumimos que did.) Para acompanhar as criptomoedas que tenho, desenvolvi um app da Web que permite ver as feiras livres em todas as situações da vida, como no conforto da minha cama, onde tenho uma boa configuração de tela única.

Tela de TV grande no final de uma cama com as pernas da autora parcialmente visíveis. Na tela, uma mesa de câmbio de criptomoedas falsa.
Relaxando e acompanhando os mercados.

Por falar nisso, os mercados podem ficar agitados a qualquer momento. Caso isso aconteça, posso rapidamente vou para minha mesa, onde tenho uma configuração multitelas. posso clicar na janela de qualquer moeda e rapidamente todos os detalhes em uma visualização em tela cheia na tela oposta. Abaixo está uma foto recente de que eu tomei durante o último Banho de sangue de YCY. Isso me pegou de surpresa e me deixou com as mãos no rosto.

O autor com as mãos no rosto em pânico olhando para a mesa de operações de criptomoedas falsas.
Panicky, testemunhando o sangue YCY.

Você pode testar a demonstração incorporada abaixo ou conferir o código-fonte dela no glitch.

Segurança e permissões

A equipe do Chrome projetou e implementou a API Window Management usando os principais definidos em Como controlar o acesso a recursos avançados da Web Platform, 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 usuários, especialmente aqueles com várias telas consistentemente conectadas a seus dispositivos. Como um só e minimização desse problema de privacidade, as propriedades de tela expostas são limitadas ao mínimo necessário para casos de uso comuns de posicionamento. A permissão do usuário é necessária para que os sites acessem várias telas informações e posicionar janelas em outras telas. Enquanto o Chromium retorna rótulos de tela detalhados, os navegadores podem retornar menos descrições (ou até mesmo marcadores vazios).

Controle do usuário

O usuário tem controle total da exposição da configuração. É possível aceitar ou recusar solicitação de permissão e revogar uma permissão concedida anteriormente por meio do recurso de informações do site em no navegador.

Controle empresarial

Os usuários do Chrome Enterprise podem controlar vários aspectos da API Window Management, como descritos na seção relevante da Grupos de políticas atômicas configurações.

Transparência

O fato de a permissão para usar a API Window Management ter sido concedida é expostas nas informações do site do navegador e também pode ser consultada por meio da API Permissions.

Persistência da permissão

O navegador mantém as concessões de permissão. A permissão pode ser revogada no site do navegador informações imprecisas ou inadequadas.

Feedback

A equipe do Chrome quer saber mais sobre suas experiências com a API Window Management.

Fale sobre o design da API

Existe algo na API que não funciona como você esperava? Ou há métodos faltando ou propriedades de que precisa para implementar sua ideia? Tem uma pergunta ou comentário sobre a segurança modelo?

  • Registre um problema de especificação no repositório do GitHub correspondente ou adicione sua opinião a um problema.

Informar um problema com a implementação

Você encontrou um bug na implementação do Chrome? Ou a implementação é diferente das especificações?

  • Registre um bug em new.crbug.com. Não deixe de incluir o máximo de detalhes instruções simples para reprodução e digite Blink>Screen>MultiScreen no Componentes. O Glitch é ótimo para compartilhar repetições rápidas e fáceis.

Mostrar suporte à API

Você planeja usar a API Window Management? Seu apoio público ajuda o Chrome para priorizar recursos e mostrar a outros fornecedores de navegadores como é essencial oferecer suporte a eles.

  • Compartilhe como você planeja usá-la na conversa sobre a WCG (em inglês).
  • Envie um tweet para @ChromiumDev usando a hashtag #WindowManagement e informe onde e como você o utiliza.
  • Peça a outros fornecedores de navegadores para implementar a API.

Links úteis

Agradecimentos

A especificação da API Window Management foi editada por Victor Costan, Joshua Bell e Mike Wasserman. A API foi implementada pela Mike Wasserman e Adrienne Walker. Este artigo foi revisado por Joe Medley, François Beaufort, e Kayce Basques. Obrigada a Laura Torrent Puig pelas fotos.