ניהול מספר מסכים באמצעות window Management API

לקבל מידע על מסכים מחוברים ולמקם חלונות ביחס למסכים האלה.

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

כמו רוב האנשים שעובדים בתחום הטכנולוגיה, נאלצתי להתאים את עצמי למציאות החדשה של העבודה ולהגדיר את המשרד הביתי האישי שלי. המכרה נראה כמו בתמונה שלמטה (אם אתם מעוניינים, תוכלו לקרוא את הפרטים המלאים על ההגדרה שלי). ה-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;
});

הדפדפן יכול להציג את בקשת ההרשאה באופן דינמי בניסיון הראשון להשתמש באחת מהשיטות של ה-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, עושה בדיוק את זה: הוא מופעל בכל פעם שמתבצע שינוי בקבוצת האפליקציות במסך. (שימו לב ששם האירוע כולל את הצורה הרבים של 'מסכים'). כלומר, האירוע מופעל בכל פעם שמחברים או מנתקים מסך חדש או מסך קיים (פיזית או באופן וירטואלי במקרה של 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);
}

פוליפיל

אי אפשר להשתמש ב-polyfill ל-Window Management API, אבל אפשר להשתמש ב-shim כדי לכתוב קוד רק ל-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, פשוט לא יופעלו או יתעלמו בהתאמה בדפדפנים שלא תומכים ב-API.

הדגמה (דמו)

אם אתם כמוני, תוכלו לפקח מקרוב על ההתפתחות של המטבעות הווירטואליים השונים. (במציאות, ממש לא כי אני אוהב את הפלנטה הזו, אבל לצורך המאמר, נניח שכן). כדי לעקוב אחרי המטבעות הווירטואליים שבבעלותי, פיתחתי אפליקציית אינטרנט שמאפשרת לי לצפות בשווקים בכל מצבי החיים, למשל, מבלי לצאת מהמיטה, כשמתקינים מסך יחיד בצורה סבירה.

מסך טלוויזיה ענק בקצה מיטה, עם רגליים גלויות חלקן של המחבר. במסך מוצג דסק מסחר של מטבעות וירטואליים.
רגיעה וצפייה בשווקים.

מכיוון שמדובר בקריפטו, השווקים יכולים להיות תנודתיים בכל שלב. במקרה כזה, אוכל לעבור במהירות לשולחן שלי שבו יש לי הגדרה של כמה מסכים. אפשר ללחוץ על חלון של כל מטבע ולראות במהירות את הפרטים המלאים בתצוגת מסך מלא במסך השני. לפניך תמונה שלי שצולמה לאחרונה במהלך קרב השבטים האחרון ב-YCY. זה תפס אותי לגמרי לא מוכן, והידיים שלי היו על הפנים.

הסופר מרים את הידיים על פרצוף מבוהל ומביט בדסק לסחר במטבעות וירטואליים.
בבהלה, צופה במרחץ הדמים של YCY.

אתם יכולים לשחק עם ההדגמה שמוטמעת למטה, או לבדוק את קוד המקור שלה במקרה של תקלה.

אבטחה והרשאות

צוות Chrome תכנן והטמיע את Window Management API בהתאם לעקרונות המרכזיים שמוגדרים במאמר בקרת הגישה לתכונות עוצמתיות של פלטפורמת אינטרנט, כולל שליטה על ידי משתמשים, שקיפות וארגונומיה. ממשק ה-API של ניהול החלונות חושף מידע חדש על המסכים שמחוברים למכשיר, ומגדיל את השטח של יצירת טביעות האצבעות בקרב המשתמשים, במיוחד כאלה עם מספר מסכים שמחוברים באופן עקבי למכשירים שלהם. כדי לצמצם את החשיפה של הפרטים האלה, מאפייני המסך שנחשפים מוגבלים למינימום הנדרש לתרחישי שימוש נפוצים של מיקומי מודעות. כדי לאתרים לקבל מידע על כמה מסכים ולמקם חלונות במסכים אחרים, נדרשת הרשאה מהמשתמשים. ב-Chromium מוצגות תוויות מפורטות של המסך, אבל הדפדפנים יכולים להציג תוויות פחות תיאוריות (או אפילו ריקות).

שליטת משתמשים

למשתמש יש שליטה מלאה על החשיפה של ההגדרה שלו. הם יכולים לאשר או לדחות את בקשת ההרשאה, ולבטל הרשאה שניתנה בעבר דרך התכונה 'מידע על האתר' בדפדפן.

בקרה ארגונית

משתמשי Chrome Enterprise יכולים לשלוט בכמה היבטים של Window Management API, כפי שמתואר בקטע הרלוונטי בהגדרות של Atomic Policy Groups.

שקיפות

אם ניתנה ההרשאה להשתמש ב-Window Management API, אנחנו נחשפים בפרטי האתר של הדפדפן ואפשר גם לשלוח שאילתות דרך Permissions API.

התמדת ההרשאות

הדפדפן שומר את ההרשאות שהוקצו. אפשר לבטל את ההרשאה דרך פרטי האתר של הדפדפן.

משוב

צוות Chrome רוצה לשמוע על החוויה שלכם עם Window Management API.

מתארים את עיצוב ה-API

האם יש משהו ב-API שלא פועל כמצופה? או אולי חסרות שיטות או מאפיינים שאתם צריכים כדי להטמיע את הרעיון? יש לכם שאלות או הערות לגבי מודל האבטחה?

  • אפשר לשלוח דיווח על בעיה במפרט במאגר GitHub המתאים, או להוסיף את המחשבות שלכם לבעיה קיימת.

דיווח על בעיה בהטמעה

מצאתם באג בהטמעה של Chrome? או שההטמעה שונה מהמפרט?

  • שולחים דיווח על באג בכתובת new.crbug.com. חשוב לכלול כמה שיותר פרטים, הוראות פשוטות לשחזור הבעיה ולהזין את הערך Blink>Screen>MultiScreen בתיבה Components. Glitch הוא כלי מצוין לשיתוף שחזור מהיר וקל של באגים.

תמיכה ב-API

האם אתם מתכננים להשתמש ב-Window Management API? התמיכה הציבורית שלכם עוזרת לצוות Chrome לתת עדיפות לתכונות, ומראה לספקי דפדפנים אחרים כמה חשובה התמיכה בהן.

  • אתם יכולים לספר איך אתם מתכננים להשתמש בו בשרשור ב-Discourse של WICG.
  • אפשר לשלוח ציוץ אל @ChromiumDev באמצעות ההאשטאג #WindowManagement ולספר לנו איפה ואיך אתם משתמשים בו.
  • לבקש מספקי דפדפנים אחרים להטמיע את ה-API.

קישורים שימושיים

תודות

ויקטור קוסטן, ג'ושועה בל ומייק ווסמרמן ערכו את המפרט של Window Management API. ה-API הוטמע על ידי Mike Wasserman ו-Adrienne Walker. המאמר הזה נבדק על ידי ג'ו מדלי, פרנסואה ביופור וקייס בסקי. התמונות באדיבות Laura Torrent Puig.