مدیریت چندین نمایشگر با رابط برنامه‌نویسی کاربردی مدیریت پنجره

اطلاعاتی در مورد نمایشگرهای متصل و موقعیت پنجره‌ها نسبت به آن نمایشگرها دریافت کنید.

منتشر شده: ۱۴ سپتامبر ۲۰۲۰

رابط برنامه‌نویسی مدیریت پنجره

رابط برنامه‌نویسی کاربردی مدیریت پنجره (Window Management API) به شما امکان می‌دهد نمایشگرهای متصل به دستگاه خود را بشمارید و پنجره‌ها را روی صفحات خاص قرار دهید.

موارد استفاده پیشنهادی

نمونه‌هایی از سایت‌هایی که ممکن است از این API استفاده کنند عبارتند از:

  • ویرایشگرهای گرافیکی چند پنجره‌ای مانند Gimp می‌توانند ابزارهای ویرایشی مختلفی را در پنجره‌هایی که به طور دقیق در موقعیت‌های مناسب قرار گرفته‌اند، قرار دهند.
  • میزهای معاملاتی مجازی می‌توانند روندهای بازار را در چندین پنجره نشان دهند که هر یک از آنها را می‌توان در حالت تمام صفحه مشاهده کرد.
  • برنامه‌های نمایش اسلاید می‌توانند یادداشت‌های گوینده را روی صفحه اصلی داخلی و ارائه را روی یک پروژکتور خارجی نشان دهند.

نحوه استفاده از 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
*/

مثل اکثر افرادی که در حوزه فناوری کار می‌کنند، من هم مجبور شدم خودم را با واقعیت کار در سال ۲۰۲۰ وفق دهم و دفتر کار خانگی شخصی‌ام را راه‌اندازی کنم. دفتر کار من شبیه عکس است (اگر علاقه‌مند هستید، می‌توانید جزئیات کامل مربوط به چیدمان من را بخوانید). آیپد کنار مک‌بوکم از طریق Sidecar به لپ‌تاپ متصل است، بنابراین هر زمان که نیاز داشته باشم، می‌توانم به سرعت آیپد را به صفحه نمایش دوم تبدیل کنم.

نیمکت مدرسه روی دو صندلی. بالای نیمکت مدرسه جعبه‌های کفش قرار دارند که یک لپ‌تاپ را نگه می‌دارند و دو آی‌پد آن را احاطه کرده‌اند.
یک تنظیمات چند صفحه‌ای.

اگر بخواهم از صفحه نمایش بزرگتر استفاده کنم، می‌توانم پنجره بازشو را از نمونه کد روی صفحه نمایش دوم قرار دهم. من این کار را به این صورت انجام می‌دهم:

popup.moveTo(2500, 50);

این یک حدس تقریبی است، زیرا هیچ راهی برای دانستن ابعاد صفحه نمایش دوم وجود ندارد. اطلاعات window.screen فقط صفحه نمایش داخلی را پوشش می‌دهد، اما صفحه نمایش آیپد را نه. width گزارش شده صفحه نمایش داخلی 1680 پیکسل بود، بنابراین تغییر به 2500 پیکسل ممکن است برای انتقال پنجره به آیپد جواب بدهد، زیرا اتفاقاً می‌دانم که در سمت راست مک‌بوک من قرار دارد. در حالت کلی چگونه می‌توانم این کار را انجام دهم؟ معلوم شد که راه بهتری از حدس زدن وجود دارد. این راه API مدیریت پنجره است.

تشخیص ویژگی

برای بررسی اینکه آیا API مدیریت پنجره پشتیبانی می‌شود، از دستور زیر استفاده کنید:

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

مجوز window-management

قبل از اینکه بتوانم از API مدیریت پنجره استفاده کنم، باید از کاربر اجازه انجام این کار را بگیرم. اجازه window-management را می‌توان با 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() اطلاعات بیشتری در مورد صفحه نمایش دوم به دست آورم. فراخوانی این تابع، یک درخواست مجوز نمایش می‌دهد که از من می‌پرسد آیا سایت می‌تواند باز شود و پنجره‌هایی را روی صفحه نمایش من قرار دهد یا خیر. این تابع، یک promise را برمی‌گرداند که با یک شیء 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 ، دقیقاً همین کار را انجام می‌دهد: هر زمان که مجموعه صفحه نمایش تغییر کند، فعال می‌شود. (توجه داشته باشید که "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 بوده است. 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);
}

پلی‌فیل

امکان چندپر کردن API مدیریت پنجره وجود ندارد، اما می‌توانید شکل آن را تغییر دهید تا بتوانید منحصراً برای API جدید کدنویسی کنید:

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، یعنی رویدادهای مختلف تغییر صفحه و ویژگی screen از FullscreenOptions ، هرگز اجرا نمی‌شوند یا به ترتیب توسط مرورگرهایی که از آنها پشتیبانی نمی‌کنند، نادیده گرفته می‌شوند.

نسخه آزمایشی

اگر از نزدیک روند توسعه ارزهای دیجیتال مختلف را زیر نظر داشته باشید، می‌توانید بازارها را از روی تخت راحت خود و با یک صفحه نمایش در برنامه من زیر نظر داشته باشید. (من واقعاً این کار را نمی‌کنم، چون عاشق این سیاره هستم، اما برای این مقاله، فرض کنید که این کار را می‌کردم.)

