Управление несколькими дисплеями с помощью API управления окнами,Управление несколькими дисплеями с помощью API управления окнами

Получите информацию о подключенных дисплеях и расположите окна относительно этих дисплеев.

API управления окнами

API управления окнами позволяет вам перечислять дисплеи, подключенные к вашему компьютеру, и размещать окна на определенных экранах.

Рекомендуемые варианты использования

Примеры сайтов, которые могут использовать этот API:

  • Многооконные графические редакторы типа Gimp могут размещать различные инструменты редактирования в точно расположенных окнах.
  • Виртуальные торговые столы могут отображать рыночные тенденции в нескольких окнах, любое из которых можно просматривать в полноэкранном режиме.
  • Приложения для слайд-шоу могут отображать заметки докладчика на внутреннем основном экране, а презентацию — на внешнем проекторе.

Как использовать API управления окнами

Проблема

Проверенный временем подход к управлению окнами Window.open() , к сожалению, не поддерживает дополнительные экраны. Хотя некоторые аспекты этого API кажутся немного архаичными, например, параметр windowFeatures DOMString , тем не менее, он хорошо служил нам на протяжении многих лет. Чтобы указать положение окна, вы можете передать координаты left и top (или screenX и screenY соответственно) и передать желаемый размер как width и height (или innerWidth и innerHeight соответственно). Например, чтобы открыть окно размером 400×300 на расстоянии 50 пикселей слева и 50 пикселей сверху, вы можете использовать следующий код:

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

Вы можете получить информацию о текущем экране, просмотрев свойство window.screen , которое возвращает объект Screen . Это вывод на моем 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
*/

Как и большинству людей, работающих в сфере технологий, мне пришлось адаптироваться к новой рабочей реальности и создать личный домашний офис. Мой выглядит так, как на фото ниже (если вам интересно, вы можете прочитать полную информацию о моей настройке ). iPad, находящийся рядом с моим MacBook, подключен к ноутбуку через Sidecar , поэтому в любой момент я могу быстро превратить iPad во второй экран.

Школьная парта на два стула. На школьной скамье стоят коробки из-под обуви, в которых лежат ноутбук и два iPad, окружающие его.
Многоэкранная установка.

Если я хочу воспользоваться преимуществом большого экрана, я могу поместить всплывающее окно из примера кода выше на второй экран. Я делаю это так:

popup.moveTo(2500, 50);

Это грубое предположение, поскольку узнать размеры второго экрана невозможно. Информация из window.screen охватывает только встроенный экран, но не экран iPad. Заявленная width встроенного экрана составляла 1680 пикселей, поэтому переход на 2500 пикселей может помочь переместить окно на iPad, поскольку я знаю, что оно расположено справа от моего MacBook. Как это сделать в общем случае? Оказывается, есть лучший способ, чем гадать. Таким образом, это API управления окнами.

Обнаружение функций

Чтобы проверить, поддерживается ли API управления окнами, используйте:

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

Разрешение window-management

Прежде чем я смогу использовать API управления окнами, я должен запросить у пользователя разрешение на это. Разрешение window-management можно запросить с помощью Permissions API следующим образом:

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

Пока используются браузеры со старым и новым именем разрешения, обязательно используйте защитный код при запросе разрешения, как в примере ниже.

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

Браузер может выбрать динамическое отображение запроса на разрешение при первой попытке использовать любой из методов нового API. Читайте дальше, чтобы узнать больше.

Свойство window.screen.isExtended

Чтобы узнать, подключено ли к моему устройству более одного экрана, я обращаюсь к свойству window.screen.isExtended . Он возвращает true или false . Для моей настройки он возвращает true .

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

Метод getScreenDetails()

Теперь, когда я знаю, что текущая настройка является многоэкранной, я могу получить дополнительную информацию о втором экране с помощью Window.getScreenDetails() . При вызове этой функции появится запрос на разрешение, в котором меня спросят, может ли сайт открываться и размещать окна на моем экране. Функция возвращает обещание, которое разрешается с помощью объекта ScreenDetailed . На моем MacBook Pro 13 с подключенным iPad это поле включает в себя поле screens с двумя объектами 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
  }]
}
*/

Информация о подключенных экранах доступна в массиве screens . Обратите внимание, что значение left для iPad начинается с 1680 , что соответствует width встроенного дисплея. Это позволяет мне точно определить, как логически расположены экраны (рядом друг с другом, друг над другом и т. д.). Также теперь для каждого экрана есть данные, показывающие, является ли он isInternal и isPrimary . Обратите внимание, что встроенный экран не обязательно является основным экраном .

Поле currentScreen — это живой объект, соответствующий текущему window.screen . Объект обновляется при размещении окон на разных экранах или при изменении устройства.

Событие смены screenschange

Единственное, чего сейчас не хватает, — это способа определить, когда у меня меняются настройки экрана. Новое событие screenschange делает именно это: оно срабатывает всякий раз, когда изменяется совокупность экранов. (Обратите внимание, что слово «screens» в названии события стоит во множественном числе.) Это означает, что событие срабатывает всякий раз, когда новый или существующий экран (физически или виртуально в случае Sidecar) подключается или отключается.

Обратите внимание, что вам необходимо асинхронно искать информацию о новом экране, само событие screenschange не предоставляет эти данные. Чтобы просмотреть сведения об экране, используйте живой объект из кэшированного интерфейса 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;
  }
});

currentscreenchange

