В любой момент времени один фрейм в Emacs является выбранным фреймом. Выбранное окно (см. Выбор окон) всегда находится на выбранном фрейме.
Когда Emacs отображает свои фреймы на нескольких терминалах (см. Несколько терминалов), каждый терминал имеет свой выбранный фрейм. Но только один из них является тем самым выбранным фреймом: это фрейм, принадлежащий терминалу, с которого поступил самый последний ввод. То есть, когда Emacs выполняет команду, поступившую с определённого терминала, выбранным фреймом является фрейм этого терминала. Поскольку Emacs выполняет только одну команду в любой момент времени, ему нужно рассматривать только один выбранный фрейм за раз; этот фрейм и называется в данном руководстве выбранным фреймом. Дисплей, на котором отображается выбранный фрейм, является дисплеем выбранного фрейма.
Эта функция возвращает выбранный фрейм.
Некоторые оконные системы и оконные менеджеры направляют ввод с клавиатуры в оконный объект, в котором находится мышь; другие требуют явных щелчков или команд для перемещения фокуса на различные оконные объекты. В любом случае Emacs автоматически отслеживает, какие фреймы имеют фокус. Чтобы явно переключиться на другой фрейм из функции Lisp, вызовите select-frame-set-input-focus.
Множественное число «фреймы» в предыдущем абзаце использовано намеренно: хотя сам Emacs имеет только один выбранный фрейм, Emacs может иметь фреймы на многих разных терминалах (напомним, что соединение с оконной системой считается терминалом), и каждый терминал имеет своё собственное представление о том, какой фрейм имеет фокус ввода. В оконной системе X, где пользовательский ввод организован в отдельные «места» ввода, каждое место в свою очередь может иметь свой собственный фокус ввода. Когда вы устанавливаете фокус ввода на фрейм, вы устанавливаете фокус для терминала этого фрейма на последнем месте, которое взаимодействовало с Emacs, но фреймы на других терминалах и местах могут оставаться в фокусе.
Если фокус ввода устанавливается до того, как на указанном терминале произошло какое-либо взаимодействие с пользователем, то X-сервер выбирает случайное место (обычно с наименьшим номером) и устанавливает туда фокус ввода.
Программы на Lisp могут временно переключать фреймы, вызывая функцию select-frame. Это не изменяет понятие фокуса в оконной системе; скорее, это уходит из-под контроля оконного менеджера до тех пор, пока этот контроль не будет каким-либо образом восстановлен.
При использовании текстового терминала на терминале одновременно может отображаться только один фрейм, поэтому после вызова select-frame при следующей перерисовке фактически отображается вновь выбранный фрейм. Этот фрейм остаётся выбранным до последующего вызова select-frame. Каждый фрейм на текстовом терминале имеет номер, который отображается в строке режима перед именем буфера (см. Переменные, используемые в строке режима).
Эта функция выбирает frame, поднимает его (если случится, что он скрыт другими фреймами) и пытается передать ему фокус оконной системы. На текстовом терминале при следующей перерисовке новый фрейм отображается на весь экран терминала. Необязательный аргумент norecord имеет тот же смысл, что и для select-frame (см. ниже). Возвращаемое значение этой функции несущественно.
В идеале функция, описанная далее, должна фокусировать фрейм без одновременного поднятия его над другими фреймами. К сожалению, многие оконные системы или оконные менеджеры могут отказаться выполнять это требование.
Эта функция передаёт frame фокус X-сервера без обязательного поднятия. frame nil означает использование выбранного фрейма. В X необязательный аргумент noactivate, если он не равен nil, означает попытку избежать сделать окно оконной системы frame «активным» окном, что должно немного сильнее настаивать на избежании поднятия frame над другими фреймами.
В MS-Windows аргумент noactivate не имеет эффекта. Однако если frame является дочерним фреймом (см. Дочерние фреймы), эта функция обычно фокусирует frame без поднятия его над другими дочерними фреймами.
Если поддержка оконной системы отсутствует, эта функция ничего не делает.
Эта команда выбирает фрейм frame, временно игнорируя фокус X-сервера, если таковой имеется. Выбор frame действует до тех пор, пока пользователь в следующий раз не сделает что-то для выбора другого фрейма, или до следующего вызова этой функции. (Если вы используете оконную систему, ранее выбранный фрейм может быть восстановлен как выбранный после возврата в цикл команд, поскольку он всё ещё может иметь фокус ввода оконной системы.)
Указанный frame становится выбранным фреймом, а его терминал становится выбранным терминалом. Затем эта функция вызывает select-window как подпрограмму, передавая окно, выбранное внутри frame, в качестве первого аргумента и norecord в качестве второго (следовательно, если norecord не равен nil, это позволяет избежать изменения порядка недавно выбранных окон и списка буферов). См. Выбор окон.
Эта функция возвращает frame или nil, если frame был удалён.
В общем случае вам никогда не следует использовать select-frame таким образом, чтобы можно было переключиться на другой терминал без возврата обратно после завершения работы.
Emacs взаимодействует с оконной системой, организуя выбор фреймов по запросу сервера и оконного менеджера. Когда оконная система сообщает Emacs, что один из его фреймов был выбран, Emacs внутренне генерирует событие focus-in. Когда фрейм Emacs отображается в эмуляторе текстового терминала, таком как xterm, который поддерживает уведомления об изменении фокуса, события focus-in и focus-out доступны даже для текстовых фреймов. События фокуса обычно обрабатываются handle-focus-in.
Эта команда обрабатывает события focus-in от оконных систем и терминалов, поддерживающих явные уведомления о фокусе. Она обновляет флаги фокуса для каждого фрейма, которые запрашивает frame-focus-state, и вызывает after-focus-change-function. Кроме того, она генерирует событие switch-frame для переключения понятия Emacs о выбранном фрейме на фрейм, который последним получил фокус на каком-либо терминале. Важно отметить, что это переключение выбранного фрейма Emacs на последний сфокусированный фрейм не означает, что другие фреймы не продолжают иметь фокус на своих соответствующих терминалах. Не вызывайте эту функцию самостоятельно: вместо этого прикрепляйте логику к after-focus-change-function.
Эта команда обрабатывает событие switch-frame, которое Emacs генерирует для себя при уведомлении о фокусе или в различных других обстоятельствах, связанных с поступлением события ввода на другой фрейм, отличный от фрейма предыдущего события. Не вызывайте эту функцию самостоятельно.
Эта функция перенаправляет фокус с frame на focus-frame. Это означает, что focus-frame будет получать последующие нажатия клавиш и события, предназначенные для frame. После такого события значение last-event-frame будет равно focus-frame. Кроме того, события switch-frame, указывающие frame, вместо этого будут выбирать focus-frame.
Если focus-frame опущен или равен nil, это отменяет любое существующее перенаправление для frame, и он снова начинает получать свои собственные события.
Одно из применений перенаправления фокуса — для фреймов, у которых нет минибуферов. Эти фреймы используют минибуферы на других фреймах. Активация минибуфера на другом фрейме перенаправляет фокус на этот фрейм. Это помещает фокус на фрейм минибуфера, где ему и положено быть, даже если мышь остаётся во фрейме, который активировал минибуфер.
Выбор фрейма также может изменять перенаправления фокуса. Выбор фрейма bar, когда ранее был выбран foo, изменяет все перенаправления, указывающие на foo, так чтобы они указывали на bar вместо этого. Это позволяет перенаправлению фокуса работать правильно, когда пользователь переключается с одного фрейма на другой с помощью select-window.
Это означает, что фрейм, чей фокус перенаправлен на самого себя, обрабатывается иначе, чем фрейм, чей фокус не перенаправлен. select-frame влияет на первый, но не на второй.
Перенаправление действует до тех пор, пока не будет вызван redirect-frame-focus для его изменения.
Эта функция возвращает последнее известное состояние фокуса для frame.
Она возвращает nil, если известно, что фрейм не в фокусе, t, если известно, что фрейм в фокусе, или unknown, если Emacs не знает состояние фокуса фрейма. (Вы можете увидеть это последнее состояние в TTY-фреймах, работающих на терминалах, которые не поддерживают явные уведомления о фокусе.)
Эта функция вызывается без аргументов, когда Emacs замечает, что фрейм мог получить или потерять фокус. События фокуса доставляются асинхронно и могут доставляться не в ожидаемом порядке, поэтому код, который хочет выполнить какие-либо действия в зависимости от состояния фокусированных фреймов, должен пройти по всем фреймам и проверить их.
Например, вот простой пример функции, которая устанавливает цвет фона в зависимости от того, имеет ли фрейм фокус:
(add-function :after after-focus-change-function
#'my-change-background)
(defun my-change-background ()
(dolist (frame (frame-list))
(pcase (frame-focus-state frame)
(`t (set-face-background 'default "black" frame))
(`nil (set-face-background 'default "#404040" frame)))))
Несколько фреймов могут одновременно казаться имеющими фокус ввода из-за различий в доставке событий фокуса, наличия нескольких терминалов Emacs и других факторов, и код должен быть устойчивым к такой ситуации.
В зависимости от оконной системы события фокуса также могут доставляться многократно и с различными состояниями фокуса, прежде чем установятся в ожидаемые значения. Код, полагающийся на уведомления о фокусе, должен «подавлять дребезг» любых видимых пользователю обновлений, возникающих из-за изменений фокуса, возможно, откладывая работу до перерисовки.
Эта функция может вызываться в произвольных контекстах, включая вызовы read-event, поэтому соблюдайте те же меры предосторожности, что и при написании фильтра процессов.
Эта опция сообщает Emacs, передаёт ли оконный менеджер фокус при перемещении указателя мыши во фрейм и как именно. Она может иметь три осмысленных значения:
nilЗначение по умолчанию nil следует использовать, если ваш оконный менеджер следует политике «щелчок для фокуса», где необходимо щёлкнуть мышью внутри фрейма, чтобы этот фрейм получил фокус.
tЗначение t следует использовать, если ваш оконный менеджер автоматически перемещает фокус вслед за положением указателя мыши, но фрейм, получающий фокус, не поднимается автоматически и может даже оставаться перекрытым другими окнами оконной системы.
auto-raiseЗначение auto-raise следует использовать, если ваш оконный менеджер автоматически перемещает фокус вслед за положением указателя мыши, и фрейм, получающий фокус, автоматически поднимается.
Если эта опция не равна nil, Emacs перемещает указатель мыши на фрейм, выбранный select-frame-set-input-focus. Эта функция используется рядом команд, например other-frame и pop-to-buffer.
Различие между значениями t и auto-raise не требуется для «обычных» фреймов, поскольку оконный менеджер обычно заботится об их поднятии. Оно полезно для автоматического поднятия дочерних фреймов с помощью mouse-autoselect-window (см. Автовыбор окон мышью).
Обратите внимание, что эта опция не различает «нестрогий» фокус (когда фрейм, ранее имевший фокус, сохраняет его, пока указатель мыши не переместится в другое окно оконной системы) и «строгий» фокус (когда фрейм немедленно теряет фокус, как только указатель мыши его покидает). Она также не определяет, поддерживает ли ваш оконный менеджер отложенный фокус или автоматическое поднятие, где можно явно указать время до получения фокуса или автоматического поднятия нового фрейма.
Вы можете задать политику «фокус следует за мышью» для отдельных окон Emacs, настроив переменную mouse-autoselect-window (см. Автовыбор окон мышью).