Administra varias pantallas con la API de Window Management

Obtén información sobre las pantallas conectadas y la posición de las ventanas en relación con esas pantallas.

API de Window Management

La API de Window Management te permite enumerar las pantallas conectadas a tu máquina y colocar ventanas en pantallas específicas.

Casos de uso sugeridos

Estos son algunos ejemplos de sitios que pueden usar esta API:

  • Editores gráficos multiventana Gimp puede colocar varias de edición de texto en ventanas precisas.
  • Las mesas de operaciones virtuales pueden mostrar las tendencias del mercado en múltiples ventanas, cualquiera de las cuales puede verse en modo de pantalla completa.
  • Las aplicaciones de presentación de diapositivas pueden mostrar notas del orador en la pantalla principal interna y la presentación en un proyector externo.

Cómo usar la API de Window Management

El problema

El enfoque antiguo para el control de ventanas Window.open(), desafortunadamente no sea consciente de las pantallas adicionales. Si bien algunos aspectos de esta API parecen un poco arcaicos, como su windowFeatures DOMString, nos ha funcionado bien a lo largo de los años. Para especificar la configuración position, puedes pasar el coordenadas como left y top (o screenX y screenY respectivamente) y pasa la cantidad deseada tamaño como width y height (o innerWidth y innerHeight, respectivamente). Por ejemplo, para abrir una una ventana de 400 × 300 a 50 píxeles desde la izquierda y 50 píxeles desde la parte superior. Este es el código que podría usar:

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

Puedes obtener información sobre la pantalla actual en la window.screen, que muestra un objeto Screen. Este es el de salida en mi MacBook Pro de 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
*/

Al igual que la mayoría de las personas que trabajan en el área de tecnología, tuve que adaptarme a la nueva realidad laboral y preparar mi oficina en casa. El mío se ve en la siguiente foto (si te interesa, puedes leer la todos los detalles de mi configuración). El iPad junto a mi MacBook está conectado a la laptop mediante Sidecar, para que siempre que lo necesite, puedo en una segunda pantalla.

Banco escolar sobre dos sillas. Encima de los bancos de la escuela hay cajas de zapatos que sostienen una laptop y dos iPads a su alrededor.
Una configuración multipantalla.

Si quiero aprovechar la pantalla más grande, puedo colocar la ventana emergente muestra de código anterior en la segunda pantalla. Listo así:

popup.moveTo(2500, 50);

Esta es una suposición aproximada, ya que no hay forma de conocer las dimensiones de la segunda pantalla. La información de window.screen solo cubre la pantalla integrada, pero no la del iPad. El width informado de la pantalla integrada era de 1680 píxeles, por lo que mover a 2500 píxeles podría cambiar la al iPad, ya que s sé que está ubicada a la derecha de mi MacBook. Cómo ¿puedo hacer esto en general? Resulta que hay una mejor manera que adivinar. De esa manera, se crea API de Window Management

Detección de funciones

Para verificar si se admite la API de Window Management, usa lo siguiente:

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

El permiso window-management

Antes de poder usar la API de Window Management, debo solicitar permiso al usuario para hacerlo. El permiso window-management se puede consultar con el API de Permissions de la siguiente manera:

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

Mientras se usan los navegadores con el nombre de permiso anterior y el nuevo, asegúrate de usar código defensivo al solicitar permiso, como se muestra en el siguiente ejemplo.

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

El navegador puede elige mostrar la solicitud de permiso dinámicamente en el primer intento de usar cualquiera de los métodos de la nueva API. Sigue leyendo para obtener más información.

La propiedad window.screen.isExtended

Para saber si hay más de una pantalla conectada a mi dispositivo, accedo al window.screen.isExtended. Muestra true o false. En mi configuración, muestra true.

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

El método getScreenDetails()

Ahora que sé que la configuración actual es multipantalla, puedo obtener más información sobre las segunda pantalla con Window.getScreenDetails(). Si llamas a esta función, se mostrará un mensaje de permiso que me pregunta si el sitio puede abrirse y colocar ventanas en mi pantalla. La función muestra una promesa que se resuelve con un objeto ScreenDetailed. En mi MacBook Pro 13 con un iPad conectado, Esto incluye un campo screens con dos 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
  }]
}
*/

La información sobre las pantallas conectadas está disponible en el array screens. Ten en cuenta cómo el valor de El valor de left para iPad comienza en 1680, que es exactamente el width de la pantalla integrada. Esta me permite determinar exactamente cómo las pantallas están organizadas lógicamente (una al lado de la otra, por encima de entre sí, etcétera). Ahora también hay datos para cada pantalla que muestran si es de tipo isInternal y si es isPrimary. Ten en cuenta que la pantalla integrada no es necesariamente la pantalla principal.

El campo currentScreen es un objeto activo que corresponde al window.screen actual. El objeto se actualiza en posiciones de ventanas en varias pantallas o cambios en los dispositivos.

El evento screenschange

Lo único que falta ahora es una forma de detectar cuándo cambia la configuración de la pantalla. Un evento nuevo, screenschange hace exactamente eso: se activa cada vez que se modifica la constelación de pantalla. (Aviso que las "pantallas" está en plural en el nombre del evento). Esto significa que el evento se activa cada vez que una pantalla nueva o la pantalla existente está (física o virtualmente, en el caso del Sidecar) enchufada o desconectada.

Ten en cuenta que debes buscar los detalles de la nueva pantalla de forma asíncrona, ya que el evento screenschange no proporciona estos datos. Para buscar los detalles de la pantalla, usa el objeto activo de un contenedor 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;
  }
});

