aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorDaniel Colascione2018-06-11 14:58:09 -0700
committerDaniel Colascione2018-06-11 16:10:34 -0700
commit2f6c682061a281dc3e397ff4727a164880e86e7b (patch)
treef5990303d483f7d80e1aa1e80a19dc64a6325b66 /lisp
parenta20fe5a7e3577f9b9ad5e88006962966240d9b0c (diff)
downloademacs-2f6c682061a281dc3e397ff4727a164880e86e7b.tar.gz
emacs-2f6c682061a281dc3e397ff4727a164880e86e7b.zip
New focus management interface
focus-in-hook and focus-out-hook don't accurately reflect actual user-visible focus states. Add a new focus interface and mark the old one obsolete. * doc/lispref/frames.texi (Input Focus): Document new focus functions. Remove references to the now-obsolete focus hooks. * lisp/frame.el (frame-focus-state): New function. (after-focus-change-function): New variable. (focus-in-hook, focus-out-hook): Move to lisp from C; mark obsolete. * lisp/term/xterm.el (xterm-translate-focus-in) (xterm-translate-focus-out): Track tty focus in `tty-focus-state' terminal parameter; call `after-focus-change-function'. (xterm--suspend-tty-function): New function. * src/frame.c (Fhandle_switch_frame): Update docstring; don't call focus hooks. (focus-in-hook, focus-out-hook): Remove: moved to lisp. (syms_of_frame): Remove unread_switch_frame; add Vunread_switch_frame. * src/keyboard.c: (Finternal_handle_focus_in): New function. (make_lispy_event): Always report focus events to lisp; don't translate them to switch events sometimes. Lisp can take care of creating synthetic switch-frame events via `internal-handle-focus-in'. * src/w32term.c (x_focus_changed): Remove switch-avoidance logic: just directly report focus changes to lisp. * src/xterm.c (x_focus_changed): Remove switch-avoidance logic: just directly report focus changes to lisp.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/frame.el106
-rw-r--r--lisp/term/xterm.el11
2 files changed, 103 insertions, 14 deletions
diff --git a/lisp/frame.el b/lisp/frame.el
index c3daff44406..2a2391e8a53 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -129,22 +129,104 @@ appended when the minibuffer frame is created."
129 ;; Gildea@x.org says it is ok to ask questions before terminating. 129 ;; Gildea@x.org says it is ok to ask questions before terminating.
130 (save-buffers-kill-emacs)))) 130 (save-buffers-kill-emacs))))
131 131
132(defun handle-focus-in (&optional _event) 132(defun frame-focus-state (&optional frame)
133 "Return FRAME's last known focus state.
134Return nil if the frame is definitely known not be focused, t if
135the frame is known to be focused, and 'unknown if we don't know. If
136FRAME is nil, query the selected frame."
137 (let* ((frame (or frame (selected-frame)))
138 (tty-top-frame (tty-top-frame frame)))
139 (if (not tty-top-frame)
140 (frame-parameter frame 'last-focus-update)
141 ;; All tty frames are frame-visible-p if the terminal is
142 ;; visible, so check whether the frame is the top tty frame
143 ;; before checking visibility.
144 (cond ((not (eq tty-top-frame frame)) nil)
145 ((not (frame-visible-p frame)) nil)
146 (t (let ((tty-focus-state
147 (terminal-parameter frame 'tty-focus-state)))
148 (cond ((eq tty-focus-state 'focused) t)
149 ((eq tty-focus-state 'defocused) nil)
150 (t 'unknown))))))))
151
152(defvar after-focus-change-function #'ignore
153 "Function called after frame focus may have changed.
154
155This function is called with no arguments when Emacs notices that
156the set of focused frames may have changed. Code wanting to do
157something when frame focus changes should use `add-function' to
158add a function to this one, and in this added function, re-scan
159the set of focused frames, calling `frame-focus-state' to
160retrieve the last known focus state of each frame. Focus events
161are delivered asynchronously, and frame input focus according to
162an external system may not correspond to the notion of the Emacs
163selected frame. Multiple frames may appear to have input focus
164simultaneously due to focus event delivery differences, the
165presence of multiple Emacs terminals, and other factors, and code
166should be robust in the face of this situation.
167
168Depending on window system, focus events may also be delivered
169repeatedly and with different focus states before settling to the
170expected values. Code relying on focus notifications should
171\"debounce\" any user-visible updates arising from focus changes,
172perhaps by deferring work until redisplay.
173
174This function may be called in arbitrary contexts, including from
175inside `read-event', so take the same care as you might when
176writing a process filter.")
177
178(defvar focus-in-hook nil
179 "Normal hook run when a frame gains focus.
180The frame gaining focus is selected at the time this hook is run.
181
182This hook is obsolete. Despite its name, this hook may be run in
183situations other than when a frame obtains input focus: for
184example, we also run this hook when switching the selected frame
185internally to handle certain input events (like mouse wheel
186scrolling) even when the user's notion of input focus
187hasn't changed.
188
189Prefer using `after-focus-change-function'.")
190(make-obsolete-variable
191 'focus-in-hook "after-focus-change-function" "27.1" 'set)
192
193(defvar focus-out-hook nil
194 "Normal hook run when all frames lost input focus.
195
196This hook is obsolete; see `focus-in-hook'. Depending on timing,
197this hook may be delivered when a frame does in fact have focus.
198Prefer `after-focus-change-function'.")
199(make-obsolete-variable
200 'focus-out-hook "after-focus-change-function" "27.1" 'set)
201
202(defun handle-focus-in (event)
133 "Handle a focus-in event. 203 "Handle a focus-in event.
134Focus-in events are usually bound to this function. 204Focus-in events are bound to this function; do not change this
135Focus-in events occur when a frame has focus, but a switch-frame event 205binding. Focus-in events occur when a frame receives focus from
136is not generated. 206the window system."
137This function runs the hook `focus-in-hook'." 207 ;; N.B. tty focus goes down a different path; see xterm.el.
138 (interactive "e") 208 (interactive "e")
139 (run-hooks 'focus-in-hook)) 209 (unless (eq (car-safe event) 'focus-in)
140 210 (error "handle-focus-in should handle focus-in events"))
141(defun handle-focus-out (&optional _event) 211 (internal-handle-focus-in event)
212 (let ((frame (nth 1 event)))
213 (setf (frame-parameter frame 'last-focus-update) t)
214 (run-hooks 'focus-in-hook)
215 (funcall after-focus-change-function)))
216
217(defun handle-focus-out (event)
142 "Handle a focus-out event. 218 "Handle a focus-out event.
143Focus-out events are usually bound to this function. 219Focus-out events are bound to this function; do not change this
144Focus-out events occur when no frame has focus. 220binding. Focus-out events occur when a frame loses focus, but
145This function runs the hook `focus-out-hook'." 221that's not the whole story: see `after-focus-change-function'."
222 ;; N.B. tty focus goes down a different path; see xterm.el.
146 (interactive "e") 223 (interactive "e")
147 (run-hooks 'focus-out-hook)) 224 (unless (eq (car event) 'focus-out)
225 (error "handle-focus-out should handle focus-out events"))
226 (let ((frame (nth 1 event)))
227 (setf (frame-parameter frame 'last-focus-update) nil)
228 (run-hooks 'focus-out-hook)
229 (funcall after-focus-change-function)))
148 230
149(defun handle-move-frame (event) 231(defun handle-move-frame (event)
150 "Handle a move-frame event. 232 "Handle a move-frame event.
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index b3b7a216352..ce4e18efff8 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -115,13 +115,20 @@ Return the pasted text as a string."
115;; notifications) instead of read-event (which can't). 115;; notifications) instead of read-event (which can't).
116 116
117(defun xterm-translate-focus-in (_prompt) 117(defun xterm-translate-focus-in (_prompt)
118 (handle-focus-in) 118 (setf (terminal-parameter nil 'tty-focus-state) 'focused)
119 (funcall after-focus-change-function)
119 []) 120 [])
120 121
121(defun xterm-translate-focus-out (_prompt) 122(defun xterm-translate-focus-out (_prompt)
122 (handle-focus-out) 123 (setf (terminal-parameter nil 'tty-focus-state) 'defocused)
124 (funcall after-focus-change-function)
123 []) 125 [])
124 126
127(defun xterm--suspend-tty-function (_tty)
128 ;; We can't know what happens to the tty after we're suspended
129 (setf (terminal-parameter nil 'tty-focus-state) nil)
130 (funcall after-focus-change-function))
131
125;; Similarly, we want to transparently slurp the entirety of a 132;; Similarly, we want to transparently slurp the entirety of a
126;; bracketed paste and encapsulate it into a single event. We used to 133;; bracketed paste and encapsulate it into a single event. We used to
127;; just slurp up the bracketed paste content in the event handler, but 134;; just slurp up the bracketed paste content in the event handler, but