Pencere Yönetimi API'si ile birden fazla ekranı yönetme

Bağlı ekranlar hakkında bilgi edinme ve pencereleri bu ekranlara göre konumlandırma

Yayınlanma tarihi: 14 Eylül 2020

Window Management API

Pencere Yönetimi API'si, makinenize bağlı ekranları listelemenize ve pencereleri belirli ekranlara yerleştirmenize olanak tanır.

Önerilen kullanım alanları

Bu API'yi kullanabilecek sitelere örnek olarak şunlar verilebilir:

  • Gimp gibi çok pencereli grafik düzenleyiciler, çeşitli düzenleme araçlarını doğru konumlandırılmış pencerelere yerleştirebilir.
  • Sanal ticaret masaları, piyasa trendlerini birden fazla pencerede gösterebilir. Bu pencerelerin herhangi biri tam ekran modunda görüntülenebilir.
  • Slayt gösterisi uygulamaları, konuşmacı notlarını dahili birincil ekranda, sunuyu ise harici bir projektörde gösterebilir.

Window Management API'yi kullanma

Pencereleri kontrol etmek için uzun süredir kullanılan yaklaşım Window.open() maalesef ek ekranlardan haberdar değil. Bu API'nin bazı yönleri (ör. windowFeatures DOMString parametresi) biraz eski görünse de yıllardır bize iyi hizmet vermiştir. Bir pencerenin konumunu belirtmek için koordinatları left ve top (veya sırasıyla screenX ve screenY) olarak, istenen boyutu ise width ve height (veya sırasıyla innerWidth ve innerHeight) olarak iletebilirsiniz. Örneğin, soldan 50 piksel ve üstten 50 piksel uzaklıkta 400×300 boyutlarında bir pencere açmak için kullanabileceğiniz kod şudur:

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

window.screen özelliğine bakarak geçerli ekran hakkında bilgi edinebilirsiniz. Bu özellik, Screen nesnesi döndürür. MacBook Pro 13" cihazımdaki çıkış:

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
*/

Teknoloji sektöründe çalışan çoğu kişi gibi ben de 2020'deki çalışma koşullarına uyum sağlamak ve evimde kişisel ofisimi kurmak zorunda kaldım. Benimki fotoğraftaki gibi görünüyor. (İlgileniyorsanız kurulumumla ilgili tüm ayrıntıları okuyabilirsiniz.) MacBook'umun yanındaki iPad, Sidecar ile dizüstü bilgisayara bağlı. Bu sayede, gerektiğinde iPad'i hızlıca ikinci bir ekrana dönüştürebiliyorum.

İki sandalyenin üzerinde okul bankı. Okul sırasının üzerinde, dizüstü bilgisayarı destekleyen ayakkabı kutuları ve etrafında iki iPad var.
Çok ekranlı kurulum.

Daha büyük ekrandan yararlanmak istiyorsam kod örneğindeki pop-up'ı ikinci ekrana yerleştirebilirim. Ben şöyle yapıyorum:

popup.moveTo(2500, 50);

İkinci ekranın boyutlarını bilmenin bir yolu olmadığından bu, kabaca bir tahmindir. window.screen cihazındaki bilgiler yalnızca yerleşik ekranı kapsar, iPad ekranını kapsamaz. Yerleşik ekranın bildirilen width değeri 1680 pikseldi. Bu nedenle, pencereyi iPad'e taşımak için 2500 piksele geçmek işe yarayabilir. Çünkü ben, iPad'in MacBook'umun sağ tarafında bulunduğunu biliyorum. How can I do this in the general case? Tahmin etmek yerine daha iyi bir yol var. Bu yöntem, Pencere Yönetimi API'sidir.

Özellik algılama

Window Management API'nin desteklenip desteklenmediğini kontrol etmek için şunu kullanın:

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

window-management izni

Pencere Yönetimi API'sini kullanmadan önce kullanıcıdan izin istemem gerekiyor. window-management izni, Permissions API ile şu şekilde sorgulanabilir:

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

Eski ve yeni izin adını içeren tarayıcılar kullanılırken izin isterken örnekteki gibi savunma amaçlı kod kullandığınızdan emin olun.

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

Tarayıcı, yeni API'nin yöntemlerinden herhangi birini kullanma girişiminde izin istemini dinamik olarak göstermeyi seçebilir. Daha fazla bilgi edinmek için okumaya devam edin.