Если меня интересуют только изменения текущего экрана (то есть значения живого объекта currentScreen ), я могу прослушивать событие currentscreenchange .

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

Событие change

Наконец, если меня интересуют только изменения на конкретном экране, я могу прослушать событие change этого экрана.

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

Новые возможности полноэкранного режима

До сих пор вы могли запросить отображение элементов в полноэкранном режиме с помощью метода requestFullScreen() с метким названием. Метод принимает параметр options , куда вы можете передать FullscreenOptions . До сих пор его единственным свойством было navigationUI . API управления окнами добавляет новое свойство screen , которое позволяет вам определить, на каком экране начинать полноэкранный режим. Например, если вы хотите сделать основной экран полноэкранным:

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

Полифилл

Невозможно заполнить API управления окнами, но вы можете изменить его форму, чтобы писать код исключительно для нового 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;
}

Другие аспекты API, то есть различные события смены экрана и свойство screen FullscreenOptions , просто никогда не сработают или будут игнорироваться соответственно неподдерживающими браузерами.

Демо

Если вы чем-то похожи на меня, вы внимательно следите за развитием различных криптовалют. (На самом деле я это делаю не потому, что люблю эту планету, но ради этой статьи просто предположу, что да.) Чтобы отслеживать криптовалюты, которыми я владею, я разработал веб-приложение, которое позволяет мне наблюдать за рынками в любых жизненных ситуациях, например, не вставая с кровати, где у меня есть приличная установка с одним экраном.

Массивный экран телевизора в конце кровати, частично видны ноги автора. На экране фальшивый пункт торговли криптовалютой.
Отдыхаем и наблюдаем за рынками.

Что касается криптовалюты, рынки могут стать беспокойными в любой момент. Если это произойдет, я могу быстро перейти к своему столу, где у меня есть многоэкранная установка. Я могу щелкнуть окно любой валюты и быстро просмотреть полную информацию в полноэкранном режиме на противоположном экране. Ниже приведена моя недавняя фотография, сделанная во время последней кровавой бойни YCY . Это застало меня врасплох и я закрыл лицо руками .

Автор, заложив руки на паническое лицо, смотрит на фальшивую стойку по торговле криптовалютой.
Паникки, ставший свидетелем кровавой бойни YCY.

Вы можете поиграть с демо-версией, представленной ниже, или посмотреть ее исходный код на предмет ошибок.

Безопасность и разрешения

Команда Chrome разработала и внедрила API управления окнами, используя основные принципы, определенные в разделе «Управление доступом к мощным функциям веб-платформы» , включая пользовательский контроль, прозрачность и эргономику. API управления окнами предоставляет новую информацию об экранах, подключенных к устройству, увеличивая поверхность для снятия отпечатков пальцев у пользователей, особенно у тех, у кого несколько экранов последовательно подключены к их устройствам. Чтобы смягчить эту проблему конфиденциальности, доступные свойства экрана ограничены минимумом, необходимым для обычных случаев размещения. Разрешение пользователя требуется сайтам для получения многоэкранной информации и размещения окон на других экранах. В то время как Chromium возвращает подробные метки экрана, браузеры могут возвращать менее описательные (или даже пустые метки).

Пользовательский контроль

Пользователь полностью контролирует экспозицию своей установки. Они могут принять или отклонить запрос на разрешение, а также отозвать ранее предоставленное разрешение с помощью функции информации о сайте в браузере.

Контроль предприятия

Пользователи Chrome Enterprise могут контролировать несколько аспектов API управления окнами, как описано в соответствующем разделе настроек групп атомарной политики .

Прозрачность

Тот факт, было ли предоставлено разрешение на использование API управления окнами, отображается в информации о сайте браузера, а также доступен для запроса через API разрешений.

Сохранение разрешений

Браузер сохраняет разрешения. Разрешение можно отозвать через информацию о сайте в браузере.

Обратная связь

Команда Chrome хочет услышать о вашем опыте работы с API управления окнами.

Расскажите нам о дизайне API

Что-то в API работает не так, как вы ожидали? Или вам не хватает методов или свойств, необходимых для реализации вашей идеи? У вас есть вопрос или комментарий по модели безопасности?

  • Сообщите о проблеме спецификации в соответствующем репозитории GitHub или добавьте свои мысли к существующей проблеме.

Сообщить о проблеме с реализацией

Вы нашли ошибку в реализации Chrome? Или реализация отличается от спецификации?

  • Сообщите об ошибке на сайте new.crbug.com . Обязательно включите как можно больше деталей, простые инструкции по воспроизведению и введите Blink>Screen>MultiScreen в поле «Компоненты» . Glitch отлично подходит для быстрого и простого обмена репродукциями.

Показать поддержку API

Планируете ли вы использовать API управления окнами? Ваша публичная поддержка помогает команде Chrome расставлять приоритеты для функций и показывает другим поставщикам браузеров, насколько важно их поддерживать.

  • Поделитесь, как вы планируете его использовать, в теме обсуждения WICG .
  • Отправьте твит @ChromiumDev , используя хэштег #WindowManagement , и сообщите нам, где и как вы его используете.
  • Попросите других поставщиков браузеров реализовать API.

Полезные ссылки

Благодарности

Спецификацию API управления окнами редактировали Виктор Костан , Джошуа Белл и Майк Вассерман . API был реализован Майком Вассерманом и Эдриен Уокер . Эта статья была рецензирована Джо Медли , Франсуа Бофором и Кейси Баскс . Спасибо Лауре Торрент Пуч за фотографии.

