29.3 选中窗口

在每个框架中,任何时刻都恰好有一个 Emacs 窗口被指定为该框架内的选中框架(selected within the frame)。对于当前选中的框架而言,这个窗口就是选中窗口(selected window)—大部分编辑操作都在其中进行,选中窗口的光标也会显示在其中(see 光标参数)。用于插入或删除文本的键盘输入通常也会发往该窗口。选中窗口的缓冲区一般也是当前缓冲区,除非使用了 set-buffer(see 当前缓冲区)。对于未被选中的框架,一旦该框架被选中,其内部的选中窗口就会成为全局选中窗口。

Function: selected-window

该函数返回选中窗口(一定是活动窗口)。

下面的函数用于显式选中一个窗口及其所属框架。

Function: select-window window &optional norecord

该函数将 window 设为选中窗口,同时设为其所在框架内的选中窗口,并选中该框架。它还会将 window 的缓冲区(see 缓冲区与窗口)设为当前缓冲区,并将该缓冲区的光标位置 point 设置为该窗口内的 window-point(see 窗口(window)与点(Point))。window 必须是活动窗口。返回值为 window

默认情况下,该函数还会将 window 的缓冲区移至缓冲区列表的最前端(see 缓冲区列表),并将 window 记为最近选中的窗口。若可选参数 norecord 为非 nil,则不会执行这些附加操作。

此外,该函数默认还会通知显示引擎,在其框架下次重绘时更新该窗口的显示。若 norecord 为非 nil,通常不会执行这类更新。但如果 norecord 为特殊符号 mark-for-redisplay,则上述附加操作会被省略,但窗口显示仍会被更新。

注意,有时仅选中窗口并不足以让它可见,或让其框架显示在最顶层:你可能还需要提升该框架,或确保输入焦点指向该框架。See 输入焦点

由于历史原因,Emacs 在窗口被选中时 不会 运行专门的钩子。应用程序和内部例程常常会临时选中一个窗口以对其执行少量操作。这样做要么是为了简化代码——因为许多函数在未指定 window 参数时默认作用于选中窗口;要么是因为有些函数过去(现在依然)不接受窗口参数,而总是作用于选中窗口。如果每次短暂选中窗口再恢复原窗口时都运行钩子,并没有实际意义。

不过,当 norecord 参数为 nil 时,select-window 会更新缓冲区列表,从而间接运行普通钩子 buffer-list-update-hook(see 缓冲区列表)。因此,该钩子可用于在窗口被“较持久地”选中时运行函数。

由于 buffer-list-update-hook 也会由与窗口管理无关的函数触发,因此在运行该钩子时,通常需要保存选中窗口的值并与 selected-window 的返回值进行比较。此外,为避免使用 buffer-list-update-hook 时出现误判,良好的实践是:所有仅临时选中窗口的 select-window 调用都应传入非 nilnorecord 参数。如果可能,此类场景应使用宏 with-selected-window(见下文)。

每当重绘逻辑检测到自上次重绘后选中窗口发生变化时,Emacs 还会运行钩子 window-selection-change-functions。详细说明见 see 窗口滚动与变更的钩子函数window-state-change-functions(同一节介绍)是另一个非正常钩子,会在选中其他窗口后运行,但也会由其他窗口变化触发。

以非 nilnorecord 参数调用 select-window 的顺序,决定了窗口按选中或使用时间排序的序列,见下文。例如,函数 get-lru-window 可用于获取最近最少使用的窗口(see 窗口循环顺序)。

Function: frame-selected-window &optional frame

该函数返回框架 frame 内的选中窗口。frame 应为活动框架;若省略或为 nil,则默认为当前选中框架。

Function: set-frame-selected-window frame window &optional norecord

该函数将 window 设为框架 frame 内的选中窗口。frame 应为活动框架;若为 nil,则默认为当前选中框架。window 必须为活动窗口。

frame 为当前选中框架,则该操作会使 window 成为全局选中窗口。

若可选参数 norecord 为非 nil,该函数不会修改最近选中窗口的顺序,也不会修改缓冲区列表。

下面的宏适用于临时选中窗口,且不影响最近选中窗口顺序或缓冲区列表。

Macro: save-selected-window forms…

该宏记录当前选中框架以及各框架的选中窗口,依次执行 forms,然后恢复之前的选中框架与窗口。它还会保存并恢复当前缓冲区。返回值为 forms 中最后一个表达式的值。

该宏不会保存或恢复窗口的大小、布局或内容;因此,如果 forms 对其进行了修改,修改会保留。若执行完 forms 后,某框架原先的选中窗口已不再是活动窗口,则该框架的选中窗口保持不变。若原先的选中窗口已失效,则 forms 执行结束时的选中窗口将保留为选中状态。当前缓冲区仅在执行完 forms 后仍存活时才会被恢复。

该宏既不改变最近选中窗口的顺序,也不改变缓冲区列表。

Macro: with-selected-window window forms…

该宏选中 window,依次执行 forms,然后恢复原先的选中窗口与当前缓冲区。最近选中窗口的顺序和缓冲区列表保持不变,除非你在 forms 中显式修改它们;例如调用 select-window 并将 norecord 参数设为 nil。因此,该宏是临时以 window 作为选中窗口工作的首选方式,可避免不必要地运行 buffer-list-update-hook

注意,该宏会临时使窗口管理代码处于不稳定状态。特别是,最近使用的窗口(见下文)不一定与选中窗口一致。因此,在该宏体内调用 get-lru-windowget-mru-window 等函数可能返回意料之外的结果。

Macro: with-selected-frame frame forms…

该宏在 frame 作为选中框架的情况下执行 forms。返回值为 forms 中最后一个表达式的值。该宏会保存并恢复选中框架,且不改变最近选中窗口的顺序或缓冲区列表中的缓冲区顺序。

Function: window-use-time &optional window

该函数返回窗口 window 的使用时间。window 必须为活动窗口,默认为当前选中窗口。

窗口的使用时间(use time)并非真实时间值,而是一个整数,会在每次以 nilnorecord 参数调用 select-window 时单调递增。使用时间最小的窗口通常称为最近最少使用窗口。使用时间最大的窗口称为最近最常使用窗口(see 窗口循环顺序),通常就是选中窗口,除非使用了 with-selected-window

Function: window-bump-use-time &optional window

该函数将 window 标记为第二近使用的窗口(仅次于选中窗口)。若 window 本身就是选中窗口,或选中窗口并非所有窗口中使用时间最大的(这种情况可能出现在 with-selected-window 作用域内),则该函数不执行任何操作。

有时多个窗口会共同协作显示同一个缓冲区,例如在跟随模式(Follow Mode)管理下(see (emacs)Follow Mode),多个窗口一起显示的缓冲区内容比单个窗口能显示的更多。将这样的窗口组(window group)视为一个整体通常很有用。诸如 window-group-start(see 窗口起始与结束位置)等多个函数支持这一用法,只需传入组内任意一个窗口作为整个组的代表即可。

Function: selected-window-group

若选中窗口属于某个窗口组,该函数返回组内所有窗口构成的列表,排序方式为:列表中第一个窗口显示缓冲区最靠前的部分,依此类推。否则函数返回只包含选中窗口的列表。

当缓冲区局部变量 selected-window-group-function 被设为某个函数时,选中窗口会被视为组的一员。此时 selected-window-group 会无参调用该函数,并返回其结果(结果应为组内窗口列表)。