window.screen.isExtended özelliği

Cihazıma birden fazla ekranın bağlanıp bağlanmadığını öğrenmek için window.screen.isExtended özelliğine erişiyorum. true veya false değerini döndürür. Kurulumum için true değerini döndürüyor.

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

getScreenDetails() yöntemi

Mevcut kurulumun çok ekranlı olduğunu öğrendiğime göre, Window.getScreenDetails() kullanarak ikinci ekran hakkında daha fazla bilgi edinebilirim. Bu işlevi çağırdığımda, site ekranımda pencereler açıp yerleştirebilir mi diye soran bir izin istemi gösteriliyor. İşlev, ScreenDetailed nesnesiyle çözümlenen bir söz döndürür. Bağlı bir iPad'in bulunduğu MacBook Pro 13'ümde, bu, iki ScreenDetailed nesnesi içeren bir screens alanı içerir:

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
  }]
}
*/

Bağlı ekranlarla ilgili bilgiler screens dizisinde yer alır. iPad için left değerinin 1680 ile başladığını unutmayın. Bu değer, yerleşik ekranın width değeridir. Bu sayede, ekranların mantıksal olarak nasıl düzenlendiğini (yan yana, üst üste vb.) tam olarak belirleyebilirim. Ayrıca, her ekranın isInternal veya isPrimary olup olmadığını gösteren veriler de mevcuttur. Yerleşik ekranın birincil ekran olması gerekmediğini unutmayın.

currentScreen alanı, mevcut window.screen ile eşleşen canlı bir nesnedir. Nesne, ekranlar arası pencere yerleşimlerinde veya cihaz değişikliklerinde güncellenir.

screenschange etkinliği

Şu anda eksik olan tek şey, ekran kurulumumun değiştiğini algılamanın bir yoludur. Yeni bir etkinlik olan screenschange, tam olarak bunu yapar: Ekran takımyıldızı her değiştirildiğinde tetiklenir. ("Ekranlar"ın etkinlik adında çoğul olduğuna dikkat edin.) Bu, yeni bir ekran veya mevcut bir ekran (Sidecar durumunda fiziksel ya da sanal olarak) takıldığında veya çıkarıldığında etkinliğin tetiklendiği anlamına gelir.

Yeni ekran ayrıntılarını eşzamansız olarak aramanız gerekir. screenschange etkinliği bu verileri sağlamaz. Ekran ayrıntılarını aramak için önbelleğe alınmış bir Screens arayüzünden canlı nesneyi kullanın.

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 etkinliği

Yalnızca mevcut ekrandaki değişikliklerle (yani canlı nesnenin değeri currentScreen) ilgileniyorsam currentscreenchange etkinliğini dinleyebilirim.

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

change etkinliği

Son olarak, yalnızca belirli bir ekrandaki değişikliklerle ilgileniyorsam o ekranın change etkinliğini dinleyebilirim.

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

Yeni tam ekran seçenekleri

Şimdiye kadar, uygun şekilde adlandırılmış requestFullScreen() yöntemiyle öğelerin tam ekran modunda gösterilmesini isteyebiliyordunuz. Yöntem, options parametresini alır. Bu parametreye FullscreenOptions değerini iletebilirsiniz. Şu ana kadar tek özelliği navigationUI oldu. Window Management API, tam ekran görünümünün hangi ekranda başlatılacağını belirlemenize olanak tanıyan yeni bir screen özelliği ekler. Örneğin, birincil ekranı tam ekran yapmak istiyorsanız:

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

Window Management API'yi polyfill yapmak mümkün değildir ancak şeklini shim yaparak yalnızca yeni API'ye karşı kod yazabilirsiniz:

if (!('getScreenDetails' in window)) {
  // Returning a one-element array with the current screen,
  // noting that there might be more.
  window.getScreenDetails = as>ync () = [window.screen];
  // Set to `false`, noting that this might be a lie.
  window.screen.isExtended = false;
}

API'nin diğer yönleri (yani çeşitli ekran değişikliği etkinlikleri ve FullscreenOptions öğesinin screen özelliği) hiçbir zaman tetiklenmez veya desteklemeyen tarayıcılar tarafından sessizce yoksayılır.

Demo