,

Получите информацию о подключенных дисплеях и расположите окна относительно этих дисплеев.

API управления окнами

API управления окнами позволяет вам перечислять дисплеи, подключенные к вашему компьютеру, и размещать окна на определенных экранах.

Рекомендуемые варианты использования

Примеры сайтов, которые могут использовать этот API:

  • Многооконные графические редакторы типа Gimp могут размещать различные инструменты редактирования в точно расположенных окнах.
  • Виртуальные торговые столы могут отображать рыночные тенденции в нескольких окнах, любое из которых можно просматривать в полноэкранном режиме.
  • Приложения для слайд-шоу могут отображать заметки докладчика на внутреннем основном экране, а презентацию — на внешнем проекторе.

Как использовать API управления окнами

Проблема

Проверенный временем подход к управлению окнами Window.open() , к сожалению, не поддерживает дополнительные экраны. Хотя некоторые аспекты этого API кажутся немного архаичными, например, параметр windowFeatures DOMString , тем не менее, он хорошо служил нам на протяжении многих лет. Чтобы указать положение окна, вы можете передать координаты left и top (или screenX и screenY соответственно) и передать желаемый размер как width и height (или innerWidth и innerHeight соответственно). Например, чтобы открыть окно размером 400×300 на расстоянии 50 пикселей слева и 50 пикселей сверху, вы можете использовать следующий код:

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

Вы можете получить информацию о текущем экране, просмотрев свойство window.screen , которое возвращает объект Screen . Это вывод на моем 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
*/

Как и большинству людей, работающих в сфере технологий, мне пришлось адаптироваться к новой рабочей реальности и создать личный домашний офис. Мой выглядит так, как на фото ниже (если вам интересно, вы можете прочитать полную информацию о моей настройке ). iPad, расположенный рядом с моим MacBook, подключен к ноутбуку через Sidecar , поэтому в любой момент я могу быстро превратить iPad во второй экран.

Школьная парта на два стула. На школьной скамье стоят коробки из-под обуви, в которых лежат ноутбук и два iPad, окружающие его.
Многоэкранная установка.

Если я хочу воспользоваться преимуществом большого экрана, я могу поместить всплывающее окно из примера кода выше на второй экран. Я делаю это так:

popup.moveTo(2500, 50);

Это грубое предположение, поскольку узнать размеры второго экрана невозможно. Информация из window.screen охватывает только встроенный экран, но не экран iPad. Заявленная width встроенного экрана составляла 1680 пикселей, поэтому переход на 2500 пикселей может помочь переместить окно на iPad, поскольку я знаю, что оно расположено справа от моего MacBook. Как это сделать в общем случае? Оказывается, есть лучший способ, чем гадать. Таким образом, это API управления окнами.

Обнаружение функций

Чтобы проверить, поддерживается ли API управления окнами, используйте:

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

Разрешение window-management

Прежде чем я смогу использовать API управления окнами, я должен запросить у пользователя разрешение на это. Разрешение window-management можно запросить с помощью Permissions API следующим образом:

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

Пока используются браузеры со старым и новым именем разрешения, обязательно используйте защитный код при запросе разрешения, как в примере ниже.

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

Браузер может выбрать динамическое отображение запроса на разрешение при первой попытке использовать любой из методов нового API. Читайте дальше, чтобы узнать больше.

Свойство window.screen.isExtended

Чтобы узнать, подключено ли к моему устройству более одного экрана, я обращаюсь к свойству window.screen.isExtended . Он возвращает true или false . Для моей настройки он возвращает true .

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

Метод getScreenDetails()

Теперь, когда я знаю, что текущая настройка является многоэкранной, я могу получить дополнительную информацию о втором экране с помощью Window.getScreenDetails() . При вызове этой функции появится запрос на разрешение, в котором меня спросят, может ли сайт открываться и размещать окна на моем экране. Функция возвращает обещание, которое разрешается с помощью объекта ScreenDetailed . На моем MacBook Pro 13 с подключенным iPad это поле включает в себя поле screens с двумя объектами 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
  }]
}
*/

Информация о подключенных экранах доступна в массиве screens . Обратите внимание, что значение left для iPad начинается с 1680 , что соответствует width встроенного дисплея. Это позволяет мне точно определить, как логически расположены экраны (рядом друг с другом, друг над другом и т. д.). Также теперь для каждого экрана есть данные, показывающие, является ли он isInternal и isPrimary . Обратите внимание, что встроенный экран не обязательно является основным экраном .

Поле currentScreen — это живой объект, соответствующий текущему window.screen . Объект обновляется при размещении окон на разных экранах или при изменении устройства.

Событие смены screenschange

Единственное, чего сейчас не хватает, — это способа определить, когда у меня меняются настройки экрана. Новое событие screenschange делает именно это: оно срабатывает всякий раз, когда изменяется совокупность экранов. (Обратите внимание, что слово «screens» в названии события используется во множественном числе.) Это означает, что событие срабатывает всякий раз, когда новый или существующий экран (физически или виртуально в случае Sidecar) подключается или отключается.

Обратите внимание, что вам необходимо асинхронно искать информацию о новом экране, само событие screenschange не предоставляет эти данные. Чтобы просмотреть сведения об экране, используйте живой объект из кэшированного интерфейса 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;
  }
});

currentscreenchange