صفحه تلویزیون بزرگی در انتهای تخت خواب که پاهای نویسنده تا حدودی دیده می‌شود. روی صفحه، یک میز معاملاتی ارز دیجیتال جعلی قرار دارد.
استراحت و تماشای بازارها.

این موضوع در مورد ارزهای دیجیتال است و بازارها می‌توانند در هر زمانی متلاطم شوند. اگر این اتفاق بیفتد، می‌توانم به سرعت به میزم بروم و در آنجا چند صفحه نمایش داشته باشم. می‌توانم روی پنجره هر ارزی کلیک کنم و به سرعت جزئیات کامل را در نمای تمام صفحه در صفحه مقابل ببینم. این عکسی است که اخیراً از من در آخرین بحران YCY گرفته شده است. کاملاً غافلگیر شدم و دستانم را روی صورتم گذاشتم.

من، وحشت‌زده، شاهد حمام خون YCY هستم.

با نسخه آزمایشی کار کنید، یا کد منبع آن را در گیت‌هاب ببینید.

امنیت و مجوزها

تیم کروم، API مدیریت پنجره را با استفاده از اصول اصلی تعریف‌شده در «کنترل دسترسی به ویژگی‌های قدرتمند پلتفرم وب» ، از جمله کنترل کاربر، شفافیت و ارگونومی، طراحی و پیاده‌سازی کرده است. API مدیریت پنجره، اطلاعات جدیدی در مورد صفحات نمایش متصل به یک دستگاه را افشا می‌کند و سطح شناسایی کاربران، به‌ویژه آن‌هایی که چندین صفحه نمایش به‌طور مداوم به دستگاه‌های خود متصل هستند را افزایش می‌دهد. به‌عنوان یکی از راهکارهای کاهش این نگرانی در مورد حریم خصوصی، ویژگی‌های صفحه نمایش در معرض نمایش به حداقل مورد نیاز برای موارد استفاده رایج از قرارگیری صفحه نمایش محدود می‌شود.

برای اینکه سایت‌ها بتوانند اطلاعات چندصفحه‌ای را دریافت کنند و پنجره‌ها را روی صفحه‌های دیگر قرار دهند، اجازه کاربر لازم است. در حالی که کرومیوم برچسب‌های صفحه نمایش با جزئیات را برمی‌گرداند، مرورگرها می‌توانند برچسب‌های کم‌توضیح‌تر (یا حتی خالی) را برگردانند.

کنترل کاربر

کاربر کنترل کامل افشای تنظیمات خود را دارد. او می‌تواند درخواست مجوز را بپذیرد یا رد کند و از طریق ویژگی اطلاعات سایت در مرورگر، مجوزی را که قبلاً اعطا شده است، لغو کند.

کنترل سازمانی

کاربران Chrome Enterprise می‌توانند چندین جنبه از رابط برنامه‌نویسی کاربردی مدیریت پنجره (Window Management API) را همانطور که در بخش مربوطه از تنظیمات گروه‌های سیاست اتمی (Atomic Policy Groups) ذکر شده است، کنترل کنند.

شفافیت

اینکه آیا مجوز استفاده از API مدیریت پنجره اعطا شده است یا خیر، در اطلاعات سایت مرورگر نمایش داده می‌شود و همچنین با API مجوزها قابل استعلام است.

تداوم مجوز

مرورگر همچنان به اعطای مجوز ادامه می‌دهد. این مجوز می‌تواند از طریق اطلاعات سایت مرورگر لغو شود.

بازخورد

آیا چیزی در مورد API وجود دارد که آنطور که انتظار داشتید کار نمی‌کند؟ یا متدها یا ویژگی‌هایی که برای پیاده‌سازی ایده‌تان به آنها نیاز دارید، وجود ندارند؟ در مورد مدل امنیتی سؤال یا نظری دارید؟

نمایش پشتیبانی از API

آیا قصد دارید از API مدیریت پنجره استفاده کنید؟ حمایت عمومی شما به تیم کروم کمک می‌کند تا ویژگی‌ها را اولویت‌بندی کنند و به سایر فروشندگان مرورگر نشان می‌دهد که پشتیبانی از آنها چقدر حیاتی است.

  • نحوه‌ی استفاده از آن را در تاپیک گفتمان WICG به اشتراک بگذارید.
  • با استفاده از هشتگ #WindowManagement به آدرس @ChromiumDev توییت کنید و به ما بگویید که کجا و چگونه از آن استفاده می‌کنید.
  • از سایر فروشندگان مرورگر بخواهید که API را پیاده‌سازی کنند.

منابع

تقدیرنامه‌ها

مشخصات API مدیریت پنجره توسط ویکتور کاستان ، جاشوا بل و مایک واسرمن ویرایش شده است. این API توسط مایک واسرمن و آدرین واکر پیاده‌سازی شده است. این API توسط جو مدلی ، فرانسوا بوفورت و کیس باسک بررسی شده است. با تشکر از لورا تورنت پویگ برای عکس‌ها.