mirror of
https://github.com/doomemacs/doomemacs
synced 2025-08-03 12:27:26 -05:00
refactor: doom-switch-frame-hook
Redesign this hook around `after-focus-change-function`, along with debouncing, to prevent it from triggering too aggressively (due to misbehaving desktop environments, elisp packages that tinker with frame focus, or accidental (and rapid) focus changes by the user). `doom-switch-{window,buffer}-hook` have also been simplified, and `doom-switch-window-hook` now will not trigger when focusing another frame (only when you switch windows *within* any one frame). This also fixes diff-hl not updating when refocusing an Emacs frame.
This commit is contained in:
@ -255,10 +255,10 @@ tell you about it. Very annoying. This prevents that."
|
|||||||
|
|
||||||
(use-package! autorevert
|
(use-package! autorevert
|
||||||
;; revert buffers when their files/state have changed
|
;; revert buffers when their files/state have changed
|
||||||
:hook (focus-in . doom-auto-revert-buffers-h)
|
|
||||||
:hook (after-save . doom-auto-revert-buffers-h)
|
:hook (after-save . doom-auto-revert-buffers-h)
|
||||||
:hook (doom-switch-buffer . doom-auto-revert-buffer-h)
|
:hook (doom-switch-buffer . doom-auto-revert-buffer-h)
|
||||||
:hook (doom-switch-window . doom-auto-revert-buffer-h)
|
:hook (doom-switch-window . doom-auto-revert-buffer-h)
|
||||||
|
:hook (doom-switch-frame . doom-auto-revert-buffers-h)
|
||||||
:config
|
:config
|
||||||
(setq auto-revert-verbose t ; let us know when it happens
|
(setq auto-revert-verbose t ; let us know when it happens
|
||||||
auto-revert-use-notify nil
|
auto-revert-use-notify nil
|
||||||
|
@ -91,22 +91,60 @@ want to change your symbol font, use `doom-symbol-font'.")
|
|||||||
"A list of hooks run after changing the focused windows.")
|
"A list of hooks run after changing the focused windows.")
|
||||||
|
|
||||||
(defcustom doom-switch-frame-hook nil
|
(defcustom doom-switch-frame-hook nil
|
||||||
"A list of hooks run after changing the focused frame.")
|
"A list of hooks run after changing the focused frame.
|
||||||
|
|
||||||
|
This also serves as an analog for `focus-in-hook' or
|
||||||
|
`after-focus-change-function', but also preforms debouncing (see
|
||||||
|
`doom-switch-frame-hook-debounce-delay'). It's possible for this hook to be
|
||||||
|
triggered multiple times (because there are edge cases where Emacs can have
|
||||||
|
multiple frames focused at once).")
|
||||||
|
|
||||||
(defun doom-run-switch-buffer-hooks-h (&optional _)
|
(defun doom-run-switch-buffer-hooks-h (&optional _)
|
||||||
(let ((gc-cons-threshold most-positive-fixnum)
|
"Trigger `doom-switch-buffer-hook' when selecting a new buffer."
|
||||||
(inhibit-redisplay t))
|
(let ((gc-cons-threshold most-positive-fixnum))
|
||||||
(run-hooks 'doom-switch-buffer-hook)))
|
(run-hooks 'doom-switch-buffer-hook)))
|
||||||
|
|
||||||
(defun doom-run-switch-window-or-frame-hooks-h (&optional _)
|
(defun doom-run-switch-window-hooks-h (&optional _)
|
||||||
(let ((gc-cons-threshold most-positive-fixnum)
|
"Trigger `doom-switch-window-hook' when selecting a window in the same frame."
|
||||||
(inhibit-redisplay t))
|
(unless (or (minibufferp)
|
||||||
(unless (equal (old-selected-frame) (selected-frame))
|
(not (equal (old-selected-frame) (selected-frame)))
|
||||||
(run-hooks 'doom-switch-frame-hook))
|
(equal (old-selected-window) (minibuffer-window)))
|
||||||
(unless (or (minibufferp)
|
(let ((gc-cons-threshold most-positive-fixnum))
|
||||||
(equal (old-selected-window) (minibuffer-window)))
|
|
||||||
(run-hooks 'doom-switch-window-hook))))
|
(run-hooks 'doom-switch-window-hook))))
|
||||||
|
|
||||||
|
(defvar doom-switch-frame-hook-debounce-delay 2.0
|
||||||
|
"The delay for which `doom-switch-frame-hook' won't trigger again.
|
||||||
|
|
||||||
|
This exists to prevent switch-frame hooks getting triggered too aggressively due
|
||||||
|
to misbehaving desktop environments, packages incorrectly frame switching in
|
||||||
|
non-interactive code, or the user accidentally (and rapidly) un-and-refocusing
|
||||||
|
the frame through some other means.")
|
||||||
|
|
||||||
|
(defun doom--run-switch-frame-hooks-fn (_)
|
||||||
|
(remove-hook 'pre-redisplay-functions #'doom--run-switch-frame-hooks)
|
||||||
|
(let ((gc-cons-threshold most-positive-fixnum))
|
||||||
|
(dolist (fr (visible-frame-list))
|
||||||
|
(let ((state (frame-focus-state fr)))
|
||||||
|
(when (and state (not (eq state 'unknown)))
|
||||||
|
(let ((last-update (frame-parameter fr '+last-focus)))
|
||||||
|
(when (or (null last-update)
|
||||||
|
(> (float-time (time-subtract (current-time) last-update))
|
||||||
|
doom-switch-frame-hook-debounce-delay))
|
||||||
|
(with-selected-frame fr
|
||||||
|
(unwind-protect
|
||||||
|
(run-hooks 'doom-switch-frame-hook)
|
||||||
|
(set-frame-parameter fr '+last-focus (current-time)))))))))))
|
||||||
|
|
||||||
|
(let (last-focus-state)
|
||||||
|
(defun doom-run-switch-frame-hooks-fn ()
|
||||||
|
"Trigger `doom-switch-frame-hook' once per frame focus change."
|
||||||
|
(let ((inhibit-redisplay t))
|
||||||
|
(or (equal last-focus-state
|
||||||
|
(setq last-focus-state
|
||||||
|
(mapcar #'frame-focus-state (frame-list))))
|
||||||
|
;; Defer until next redisplay
|
||||||
|
(add-hook 'pre-redisplay-functions #'doom--run-switch-frame-hooks-fn)))))
|
||||||
|
|
||||||
(defun doom-protect-fallback-buffer-h ()
|
(defun doom-protect-fallback-buffer-h ()
|
||||||
"Don't kill the scratch buffer. Meant for `kill-buffer-query-functions'."
|
"Don't kill the scratch buffer. Meant for `kill-buffer-query-functions'."
|
||||||
(not (eq (current-buffer) (doom-fallback-buffer))))
|
(not (eq (current-buffer) (doom-fallback-buffer))))
|
||||||
@ -669,9 +707,9 @@ triggering hooks during startup."
|
|||||||
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
|
;; Make `next-buffer', `other-buffer', etc. ignore unreal buffers.
|
||||||
(push '(buffer-predicate . doom-buffer-frame-predicate) default-frame-alist)
|
(push '(buffer-predicate . doom-buffer-frame-predicate) default-frame-alist)
|
||||||
|
|
||||||
;; Initialize `doom-switch-window-hook' and `doom-switch-frame-hook'
|
;; Initialize `doom-switch-*-hook' hooks.
|
||||||
(add-hook 'window-selection-change-functions #'doom-run-switch-window-or-frame-hooks-h)
|
(add-function :after after-focus-change-function #'doom-run-switch-frame-hooks-fn)
|
||||||
;; Initialize `doom-switch-buffer-hook'
|
(add-hook 'window-selection-change-functions #'doom-run-switch-window-hooks-h)
|
||||||
(add-hook 'window-buffer-change-functions #'doom-run-switch-buffer-hooks-h)
|
(add-hook 'window-buffer-change-functions #'doom-run-switch-buffer-hooks-h)
|
||||||
;; `window-buffer-change-functions' doesn't trigger for files visited via the server.
|
;; `window-buffer-change-functions' doesn't trigger for files visited via the server.
|
||||||
(add-hook 'server-visit-hook #'doom-run-switch-buffer-hooks-h))
|
(add-hook 'server-visit-hook #'doom-run-switch-buffer-hooks-h))
|
||||||
|
@ -50,7 +50,7 @@ Only has an effect in GUI Emacs.")
|
|||||||
;; ...then refresh the rest only when we switch to them or refocus the active
|
;; ...then refresh the rest only when we switch to them or refocus the active
|
||||||
;; frame, not all at once.
|
;; frame, not all at once.
|
||||||
(add-hook 'doom-switch-buffer-hook #'+magit-revert-buffer-maybe-h)
|
(add-hook 'doom-switch-buffer-hook #'+magit-revert-buffer-maybe-h)
|
||||||
(add-hook 'focus-in-hook #'+magit-mark-stale-buffers-h)
|
(add-hook 'doom-switch-frame-hook #'+magit-mark-stale-buffers-h)
|
||||||
|
|
||||||
;; The default location for git-credential-cache is in
|
;; The default location for git-credential-cache is in
|
||||||
;; ~/.cache/git/credential. However, if ~/.git-credential-cache/ exists, then
|
;; ~/.cache/git/credential. However, if ~/.git-credential-cache/ exists, then
|
||||||
|
@ -368,7 +368,7 @@ Requires `anzu', also `evil-anzu' if using `evil-mode' for compatibility with
|
|||||||
;; In case the user saves the file to a new location
|
;; In case the user saves the file to a new location
|
||||||
after-save-hook
|
after-save-hook
|
||||||
;; ...or makes external changes then returns to Emacs
|
;; ...or makes external changes then returns to Emacs
|
||||||
focus-in-hook
|
doom-switch-frame-hook
|
||||||
;; ...or when we change the current project!
|
;; ...or when we change the current project!
|
||||||
projectile-after-switch-project-hook
|
projectile-after-switch-project-hook
|
||||||
;; ...when the visited file changes (e.g. it's renamed)
|
;; ...when the visited file changes (e.g. it's renamed)
|
||||||
|
@ -118,8 +118,9 @@ Respects `diff-hl-disable-on-remote'."
|
|||||||
:n "{" #'diff-hl-show-hunk-previous
|
:n "{" #'diff-hl-show-hunk-previous
|
||||||
:n "}" #'diff-hl-show-hunk-next
|
:n "}" #'diff-hl-show-hunk-next
|
||||||
:n "S" #'diff-hl-show-hunk-stage-hunk))
|
:n "S" #'diff-hl-show-hunk-stage-hunk))
|
||||||
;; UX: Refresh gutter on ESC or refocusing the Emacs frame.
|
;; UX: Refresh gutter in the selected buffer on ESC, switching windows, or
|
||||||
(add-hook! '(doom-escape-hook doom-switch-window-hook) :append
|
;; refocusing the frame.
|
||||||
|
(add-hook! '(doom-escape-hook doom-switch-window-hook doom-switch-frame-hook) :append
|
||||||
(defun +vc-gutter-update-h (&rest _)
|
(defun +vc-gutter-update-h (&rest _)
|
||||||
"Return nil to prevent shadowing other `doom-escape-hook' hooks."
|
"Return nil to prevent shadowing other `doom-escape-hook' hooks."
|
||||||
(ignore (or inhibit-redisplay
|
(ignore (or inhibit-redisplay
|
||||||
|
Reference in New Issue
Block a user