Если меня интересуют только изменения текущего экрана (то есть значения живого объекта currentScreen ), я могу прослушивать событие currentscreenchange .

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

Событие change

Наконец, если меня интересуют только изменения на конкретном экране, я могу прослушать событие change этого экрана.

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

Новые возможности полноэкранного режима

До сих пор вы могли запросить отображение элементов в полноэкранном режиме с помощью метода requestFullScreen() с метким названием. Метод принимает параметр options , куда вы можете передать FullscreenOptions . До сих пор его единственным свойством было navigationUI . API управления окнами добавляет новое свойство screen , которое позволяет вам определить, на каком экране начинать полноэкранный режим. Например, если вы хотите сделать основной экран полноэкранным:

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

Полифилл

Невозможно заполнить API управления окнами, но вы можете изменить его форму, чтобы писать код исключительно для нового 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;
}

Другие аспекты API, то есть различные события смены экрана и свойство screen FullscreenOptions , просто никогда не срабатывают или молча игнорируются соответственно неподдерживающими браузерами.

Демо

Если вы чем-то похожи на меня, вы внимательно следите за развитием различных криптовалют. (На самом деле я это делаю не потому, что люблю эту планету, но ради этой статьи просто предположу, что да.) Чтобы отслеживать криптовалюты, которыми я владею, я разработал веб-приложение, которое позволяет мне наблюдать за рынками в любых жизненных ситуациях, например, не вставая с кровати, где у меня есть приличная настройка с одним экраном.

Массивный экран телевизора в конце кровати, частично видны ноги автора. На экране фальшивый пункт торговли криптовалютой.
Отдыхаем и наблюдаем за рынками.

Что касается криптовалюты, рынки могут стать беспокойными в любой момент. Если это произойдет, я могу быстро перейти к своему столу, где у меня есть многоэкранная установка. Я могу щелкнуть окно любой валюты и быстро просмотреть полную информацию в полноэкранном режиме на противоположном экране. Ниже приведена моя недавняя фотография, сделанная во время последней кровавой бойни YCY . Это застало меня врасплох и я закрыл лицо руками .

Автор, заложив руки на паническое лицо, смотрит на фальшивую стойку по торговле криптовалютой.
Паникки, ставший свидетелем кровавой бойни YCY.

Вы можете поиграть с демо-версией, представленной ниже, или посмотреть ее исходный код на предмет ошибок.

Безопасность и разрешения

Команда Chrome разработала и реализовала API управления окнами, используя основные принципы, определенные в разделе «Управление доступом к мощным функциям веб-платформы» , включая пользовательский контроль, прозрачность и эргономику. API управления окнами предоставляет новую информацию об экранах, подключенных к устройству, увеличивая возможность снятия отпечатков пальцев у пользователей, особенно у тех, у кого несколько экранов последовательно подключены к их устройствам. Чтобы смягчить эту проблему конфиденциальности, доступные свойства экрана ограничены минимумом, необходимым для обычных случаев размещения. Разрешение пользователя требуется сайтам для получения многоэкранной информации и размещения окон на других экранах. В то время как Chromium возвращает подробные метки экрана, браузеры могут возвращать менее описательные (или даже пустые метки).

Пользовательский контроль

Пользователь полностью контролирует экспозицию своей установки. Они могут принять или отклонить запрос на разрешение, а также отозвать ранее предоставленное разрешение с помощью функции информации о сайте в браузере.

Контроль предприятия

Пользователи Chrome Enterprise могут управлять несколькими аспектами API управления окнами, как описано в соответствующем разделе настроек групп атомарной политики .

Прозрачность

Тот факт, было ли предоставлено разрешение на использование API управления окнами, отображается в информации о сайте браузера, а также доступен для запроса через API разрешений.

Сохранение разрешений

Браузер сохраняет разрешения. Разрешение можно отозвать через информацию о сайте в браузере.

Обратная связь

Команда Chrome хочет услышать о вашем опыте работы с API управления окнами.

Расскажите нам о дизайне API

Что-то в API работает не так, как вы ожидали? Или вам не хватает методов или свойств, необходимых для реализации вашей идеи? У вас есть вопрос или комментарий по модели безопасности?

  • Сообщите о проблеме спецификации в соответствующем репозитории GitHub или добавьте свои мысли к существующей проблеме.

Сообщить о проблеме с реализацией

Вы нашли ошибку в реализации Chrome? Или реализация отличается от спецификации?

  • Сообщите об ошибке на сайте new.crbug.com . Обязательно включите как можно больше деталей, простые инструкции по воспроизведению и введите Blink>Screen>MultiScreen в поле «Компоненты» . Glitch отлично подходит для быстрого и простого обмена репродукциями.

Показать поддержку API

Планируете ли вы использовать API управления окнами? Ваша публичная поддержка помогает команде Chrome расставлять приоритеты для функций и показывает другим поставщикам браузеров, насколько важно их поддерживать.

  • Поделитесь, как вы планируете его использовать, в теме обсуждения WICG .
  • Отправьте твит @ChromiumDev , используя хэштег #WindowManagement , и сообщите нам, где и как вы его используете.
  • Попросите других поставщиков браузеров реализовать API.

Полезные ссылки

Благодарности

Спецификацию API управления окнами редактировали Виктор Костан , Джошуа Белл и Майк Вассерман . API был реализован Майком Вассерманом и Эдриен Уокер . Эта статья была рецензирована Джо Медли , Франсуа Бофором и Кейси Баскс . Спасибо Лауре Торрент Пуч за фотографии.