El evento currentscreenchange

Si solo me interesan los cambios en la pantalla actual (es decir, el valor del objeto activo currentScreen), puedo escuchar el 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);
});

El evento change

Por último, si solo me interesan los cambios en una pantalla concreta, puedo escuchar change evento.

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

Nuevas opciones de pantalla completa

Hasta ahora, podías solicitar que los elementos se mostraran en modo de pantalla completa a través del llamado requestFullScreen() . El método toma un parámetro options, en el que puedes pasar FullscreenOptions Hasta ahora, su única propiedad ha sido navigationUI La API de Window Management agrega una nueva propiedad screen que te permite determinar en qué pantalla se inicia la vista de pantalla completa. Por ejemplo, si quieres que la pantalla principal pantalla completa:

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

No es posible crear polyfills de la API de Window Management, pero puedes corregir su forma para que puedes programar exclusivamente con la nueva 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;
}

Los demás aspectos de la API, es decir, los distintos eventos de cambio de pantalla y la propiedad screen de FullscreenOptions, nunca se activaría ni se ignorará en silencio, respectivamente, navegadores no compatibles.

Demostración

Si eres de alguna forma como yo, debes prestar atención al desarrollo de las diversas criptomonedas. (En realidad, no lo hago porque amo este planeta, pero en este artículo, supón que did.) Para hacer un seguimiento de las criptomonedas que tengo, desarrollé una aplicación web que me permite ver los mercados en todas las situaciones de la vida, por ejemplo, desde la comodidad de mi cama, donde tengo un configuración de una sola pantalla.

Pantalla de TV enorme al final de una cama con las piernas del autor parcialmente visibles. En la pantalla, se ve una mesa de comercio de criptomonedas falsas.
Relájate y observa los mercados.

En cuanto a las criptomonedas, los mercados pueden volverse agitados en cualquier momento. Si esto sucede, puedo rápidamente y pasaré a mi escritorio donde tengo una configuración multipantalla. puedo hacer clic en la ventana de cualquier moneda y ver rápidamente todos los detalles en una vista de pantalla completa en la pantalla opuesta. A continuación, hay una foto reciente de que me tomé en el último baño de sangre de YCY. Me atrapó completamente por sorpresa y me dejó con las manos en la cara.

El autor, con las manos en la cara de pánico, mira la mesa de comercio de criptomonedas falsas.
Pánico, presenciando el baño de sangre de YCY

Puedes jugar con la demostración incorporada a continuación o ver su código fuente en caso de error.

Seguridad y permisos

El equipo de Chrome diseñó e implementó la API de Window Management con la base de que se definen en Controla el acceso a las funciones potentes de la plataforma web, incluidos el control de usuario, la transparencia y la ergonomía. La API de Window Management expone nueva información sobre las pantallas conectadas a un dispositivo, lo que aumenta la superficie de huella digital de en especial, aquellos con varias pantallas conectadas a sus dispositivos de manera constante. Como uno para mitigar esta preocupación por la privacidad, las propiedades de la pantalla expuesta se limitan a lo mínimo necesario para casos de uso de posiciones comunes. Se requiere permiso del usuario para que los sitios tengan la función multipantalla información y colocar las ventanas en otras pantallas. Si bien Chromium devuelve etiquetas de pantalla detalladas, los navegadores tienen la libertad de mostrar etiquetas menos descriptivas (o incluso vacías).

Control de usuarios

El usuario tiene el control total de la exposición de su configuración. Puede aceptar o rechazar el solicitud de permiso y revocar un permiso otorgado previamente a través de la función de información del sitio en el navegador.

Control empresarial

Los usuarios de Chrome Enterprise pueden controlar varios aspectos de la API de Window Management, como descritos en la sección relevante de Grupos atómicos de políticas configuración.

Transparencia

El hecho de que se haya otorgado permiso para usar la API de Window Management que se expone en la información del sitio del navegador y que también se puede consultar a través de la API de Permissions.

Persistencia de permisos

El navegador conserva los otorgamientos de permisos. Se puede revocar el permiso a través del sitio del navegador. información.

Comentarios

El equipo de Chrome quiere conocer tu experiencia con la API de Window Management.

Cuéntanos sobre el diseño de la API

¿Algo en la API no funciona como esperabas? ¿O faltan métodos o propiedades que necesitas para implementar tu idea? Haz una pregunta o comentario sobre la seguridad modelo?

  • Informa un problema de especificaciones en el repositorio de GitHub correspondiente o agrega lo que piensas a un archivo problema.

Informar un problema con la implementación

¿Encontraste un error en la implementación de Chrome? ¿O la implementación es diferente de la especificación?

  • Informa un error en new.crbug.com. Asegúrate de incluir todos los detalles que , obtén instrucciones sencillas para reproducir y, luego, ingresa Blink>Screen>MultiScreen en el Componentes. Glitch funciona muy bien para compartir repros rápidos y fáciles.

Demuestra compatibilidad con la API

¿Planeas usar la API de Window Management? Tu apoyo público ayuda a Chrome para priorizar funciones y muestra a otros proveedores de navegadores la importancia de brindar compatibilidad con ellas.

Vínculos útiles

Agradecimientos

El usuario editó la especificación de la API de Window Management Victor Costan, Joshua Bell y Mike Wasserman. La API fue implementada por Mike Wasserman y Adrienne Walker. Este artículo fue revisado por Joe Medley, François Beaufort, y Kayce Basques. Gracias a Laura Torrent Puig por las fotos.