接続されているディスプレイに関する情報を取得し、それらのディスプレイを基準にウィンドウを配置します。
Window Management API
Window Management API を使用すると、マシンに接続されているディスプレイを列挙し、特定の画面にウィンドウを配置できます。
推奨されるユースケース
この API を使用するサイトの例を次に示します。
- Gimp のようなマルチウィンドウ グラフィック エディタでは、さまざまな編集ツールを正確に配置されたウィンドウに配置できます。
- 仮想取引デスクでは、複数のウィンドウに市場のトレンドを表示できます。これらのウィンドウはいずれも、全画面表示モードで表示できます。
- スライドショー アプリでは、内部のメイン画面にスピーカー ノートを表示し、外部プロジェクタにプレゼンテーションを表示できます。
Window Management 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
*/
テクノロジー業界で働くほとんどの人と同じように、私は新しい働き方に適応し、個人用の自宅オフィスをセットアップする必要がありました。私のセットアップは下の写真を参照してください(興味がある方は、私のセットアップの詳細をご覧ください)。MacBook の横にある iPad は Sidecar 経由でノートパソコンに接続されているため、必要に応じて iPad をサブ画面に素早く切り替えることができます。
大きな画面を活用したい場合は、上記のコードサンプルのポップアップを 2 つ目の画面に配置できます。次のように行います。
popup.moveTo(2500, 50);
2 つ目の画面のサイズを把握する方法がないため、これはあくまでも推測です。window.screen
の情報は、内蔵画面のみを対象としており、iPad の画面は対象外です。内蔵画面の報告された width
は 1680
ピクセルでした。MacBook の右側にあることが判明したため、2500
ピクセルに変更すると、ウィンドウが iPad に移動する可能性があります。一般的なケースでこれを行うにはどうすればよいですか?実は、推測するよりも良い方法があります。その方法は Window Management API です。
特徴検出
Window Management API がサポートされているかどうかを確認するには、次のコマンドを使用します。
if ('getScreenDetails' in window) {
// The Window Management API is supported.
}
window-management
権限
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()
を使用して 2 番目の画面の詳細情報を取得できます。この関数を呼び出すと、サイトが画面上にウィンドウを開いて配置することを許可するかどうかを尋ねる権限プロンプトが表示されます。この関数は、ScreenDetailed
オブジェクトで解決される Promise を返します。iPad が接続されている MacBook Pro 13 では、2 つの ScreenDetailed
オブジェクトを含む screens
フィールドがあります。
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
配列で確認できます。iPad の left
の値が 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
です。Window Management 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);
}
ポリフィル
Window Management 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 の他の部分(さまざまな画面変更イベントや FullscreenOptions
の screen
プロパティ)は、サポートされていないブラウザでは、単にトリガーされず、またはサイレントで無視されます。
デモ
私と同じように、さまざまな暗号通貨の開発を注視している方も多いと思います。(実際は、この惑星を愛しているので、そうは思いませんが、この記事ではそう仮定してください)。自分が所有する暗号通貨の状況を把握するために、ウェブアプリを開発しました。このアプリでは、ベッドに座ってシングル スクリーンで快適に設定できるなど、あらゆる生活状況で市場を監視できます。
暗号通貨市場はいつでも混乱する可能性があります。そのような場合は、マルチ画面をセットアップしたデスクにすぐに移動できます。任意の通貨のウィンドウをクリックすると、反対側の画面の全画面表示で詳細情報をすばやく確認できます。以下は、前回の YCY の血みどろの戦いで撮影した私の最近の写真です。完全に不意を突かれ、顔に手を当ててしまいました。
下記に埋め込まれたデモを試したり、glitch でソースコードを確認したりできます。
セキュリティと権限
Chrome チームは、強力なウェブ プラットフォーム機能へのアクセスを制御するで定義されているコア プリンシプル(ユーザー コントロール、透明性、人間工学など)を使用して、Window Management API を設計して実装しました。Window Management API は、デバイスに接続されている画面に関する新しい情報を公開し、ユーザーの指紋採取サーフェスを増やします。特に、複数の画面がデバイスに常時接続されているユーザーの指紋採取サーフェスは増加します。このプライバシーに関する懸念を軽減するため、公開される画面プロパティは、一般的なプレースメントのユースケースに必要な最小限に制限されています。サイトがマルチスクリーン情報を取得し、他の画面にウィンドウを配置するには、ユーザーの権限が必要です。Chromium は詳細な画面ラベルを返しますが、ブラウザはより簡潔なラベル(または空のラベル)を返すことができます。
ユーザー コントロール
ユーザーは、設定の公開を完全に管理できます。ユーザーは、権限プロンプトを承認または拒否し、ブラウザのサイト情報機能を使用して、以前に付与した権限を取り消すことができます。
エンタープライズ管理
Chrome Enterprise ユーザーは、アトミック ポリシー グループの設定の該当するセクションで説明されているように、Window Management API のいくつかの側面を制御できます。
透明性
Window Management API の使用許可が付与されているかどうかは、ブラウザのサイト情報で公開され、Permissions API でクエリすることもできます。
権限の保持
ブラウザは権限の付与を保持します。この権限は、ブラウザのサイト情報で取り消すことができます。
フィードバック
Chrome チームは、Window Management API の使用感について、皆様のご意見をお聞きしたいと考えております。
API 設計について
API が想定どおりに動作しない点はありますか?または、アイデアを実装するために必要なメソッドやプロパティが不足している場合はどうすればよいですか?セキュリティ モデルに関する質問やコメントがある場合
- 対応する GitHub リポジトリで仕様に関する問題を報告するか、既存の問題にコメントを追加します。
実装に関する問題を報告する
Chrome の実装にバグが見つかりましたか?それとも、実装が仕様と異なるのでしょうか?
- new.crbug.com でバグを報告します。できるだけ詳細な情報を含め、再現手順を簡単に説明してください。[コンポーネント] ボックスに
Blink>Screen>MultiScreen
を入力します。Glitch は、簡単な再現手順をすばやく共有するのに適しています。
API のサポートを表示する
Window Management API を使用する予定はありますか?一般公開されている機能へのサポートは、Chrome チームが機能の優先順位を決める際に役立ち、他のブラウザ ベンダーにその機能のサポートがどれほど重要であるかを示します。
- WICG Discourse スレッドで、どのように使用する予定かをお知らせください。
- ハッシュタグ
#WindowManagement
を使用して @ChromiumDev にツイートを送信し、どこでどのように使用しているかをお知らせください。 - 他のブラウザ ベンダーに API の実装を依頼する。
関連情報
- 仕様案
- 一般向けの説明
- Window Management API デモ | Window Management API デモソース
- Chromium トラッキング バグ
- ChromeStatus.com のエントリ
- 点滅コンポーネント:
Blink>Screen>MultiScreen
- TAG の審査
- テストの目的
謝辞
Window Management API の仕様は、Victor Costan、Joshua Bell、Mike Wasserman によって編集されました。この API は、Mike Wasserman と Adrienne Walker によって実装されました。この記事は、Joe Medley、François Beaufort、Kayce Basques によるレビューを経て公開されました。写真は Laura Torrent Puig 様から提供されました。