,

Получите информацию о подключенных дисплеях и расположите окна относительно этих дисплеев.

API управления окнами

API управления окнами позволяет вам перечислять дисплеи, подключенные к вашему компьютеру, и размещать окна на определенных экранах.

Рекомендуемые варианты использования

Примеры сайтов, которые могут использовать этот API:

  • Многооконные графические редакторы типа Gimp могут размещать различные инструменты редактирования в точно расположенных окнах.
  • Виртуальные торговые столы могут отображать рыночные тенденции в нескольких окнах, любое из которых можно просматривать в полноэкранном режиме.
  • Приложения для слайд-шоу могут отображать заметки докладчика на внутреннем основном экране, а презентацию — на внешнем проекторе.

Как использовать API управления окнами

Проблема

Проверенный временем подход к управлению окнами Window.open() , к сожалению, не поддерживает дополнительные экраны. Хотя некоторые аспекты этого API кажутся немного архаичными, например, параметр windowFeatures DOMString , тем не менее, он хорошо служил нам на протяжении многих лет. Чтобы указать положение окна, вы можете передать координаты left и top (или screenX и screenY соответственно) и передать желаемый размер как width и height (или innerWidth и innerHeight соответственно). Например, чтобы открыть окно размером 400×300 на расстоянии 50 пикселей слева и 50 пикселей сверху, вы можете использовать следующий код:

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

Вы можете получить информацию о текущем экране, просмотрев свойство window.screen , которое возвращает объект Screen . Это вывод на моем 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
*/

Как и большинству людей, работающих в сфере технологий, мне пришлось адаптироваться к новой рабочей реальности и создать личный домашний офис. Мой выглядит так, как на фото ниже (если вам интересно, вы можете прочитать полную информацию о моей настройке ). iPad, находящийся рядом с моим MacBook, подключен к ноутбуку через Sidecar , поэтому в любой момент я могу быстро превратить iPad во второй экран.

Школьная парта на два стула. На школьной скамье стоят коробки из-под обуви, в которых лежат ноутбук и два iPad, окружающие его.
Многоэкранная установка.

Если я хочу воспользоваться преимуществом большого экрана, я могу поместить всплывающее окно из примера кода выше на второй экран. Я делаю это так:

popup.moveTo(2500, 50);

Это грубое предположение, поскольку узнать размеры второго экрана невозможно. Информация из window.screen охватывает только встроенный экран, но не экран iPad. Заявленная width встроенного экрана составляла 1680 пикселей, поэтому переход на 2500 пикселей может помочь переместить окно на iPad, поскольку я знаю, что оно расположено справа от моего MacBook. Как это сделать в общем случае? Оказывается, есть лучший способ, чем гадать. Таким образом, это API управления окнами.

Обнаружение функций

Чтобы проверить, поддерживается ли API управления окнами, используйте:

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

Разрешение window-management

Прежде чем я смогу использовать API управления окнами, я должен запросить у пользователя разрешение на это. Разрешение window-management можно запросить с помощью Permissions API следующим образом:

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

Пока используются браузеры со старым и новым именем разрешения, обязательно используйте защитный код при запросе разрешения, как в примере ниже.

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

Браузер может выбрать динамическое отображение запроса на разрешение при первой попытке использовать любой из методов нового API. Читайте дальше, чтобы узнать больше.

Свойство window.screen.isExtended

Чтобы узнать, подключено ли к моему устройству более одного экрана, я обращаюсь к свойству window.screen.isExtended . Он возвращает true или false . Для моей настройки он возвращает true .

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

Метод getScreenDetails()

Теперь, когда я знаю, что текущая настройка является многоэкранной, я могу получить дополнительную информацию о втором экране с помощью Window.getScreenDetails() . При вызове этой функции появится запрос на разрешение, в котором меня спросят, может ли сайт открываться и размещать окна на моем экране. Функция возвращает обещание, которое разрешается с помощью объекта ScreenDetailed . На моем MacBook Pro 13 с подключенным iPad это поле включает в себя поле screens с двумя объектами 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
  }]
}
*/

Информация о подключенных экранах доступна в массиве screens . Обратите внимание, что значение left для iPad начинается с 1680 , что соответствует width встроенного дисплея. Это позволяет мне точно определить, как логически расположены экраны (рядом друг с другом, друг над другом и т. д.). Также теперь для каждого экрана есть данные, показывающие, является ли он isInternal и isPrimary . Обратите внимание, что встроенный экран не обязательно является основным экраном .

Поле currentScreen — это живой объект, соответствующий текущему window.screen . Объект обновляется при размещении окон на разных экранах или при изменении устройства.

Событие смены screenschange

Единственное, чего сейчас не хватает, — это способа определить, когда у меня меняются настройки экрана. Новое событие screenschange делает именно это: оно срабатывает всякий раз, когда изменяется совокупность экранов. (Обратите внимание, что слово «screens» в названии события используется во множественном числе.) Это означает, что событие срабатывает всякий раз, когда новый или существующий экран (физически или виртуально в случае Sidecar) подключается или отключается.

Обратите внимание, что вам необходимо асинхронно искать информацию о новом экране, само событие screenschange не предоставляет эти данные. Чтобы просмотреть сведения об экране, используйте живой объект из кэшированного интерфейса 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;
  }
});

currentscreenchange

