إدارة عدة شاشات باستخدام Window Management API

الحصول على معلومات حول الشاشات المرتبطة وتحديد موضع النوافذ بالنسبة إلى شاشات العرض هذه.

Window Management API

تتيح لك واجهة برمجة التطبيقات Window Management API إدراج الشاشات المتصلة بجهازك ووضع النوافذ على شاشات محدّدة.

حالات الاستخدام المقترَحة

تشمل الأمثلة على المواقع الإلكترونية التي قد تستخدم واجهة برمجة التطبيقات هذه ما يلي:

  • بإمكان أدوات تحرير الرسومات ذات النوافذ المتعددة الموجودة في Gimp وضع أدوات تعديل متعددة في نوافذ مواضع دقيقة.
  • يمكن لمكاتب التداول الافتراضية عرض مؤشرات السوق في عدة نوافذ يمكن عرض أي منها في وضع ملء الشاشة.
  • يمكن لتطبيقات عرض الشرائح عرض ملاحظات المحاضر على الشاشة الأساسية الداخلية وعرض العرض على أداة عرض خارجية.

كيفية استخدام واجهة برمجة التطبيقات Window Management API

المشكلة

إنّ الطريقة التي أثبتت فعاليتها للتحكّم في النوافذ، Window.open()، لا تراعي التعامل مع الشاشات الإضافية. مع أنّ بعض جوانب واجهة برمجة التطبيقات هذه تبدو قديمة بعض الشيء، مثل مَعلمة 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. كيف يمكنني إجراء ذلك بشكل عام؟ تبيّن أنّ هناك طريقة أفضل من التخمين. هذه الطريقة هي 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;
});

يمكن للمتصفّح اختيار عرض طلب الحصول على الأذونات ديناميكيًا عند أول محاولة لاستخدام أي طريقة من طرق واجهة برمجة التطبيقات الجديدة. تابع القراءة لمعرفة المزيد.

