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

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

ממשק API לניהול חלונות

באמצעות ה-Window Management API אפשר לספור את המסכים שמחוברים למכונה שלך ולמקם חלונות במסכים מסוימים.

הצעות לתרחישים לדוגמה

דוגמאות לאתרים שבהם אפשר להשתמש ב-API הזה:

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

איך משתמשים ב-Window Management API

הבעיה

הגישה שנבדקה בזמן לשליטה בחלונות, לצערי Window.open(), לא מודעים למסכים נוספים. היבטים מסוימים של ה-API הזה נראים קצת מיושנים, למשל windowFeatures DOMString, למרות זאת הוא שימש אותנו במשך השנים. כדי לציין את שם החלון position, אפשר להעביר 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 לניהול חלונות.

זיהוי תכונות

כדי לבדוק אם יש תמיכה ב-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 ממשק ה-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, כלומר אירועי שינוי המסך השונים והמאפיין screen של FullscreenOptions אף פעם לא יפעל או יתעלם מהודעה שקטה, בהתאמה בדפדפנים שאינם תומכים.

הדגמה (דמו)

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

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

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

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

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

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

צוות Chrome תכנן והטמיע את ממשק ה-API לניהול חלונות באמצעות הליבה את העקרונות שמוגדרים בשליטה בגישה לתכונות חזקות של פלטפורמת האינטרנט, כולל שליטה של משתמשים, שקיפות וארגונומיה. ממשק ה-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.
  • שליחת ציוץ אל @ChromiumDev בעזרת hashtag #WindowManagement וגם ספר לנו איפה ואיך אתה משתמש בו.
  • תוכלו לבקש מספקי דפדפנים אחרים להטמיע את ה-API.

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

אישורים

המפרט של window Management API נערך על ידי ויקטור קוסטה, Joshua Bell, וגם מייק וסרמן. ה-API הוטמע על ידי מייק וסרמן וגם אדריאן ווקר. המאמר הזה נבדק על ידי Joe Medley, François Beaufort, ו-Kayce Basques. תודה ללורה טורנט פויג על התמונות.