Если меня интересуют только изменения текущего экрана (то есть значения живого объекта currentScreen ), я могу прослушивать событие currentscreenchange .

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

Событие change

Наконец, если меня интересуют только изменения на конкретном экране, я могу прослушать событие change этого экрана.

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

Новые возможности полноэкранного режима

До сих пор вы могли запросить отображение элементов в полноэкранном режиме с помощью метода requestFullScreen() с метким названием. Метод принимает параметр options , куда вы можете передать FullscreenOptions . До сих пор его единственным свойством было navigationUI . API управления окнами добавляет новое свойство screen , которое позволяет вам определить, на каком экране начинать полноэкранный режим. Например, если вы хотите сделать основной экран полноэкранным:

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

Полифилл

Невозможно заполнить API управления окнами, но вы можете изменить его форму, чтобы писать код исключительно для нового 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;
}

Другие аспекты API, то есть различные события смены экрана и свойство screen FullscreenOptions , просто никогда не срабатывают или молча игнорируются соответственно неподдерживающими браузерами.

Демо

Если вы чем-то похожи на меня, вы внимательно следите за развитием различных криптовалют. (На самом деле я это делаю не потому, что люблю эту планету, но ради этой статьи просто предположу, что да.) Чтобы отслеживать криптовалюты, которыми я владею, я разработал веб-приложение, которое позволяет мне наблюдать за рынками в любых жизненных ситуациях, например, не вставая с кровати, где у меня есть приличная настройка с одним экраном.

Массивный экран телевизора в конце кровати, частично видны ноги автора. На экране фальшивый пункт торговли криптовалютой.
Отдыхаем и наблюдаем за рынками.

Что касается криптовалюты, рынки могут стать беспокойными в любой момент. Если это произойдет, я могу быстро перейти к своему столу, где у меня есть многоэкранная установка. Я могу щелкнуть окно любой валюты и быстро просмотреть полную информацию в полноэкранном режиме на противоположном экране. Ниже приведена моя недавняя фотография, сделанная во время последней кровавой бойни YCY . Это застало меня врасплох и я закрыл лицо руками .

Автор, заложив руки на паническое лицо, смотрит на фальшивую стойку по торговле криптовалютой.
Паникки, ставший свидетелем кровавой бойни YCY.

Вы можете поиграть с демо-версией, представленной ниже, или посмотреть ее исходный код на предмет ошибок.

Безопасность и разрешения

Команда Chrome разработала и реализовала API управления окнами, используя основные принципы, определенные в разделе «Управление доступом к мощным функциям веб-платформы» , включая пользовательский контроль, прозрачность и эргономику. API управления окнами предоставляет новую информацию об экранах, подключенных к устройству, увеличивая возможность снятия отпечатков пальцев у пользователей, особенно у тех, у кого несколько экранов последовательно подключены к их устройствам. Чтобы смягчить эту проблему конфиденциальности, доступные свойства экрана ограничены минимумом, необходимым для обычных случаев размещения. Разрешение пользователя требуется сайтам для получения многоэкранной информации и размещения окон на других экранах. В то время как Chromium возвращает подробные метки экрана, браузеры могут свободно возвращать менее описательные (или даже пустые этикетки).

Пользовательский контроль

Пользователь полностью контролирует экспозицию их настройки. Они могут принять или отклонить подсказку разрешения и отозвать ранее предоставленное разрешение через функцию информации о сайте в браузере.

Корпоративное управление

Пользователи Chrome Enterprise могут управлять несколькими аспектами API управления окнами, как указано в соответствующем разделе настройки групп атомной политики .

Прозрачность

Тот факт, что разрешение на использование API управления окнами было предоставлено, раскрыто в информации о сайте браузера, а также поддается запросу через API разрешений.

По настойку разрешения

Браузер сохраняет гранты разрешения. Разрешение может быть отозвано через информацию о сайте браузера.

Обратная связь

Команда Chrome хочет услышать о вашем опыте с API управления окнами.

Расскажите нам о дизайне API

Есть ли что -то в API, которое не работает так, как вы ожидали? Или вам не хватает методов или свойств, необходимых для реализации вашей идеи? У вас есть вопрос или комментарий по модели безопасности?

  • Задайте проблему спецификации в соответствующем репо github или добавьте свои мысли к существующей проблеме.

Сообщить о проблеме с реализацией

Вы нашли ошибку с реализацией Chrome? Или реализация отличается от спецификации?

  • Сообщите об ошибке на сайте new.crbug.com . Обязательно включите как можно больше деталей, простые инструкции для воспроизведения и введите Blink>Screen>MultiScreen в поле компонентов . Glitch отлично подходит для быстрого и простого обмена репродукциями.

Показать поддержку API

Вы планируете использовать API управления окнами? Ваша общественная поддержка помогает команде Chrome определить приоритеты функций и показывает другим поставщикам браузеров, насколько важно их поддержать.

  • Поделитесь тем, как вы планируете использовать его в дискурсной ветке WICG .
  • Отправьте твит @chromiumdev , используя хэштег #WindowManagement и дайте нам знать, где и как вы его используете.
  • Попросите других поставщиков браузеров внедрить API.

Полезные ссылки

Благодарности

Спецификация API управления окнами была отредактирована Виктором Костаном , Джошуа Беллом и Майком Вассерманом . API был реализован Майком Вассерманом и Эдриенной Уокер . Эта статья была рассмотрена Джо Медли , Франсуа Бофортом и Кейсом Баски . Спасибо Лоре Торрент Пуиг за фотографии.