Çeşitli kripto para birimlerinin gelişimini yakından takip ederseniz uygulamamdaki tek ekran kurulumuyla piyasaları yatağınızın rahatlığında izleyebilirsiniz. (Bu gezegeni çok sevdiğim için bu durumdan hiç hoşlanmıyorum ancak bu makalenin konusu gereği, bu durumdan hoşlandığımı varsayalım.)

Yatağın ucunda, yazarın bacaklarının kısmen göründüğü büyük bir TV ekranı. Ekranda sahte bir kripto para birimi işlem masası gösteriliyor.
Rahatlayıp piyasaları izliyorum.

Kripto para piyasalarıyla ilgili bu durum, piyasaların herhangi bir zamanda karışık hale gelmesine neden olabilir. Bu durumda, çoklu ekran kurulumumun olduğu masama hızlıca geçebilirim. Herhangi bir para biriminin penceresini tıklayarak tam ekran görünümünde tüm ayrıntıları hızlıca görebiliyorum. YCY kan banyosu sırasında çekilen son fotoğrafımı paylaşıyorum. Bu durum beni tamamen hazırlıksız yakaladı ve ellerimle yüzümü kapatmama neden oldu.

Me, panicky, witnessing the YCY bloodbath.

Demoyu inceleyin veya GitHub'daki kaynak kodunu görüntüleyin.

Güvenlik ve izinler

Chrome Ekibi, Window Management API'yi Güçlü Web Platformu Özelliklerine Erişimi Kontrol Etme'de tanımlanan temel ilkeleri (kullanıcı kontrolü, şeffaflık ve ergonomi dahil) kullanarak tasarlayıp uygulamıştır. Pencere Yönetimi API'si, bir cihaza bağlı ekranlarla ilgili yeni bilgiler sunarak kullanıcıların parmak izi yüzeyini artırır. Bu durum, özellikle cihazlarına sürekli olarak birden fazla ekran bağlayan kullanıcılar için geçerlidir. Bu gizlilik endişesini gidermek için, gösterilen ekran özellikleri yaygın yerleşim kullanım alanları için gereken minimum düzeyle sınırlıdır.

Sitelerin çoklu ekran bilgisi alması ve pencereleri diğer ekranlara yerleştirmesi için kullanıcı izni gerekir. Chromium, ayrıntılı ekran etiketleri döndürürken tarayıcılar daha az açıklayıcı (hatta boş etiketler) döndürmekte serbesttir.

Kullanıcı denetimi

Kullanıcı, kurulumunun görünürlüğü üzerinde tam denetime sahiptir. Kullanıcılar izin istemini kabul edebilir veya reddedebilir ve daha önce verilen bir izni tarayıcıdaki site bilgileri özelliği aracılığıyla iptal edebilir.

Kurumsal kontrol

Chrome Enterprise kullanıcıları, Atomic Policy Groups ayarlarının ilgili bölümünde belirtildiği gibi Pencere Yönetimi API'sinin çeşitli yönlerini kontrol edebilir.

Şeffaflık

Pencere Yönetimi API'sini kullanma izninin verilip verilmediği, tarayıcının site bilgilerinde gösterilir ve Permissions API ile de sorgulanabilir.

İzin kalıcılığı

Tarayıcı, izinleri kalıcı olarak saklar. İzin, tarayıcının site bilgileri bölümünden iptal edilebilir.

Geri bildirim

API'nin beklendiğiniz gibi çalışmayan bir yönü var mı? Yoksa fikrinizi uygulamak için eksik yöntemler veya özellikler mi var? Güvenlik modeliyle ilgili sorunuz veya yorumunuz mu var?

API'ye desteğinizi gösterme

Pencere Yönetimi API'sini kullanmayı planlıyor musunuz? Herkese açık desteğiniz, Chrome ekibinin özelliklere öncelik vermesine yardımcı olur ve diğer tarayıcı satıcılarına bu özelliklerin desteklenmesinin ne kadar önemli olduğunu gösterir.

Kaynaklar

Teşekkür

Window Management API spesifikasyonu Victor Costan, Joshua Bell ve Mike Wasserman tarafından düzenlendi. API, Mike Wasserman ve Adrienne Walker tarafından uygulandı. Bu makale Joe Medley, François Beaufort ve Kayce Basques tarafından incelenmiştir. Fotoğraflar için Laura Torrent Puig'e teşekkür ederiz.