سمة 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، ذلك بالضبط: يتم تشغيله عند تعديل مجموعة النجوم على الشاشة. (يُرجى ملاحظة أنّ "الشاشات" هي جمع في اسم الحدث). وهذا يعني أنّه يتم تشغيل الحدث كلما تم توصيل شاشة جديدة أو شاشة حالية (بشكل فعلي أو افتراضي في حالة 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، ولكن يمكنك استخدام بديل لها حتى تتمكّن من كتابة الرموز البرمجية باستخدام واجهة برمجة التطبيقات الجديدة فقط:

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

أما الجوانب الأخرى لواجهة برمجة التطبيقات، أي أحداث تغيير الشاشة المختلفة وخاصية screen في FullscreenOptions، فلن يتم تفعيلها مطلقًا أو تجاهلها بصمت على التوالي من قِبل browsers غير المتوافقة.

عرض توضيحي

إذا كنتم أي شيء مثلي، يمكنكم متابعة تطور العملات المشفّرة المختلفة عن كثب. (في الواقع، لا أريد ذلك كثيرًا لأنّني أحب هذا الكوكب، ولكن أفترض فقط أنّني أريد ذلك من أجل هذه المقالة). لتتبُّع العملات المشفّرة التي أملكها، طوّرتُ تطبيق ويب يتيح لي مراقبة الأسواق في جميع مواقف الحياة، مثل الاستراحة على سريري حيث أملك شاشة واحدة جيدة.

شاشة تلفزيون كبيرة في نهاية سرير مع ظهور أرجل الكاتب جزئيًا تظهر على الشاشة طاولة تداول مزيّفة للعملات المشفّرة.
الاسترخاء ومشاهدة الأسواق:

بما أنّ هذه المقالة تتناول العملات المشفّرة، يمكن أن تصبح الأسواق مزدحمة في أي وقت. إذا حدث هذا، يمكنني الانتقال بسرعة إلى مكتبي حيث لدي إعداد متعدد الشاشات. يمكنني النقر فوق نافذة أي عملة ورؤية التفاصيل الكاملة بسرعة في عرض ملء الشاشة على الشاشة المقابلة. في ما يلي صورة حديثة لي تم التقاطها خلال مذبحة YCY الأخيرة. لقد فاجأني تمامًا وتركني أضع يدي على وجهي.

يضع المؤلف يديه على وجهه المذعور ويحدّق في مكتب تداول العملات المشفّرة المزيّف.
أشعر بالذعر، فأنا أشهد مذبحة YCY.

يمكنك تشغيل الإصدار التجريبي المضمّن أدناه، أو الاطّلاع على رمز المصدر على glitch.

الأمان والأذونات

صمَّم فريق Chrome ونفَّذ واجهة برمجة التطبيقات Window Management API باستخدام المبادئ الأساسية المحدّدة في التحكّم في الوصول إلى ميزات النظام الأساسي الفعّال للويب، بما في ذلك التحكّم في المستخدم والشفافية وسهولة الاستخدام. تعرض واجهة برمجة التطبيقات Window Management API معلومات جديدة عن الشاشات المتصلة بالجهاز، ما يزيد من مساحة جمع معلومات بصمة المستخدمين، خاصةً أولئك الذين لديهم شاشات متعددة متصلة بأجهزة باستمرار. للحد من هذه المخاوف المتعلقة بالخصوصية، تقتصر خصائص الشاشة المكشوفة على الحد الأدنى المطلوب لحالات استخدام المواضع الشائعة. يجب الحصول على إذن المستخدم لكي تتمكّن المواقع الإلكترونية من الحصول على معلومات عن الشاشات المتعدّدة ووضع النوافذ على شاشات أخرى. في حين أنّ Chromium يعرض تصنيفات تفصيلية للشاشة، يمكن للمتصفّحات عرض تصنيفات أقل وصفية (أو حتى تصنيفات فارغة).

التحكّم في المستخدم

يمكن للمستخدم التحكّم بشكل كامل في مستوى ظهور الإعداد. ويمكنهم قبول طلب منح الإذن أو رفضه، وإبطال إذن سبق منحه من خلال ميزة معلومات الموقع الإلكتروني في المتصفّح.

التحكّم في المؤسسة

يمكن لمستخدمي Chrome Enterprise التحكّم في عدة جوانب من واجهة برمجة التطبيقات Window Management API كما هو موضح في القسم ذي الصلة من إعدادات مجموعات السياسات الأساسية.

الشفافية

يتم عرض ما إذا تم منح الإذن لاستخدام واجهة برمجة التطبيقات Window Management API في معلومات الموقع الإلكتروني للمتصفّح، ويمكن أيضًا إجراء طلب بحث من خلال Permissions API.

الاحتفاظ بالأذونات

يحفظ المتصفّح أذونات الاستخدام الممنوحة. يمكن إلغاء الإذن من خلال معلومات الموقع الإلكتروني في المتصفّح.

ملاحظات

يريد فريق Chrome معرفة تجاربك مع واجهة برمجة التطبيقات Window Management API.

أخبِرنا عن تصميم واجهة برمجة التطبيقات.

هل هناك مشكلة في واجهة برمجة التطبيقات لا تعمل على النحو المتوقّع؟ أو هل هناك طرق أو خصائص مفقودة تحتاجها لتنفيذ فكرتك؟ هل لديك سؤال أو تعليق بشأن نموذج الأمان؟

  • يُرجى الإبلاغ عن مشكلة في المواصفات بشأن مستودع GitHub ذي الصلة، أو إضافة أفكارك إلى مشكلة حالية.

الإبلاغ عن مشكلة في التنفيذ

هل واجهت مشكلة في التنفيذ في Chrome؟ أم أنّ عملية التنفيذ مختلفة عن المواصفات؟

  • يُرجى الإبلاغ عن الخطأ على new.crbug.com. وتأكّد من تضمين أكبر قدر ممكن من التفاصيل، وإرشادات بسيطة لإعادة إنتاجه، وأدخِل الرمز Blink>Screen>MultiScreen في مربّع المكونات. يُعدّ تطبيق Glitch مثاليًا لمشاركة عمليات إعادة الإنتاج بسرعة وسهولة.

إظهار الدعم لواجهة برمجة التطبيقات

هل تخطّط لاستخدام واجهة برمجة التطبيقات Window Management API؟ يساعد دعمك العلني فريق Chrome في تحديد أولويات الميزات ويُظهر لموفّري المتصفّحات الآخرين مدى أهمية توفير هذه الميزات.

روابط مفيدة

الشكر والتقدير

تم تعديل مواصفات واجهة برمجة التطبيقات Window Management API بواسطة كلٍّ من Victor Costan وJoshua Bell و Mike Wasserman. نفَّذ واجهة برمجة التطبيقات كلّ من مايك واسرمان و أدريان ووكر. تمت مراجعة هذه المقالة بواسطة جو ميدلي وفرانسوا بوفورت وكايس باسك. نشكر Laura Torrent Puig على الصور.