,

Получите информацию о подключенных дисплеях и поставьте окна относительно этих дисплеев.

Управление окнами API

API управления окнами позволяет перечислять дисплеи, подключенные к вашей машине, и размещать окна на определенных экранах.

Предлагаемые варианты использования

Примеры сайтов, которые могут использовать этот API, включают:

  • Редакторы графики с несколькими Window à la Gimp могут размещать различные инструменты редактирования в точно расположенные Windows.
  • Виртуальные торговые столы могут показывать тенденции рынка в нескольких окнах, любые из которых можно просмотреть в полноэкранном режиме.
  • Приложения SlideShow могут отображать заметки о динамике на внутреннем первичном экране и презентацию на внешнем проекторе.

Как использовать API управления окнами

Проблема

Протестированный по времени подход к управлению Windows, Window.open() , к сожалению, не знает о дополнительных экранах. В то время как некоторые аспекты этого API кажутся немного архаичными, такие как его windowFeatures параметр DOMString , он, тем не менее, служил нам за эти годы. Чтобы указать позицию окна, вы можете передать координаты, как left и top (или screenX и screenY соответственно) и передавать желаемый размер в виде width и height (или innerWidth и innerHeight соответственно). Например, чтобы открыть окно 400 × 300 при 50 пикселях слева и 50 пикселей от вершины, это код, который вы можете использовать:

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

Вы можете получить информацию о текущем экране, посмотрев на свойство window.screen , которое возвращает объект Screen . Это выход на моем 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
*/

Как и большинство людей, работающих в технологиях, мне пришлось адаптироваться к новой рабочей реальности и создать свой личный домашний офис. Мой выглядит на фото ниже (если вам интересно, вы можете прочитать полную информацию о моей настройке ). IPad рядом с моим MacBook подключен к ноутбуку через коляску , поэтому, когда мне нужно, я могу быстро превратить iPad во второй экран.

Школьная скамейка на двух стульях. Вдобавок к школьной скамейке находятся обувные коробки, поддерживающие ноутбук и два iPad, окружающие его.
Многоэкранная установка.

Если я хочу воспользоваться большим экраном, я могу поместить всплывающее окно из примера кода выше на второй экран. Я делаю это так:

popup.moveTo(2500, 50);

Это грубое предположение, так как нет способа узнать размеры второго экрана. Информация из window.screen только покрывает встроенный экран, но не на экране iPad. Зарегистрированная width встроенного экрана составляла 1680 пикселей, поэтому перемещение на 2500 пикселей может работать, чтобы перенести окно на iPad, так как я узнал, что оно расположено справа от моего MacBook. Как я могу сделать это в общем случае? Оказывается, есть лучший способ, чем угадать. Таким образом, API управления окнами.

Обнаружение функций

Чтобы проверить, поддерживается ли API управления окнами, используйте:

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

Разрешение window-management

Прежде чем я смогу использовать API управления окнами, я должен попросить пользователя разрешить это. Разрешение window-management может быть запрошено с API разрешений, как и SO:

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

В то время как браузеры со старым и новым именем разрешения используются, обязательно используйте защитный код при запросе разрешения, как в примере ниже.

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

Браузер может динамически показать подсказку разрешения с первой попыткой использовать любой из методов нового API. Читайте дальше, чтобы узнать больше.

window.screen.isExtended

Чтобы узнать, подключено ли к моему устройству более одного экрана, я получаю доступ к свойству window.screen.isExtended . Он возвращает true или false . Для моей настройки это возвращает true .

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

Метод getScreenDetails()

Теперь, когда я знаю, что текущая настройка является многоэкранной, я могу получить больше информации о втором экране с помощью Window.getScreenDetails() . Вызов этой функции покажет подсказку разрешения, которая спросит меня, может ли сайт открыть и разместить Windows на моем экране. Функция возвращает обещание, которое разрешает с помощью ScreenDetailed объекта. На моем MacBook Pro 13 с подключенным iPad это включает в себя поле screens с двумя объектами, 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
  }]
}
*/

Информация о подключенных экранах доступна в массиве screens . Обратите внимание, как значение left для iPad начинается с 1680 , что является именно width встроенного дисплея. Это позволяет мне точно определить, как экраны расположены логически (рядом друг с другом, друг над другом и т. Д.). Сейчас для каждого экрана также есть данные, чтобы показать, является ли он isInternal , и является ли он isPrimary . Обратите внимание, что встроенный экран не обязательно является основным экраном .

Поле currentScreen - это живой объект, соответствующий текущему window.screen . Объект обновляется на размещении окна поперечного экрана или изменениям устройства.

Событие screenschange

Единственное, чего сейчас не хватает, - это способ обнаружить, когда изменяется настройка экрана. Новое событие, screenschange , делает именно это: оно стреляет всякий раз, когда модифицируется созвездие экрана. (Обратите внимание, что «экраны» является множественным числом во время этого имени.) Это означает, что событие запускается всякий раз, когда новый экран или существующий экран (физически или практически в случае коляска) подключено или отключено.

Обратите внимание, что вам нужно искать новые данные экрана асинхронно, само событие screenschange не предоставляет эти данные. Чтобы посмотреть детали экрана, используйте живой объект из интерфейса кэшированных 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;
  }
});

Событие currentscreenchange

