Skip to content

Панель на каждом подключённом дисплее - #60

Merged
akalikbergenov merged 5 commits into
mainfrom
integrate/multi-display
Aug 24, 2026
Merged

Панель на каждом подключённом дисплее#60
akalikbergenov merged 5 commits into
mainfrom
integrate/multi-display

Conversation

@akalikbergenov

Copy link
Copy Markdown
Owner

Closes #3.

Четыре коммита про чёлку плюс пятый — встреча с тем, что приехало в main за сегодня.

Что делают первые четыре

  • NotchViewModel стал общим состоянием приложения, а всё, что относится к одному экрану
    (открыта ли панель, тянут ли файл, держит ли клавиатуру), вынесено в PanelState;
    NotchController держит по NotchScreenPanel на дисплей, сверяя их по стабильному
    CGDirectDisplayID, а не по индексу в NSScreen.screens.
  • Синтетическая чёлка на маке без выреза открывается так же, как настоящая.
  • Глубина зоны решается по фактическим иконкам меню-бара, а не по типу чёлки — то самое
    перекрытие пунктов меню из На маке без челки синтетическая челка занимает середину меню-бара #3.
  • В замер попадают именно иконки меню-бара, а не любое окно на его уровне.
  • В настройках появился переключатель «Показывать на всех дисплеях».

Что пришлось разрешить руками

Единственный конфликт — NotchController: #44 чинил залипание раскрытой панели в старой,
односпановой архитектуре, которой здесь больше нет. Порядок «сначала клавиатура, потом свёртка»
в новой уже был и сделан аккуратнее — через openGeneration. Не было второй половины: после #44
acceptsKeyboard больше не отдаёт ключ сам, это делает явный releaseKey(), и в новой
архитектуре его никто не звал — панель осталась бы с клавиатурой. Перенёс releaseKey() и запрос
на перерисовку в NotchScreenPanel.collapse() и в setKeyboard(false) для закрытой панели.

Остальные восемь сегодняшних правок сошлись без конфликтов.

Проверено локально: swift build, ./Scripts/bundle.sh release, ./Scripts/test-helper.sh
(хелпер ответил живым треком), проверка ключей перевода — чисто, 70 ключей.

🤖 Generated with Claude Code

akalikbergenov and others added 5 commits August 17, 2026 00:40
Разрез проходит по курсору: он в один момент времени ровно на одном
экране, поэтому «открыта», «на неё тянут файл» и «держит клавиатуру»
переезжают в PanelState, по одному на дисплей, а вкладка, хранилища и
сервисы остаются общими в NotchViewModel — одна история буфера, один
perl-хелпер Now Playing.

Экраны сверяются по CGDirectDisplayID, а не по месту в NSScreen.screens:
этот массив на каждую переконфигурацию выдаёт новые объекты и может их
переставить. Дисплей, чья чёлка не сдвинулась, сохраняет свою панель
открытой. Зеркальные пропускаются — вторая панель поверх той же картинки.

Телесуфлёр держит открытым один экран, тот, с которого запустили: пин на
всех оставил бы панель раскрытой там, куда никто не смотрит. Если этот
дисплей отключили, дубль заканчивается — читать больше некому.

Настройки → «Дисплеи» сворачивают всё обратно к одному экрану: с
физической чёлкой, если она есть, иначе к главному. Применяется сразу.

Архитектура разреза — из PR #13.

Co-Authored-By: zhd-dm <64752156+zhd-dm@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Узкая полоска в 8 pt и ожидание в 300 мс написаны под маки без чёлки,
где синтетическая лежит на работающем меню-баре и под ней иконки
статус-итемов, в которые целится курсор. Условием было «не физическая»,
хотя причина — «под ней меню-бар».

На внешнем мониторе без отдельных Spaces меню-бара нет вовсе:
visibleFrame доходит до верхней кромки. Осторожность там ничего не
защищала, а стоила всего — панель рисовалась высотой 24 pt и отвечала
только верхними 8, и открывалась вшестеро дольше встроенной.

Теперь решает guardsMenuBar. Нулевая высота меню-бара значит одно из
двух — его нет совсем или он спрятан, — поэтому дисплей, который им
владеет (screens.first, главный в «Расположении»), считается несущим
меню-бар в любом случае: на маке без чёлки с автоскрытием всё остаётся
как было.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Полоска в 8 pt и ожидание 300 мс защищают иконки статус-итемов: на узком
экране синтетическая чёлка садится ровно туда, где они начинаются, и
разворачивать панель поверх того, куда целится курсор, нельзя. Условие
же стояло на «чёлка не физическая» — то есть на следствии, а не на
причине, и срабатывало там, где защищать нечего.

На внешнем мониторе 1920 pt чёлка занимает 870…1050, а иконки начинаются
с 1606 — зазор 556 pt. Панель при этом рисовалась высотой 25 pt и
отвечала только верхними 8: наводишь на чёлку, ничего не происходит,
открывается лишь когда упрёшься в кромку экрана.

Теперь положение иконок измеряется. Статус-итемы — окна на уровне
статус-бара, рамка окна публична, даже когда картинка нет, поэтому самый
левый из них просто считывается через CGWindowList; разрешений это не
требует. Догадка о ширине дисплея не подошла бы: иконки начинаются с
x≈757 на одном 13-дюймовом маке и с x≈1158 на другом — это факт о том,
сколько их у человека.

Замер повторяется, когда панель сворачивается: иконки появляются и
исчезают вместе с приложениями, а свёрнутая панель — единственный момент,
когда пересборка ничего не стоит.

Проверено на двух экранах: на LG панель открывается на 22 pt ниже верхней
кромки, в глубине чёлки, — раньше только с 8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Уровень statusWindow может попросить кто угодно — плавающая панель
утилиты посреди экрана лежит на нём же. Фильтр проверял только «окно на
этом дисплее», поэтому одно такое окно слева читалось как иконка,
дотянувшаяся до чёлки, и зона молча схлопывалась до полоски в 8 pt.
Теперь окно должно пересекать полосу меню-бара этого экрана.

Пустой список — не доказательство пустого меню-бара: одна Пультовая
держит там несколько окон. Значит замер не удался, и это читается как
«тесно», с прежней осторожной полоской.

Окна window-серверу перечисляются один раз на всю пересборку, а не по
разу на экран: вопрос у всех экранов один и тот же.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Конфликт был один и содержательный: #44 чинил залипание раскрытой панели
в старом NotchController, а здесь он разобран на общий контроллер и
NotchScreenPanel на каждый дисплей. Порядок «сначала клавиатура, потом
свёртка» тут уже был; чего не было — явного releaseKey и запроса на
перерисовку, потому что acceptsKeyboard перестал отдавать ключ сам.
Оба перенесены в NotchScreenPanel, где теперь живёт закрытие.

Остальное сошлось само: closeDelay 0.05 и свой стиль тумблера из #42,
заготовки из #47 и #49, скрытие из #51.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

На маке без челки синтетическая челка занимает середину меню-бара

1 participant