Если меня заинтересованы только в изменениях в текущем экране (то есть значении живого объекта currentScreen ), я могу прослушать событие currentscreenchange .

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

Мероприятие change

Наконец, если я заинтересован только в изменениях в конкретном экране, я могу прослушать событие change этого экрана.

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

Новые полноэкранные варианты

До сих пор вы можете запросить, чтобы элементы отображались в полноэкранном режиме с помощью метко именованного метода requestFullScreen() . Метод принимает параметр options , где вы можете пройти FullscreenOptions . До сих пор его единственной собственностью была navigationUI . API управления окном добавляет новое свойство screen , которое позволяет определить, какой экран запустить полноэкранное представление. Например, если вы хотите сделать основной экран полноэкранным:

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

Полифилл

Невозможно полифильнее API управления окнами, но вы можете содержать его форму, чтобы вы могли кодироваться исключительно против нового 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;
}

Другие аспекты API, то есть различные события изменения экрана и свойство screen FullscreenOptions , просто никогда не стреляют или молча игнорируются соответственно браузерами.

Демо

Если вы что -то похожи на меня, вы внимательно следите за развитием различных криптовалют. (На самом деле я очень не знаю, потому что я люблю эту планету, но, ради этой статьи, просто предположим, что я это сделал.) Чтобы отслеживать криптовалюты, которые я владею, я разработал веб-приложение, которое позволяет мне наблюдать за рынками во всех жизненных ситуациях, таких как утешение моей кровати, где у меня есть приличная настройка одноразового.

Массивный телевизионный экран в конце кровати с ногами автора частично видна. На экране фальшивый стол для торговли криптовалютой.
Расслабьтесь и смотрят рынки.

Это крипто, рынки могут стать беспокойными в любое время. Если это произойдет, я могу быстро перейти к своему столу, где у меня есть многоэкранная установка. Я могу нажать на окно любой валюты и быстро увидеть полную информацию в полноэкранном представлении на противоположном экране. Ниже приведена недавняя фотография меня сделана во время последней Ycy Bloodbath . Это полностью поймало меня с самого начала и оставило меня руками на лице .

Автор с руками на его паническом лицо, уставившись на фальшивую криптовалютную торговлю.
Паник, свидетельствуя о джийской крови.

Вы можете играть с демонстрацией , встроенной ниже, или увидеть его исходный код на глюке.

Безопасность и разрешения

Команда Chrome разработала и внедрила API управления окнами, используя основные принципы, определенные в контроле доступа к мощным функциям веб -платформы , включая управление пользователем, прозрачность и эргономику. API управления окнами открывает новую информацию о экранах, подключенных к устройству, увеличивая поверхность отпечатков пальцев пользователей, особенно с несколькими экранами, последовательно подключенными к их устройствам. В качестве одного смягчения этой проблемы конфиденциальности, открытые свойства экрана ограничены минимумом, необходимым для общих вариантов использования размещения. Пользовательский разрешение требуется, чтобы сайты получили многоэкранную информацию и размещали Windows на другие экраны. В то время как Chromium возвращает подробные метки экрана, браузеры могут свободно возвращать менее описательные (или даже пустые этикетки).

Пользовательский контроль

Пользователь полностью контролирует экспозицию их настройки. Они могут принять или отклонить подсказку разрешения и отозвать ранее предоставленное разрешение через функцию информации о сайте в браузере.

Корпоративное управление

Пользователи Chrome Enterprise могут управлять несколькими аспектами API управления окнами, как указано в соответствующем разделе настройки групп атомной политики .

Прозрачность

Тот факт, что разрешение на использование API управления окнами было предоставлено, раскрыто в информации о сайте браузера, а также поддается запросу через API разрешений.

По настойку разрешения

Браузер сохраняет гранты разрешения. Разрешение может быть отозвано через информацию о сайте браузера.

Обратная связь

Команда Chrome хочет услышать о вашем опыте с API управления окнами.

Расскажите нам о дизайне API

Есть ли что -то в API, которое не работает так, как вы ожидали? Или вам не хватает методов или свойств, необходимых для реализации вашей идеи? У вас есть вопрос или комментарий по модели безопасности?

  • Задайте проблему спецификации в соответствующем репо github или добавьте свои мысли к существующей проблеме.

Сообщить о проблеме с реализацией

Вы нашли ошибку с реализацией Chrome? Или реализация отличается от спецификации?

  • Сообщите об ошибке на сайте new.crbug.com . Обязательно включите как можно больше деталей, простые инструкции для воспроизведения и введите Blink>Screen>MultiScreen в поле компонентов . Glitch отлично подходит для быстрого и простого обмена репродукциями.

Показать поддержку API

Вы планируете использовать API управления окнами? Ваша общественная поддержка помогает команде Chrome определить приоритеты функций и показывает другим поставщикам браузеров, насколько важно их поддержать.

  • Поделитесь тем, как вы планируете использовать его в дискурсной ветке WICG .
  • Отправьте твит @chromiumdev , используя хэштег #WindowManagement и дайте нам знать, где и как вы его используете.
  • Попросите других поставщиков браузеров внедрить API.

Полезные ссылки

Благодарности

Спецификация API управления окнами была отредактирована Виктором Костаном , Джошуа Беллом и Майком Вассерманом . API был реализован Майком Вассерманом и Эдриенной Уокер . Эта статья была рассмотрена Джо Медли , Франсуа Бофортом и Кейсом Баски . Спасибо Лоре Торрент Пуиг за фотографии.