1

I am faced with a specific problem: My elisp code, that reacts to DBus events, needs to know whether Emacs window it is currently running in has focus or not at the moment the event arrived.

When running under X, the answer is known, and I'll put it there in case anyone stumbles on this question:

(defun x-active-window ()
  "Return the window ID of the current active window in X \
as given by the _NET_ACTIVE_WINDOW of the root window set by the \
window-manager, or nil if not able to."
       (and (eq (window-system) 'x)
            (x-window-property
             "_NET_ACTIVE_WINDOW" nil "WINDOW" 0 nil t)))

(defun frame-outer-window-id (frame)
  "Return the frame outer-window-id property, or nil if FRAME not \
of the correct type."
  (and (framep frame)
       (string-to-number (frame-parameter frame 'outer-window-id))))

(defun x-active-window-p (frame)
  "Check if FRAME is the X active window. \
Return t if frame has focus or nil otherwise."
  (and (framep frame)
       (eq (frame-outer-window-id frame)
           (x-active-window))))

(x-active-window-p (selected-frame)))

Unfortunately, I am also running the current master emacs with pgtk on Wayland, where the above doesn't work at all, because there's no XWayland underneath. After much mucking around, I've been able to come up with this horror:

(defun pgtk-active-window ()
  "Returns _updateTitleID of the active window in Gnome Shell."
  (second (dbus-call-method
           :session
           "org.gnome.Shell"
           "/org/gnome/Shell"
           "org.gnome.Shell"
           "Eval"
           "global.display.focus_window._updateTitleID;")))

I.e. through poorly documented, roundabout methods (by calling into Gnome Shell over DBus and telling it to execute a line of javascript) we get one, apparently unique parameter about the window currently in focus, (that's the only one it returns) which does not appear to change during window lifecycle. Then we can compare it to the one we stored during startup, when our window was in focus.

It works, for suitably small quantities of "works", but all the problems with this approach should be obvious. However, I was not able to find any other way a frame could determine if it is currently in focus in in PGTK, and going through the emacs source did not enlighten me either.

Does a better way currently exist?

RN3AOH
  • 53
  • 6
  • Maybe I'm missing something, but isn't that the job of `frame-focus-state`? – Gilles 'SO- stop being evil' Jan 19 '22 at 20:02
  • @Gilles'SO-stopbeingevil' No, you're not. It's just that this function wasn't available when the above magic code for X was written, having been added in 27.1 or thereabout. I've since discovered it and have been meaning to write up a proper answer, but didn't get around to it yet. – RN3AOH Jan 21 '22 at 08:37

2 Answers2

1

Under typical conditions, when all the frames of an Emacs instance are on the same GUI environment, the frame that has the focus, if any, is (selected-frame). The selected frame isn't necessarily active, however: a frame remains selected when the focus switches to a non-Emacs window, and Lisp code can temporarily select a different frame.

Since Emacs 27, you can call (frame-focus-state) to tell whether the selected frame has the focus. This can return unknown for terminal frames, because terminal frames don't have explicit focus change events: Emacs only decides that a terminal frame is focused when it receives input, and that it loses focus when another frame receives input.

Since Emacs 24.4, you can keep track of which frames are focused via the hooks focus-in-hook and focus-out-hook. These hooks are triggered when Emacs thinks that a frame has gained or lost focus respectively, which I think is accurate under all GUI environments, but is guessed for terminal frames.

Before 24.4, there didn't seem to be a way to know about the OS focus, other than deciding when a window receives input, it presumably has the focus.

Note that Emacs can display frames on multiple displays, and each of them has its own focus. It's possible for multiple frames to have the focus, each on their own display. If you want to know about all focused frames, iterate over (frame-list) and query each frame's focus state. You can tell which display a frame is on with (frame-parameter frame 'display).

0

So, the correct answer: Neither mess of code is necessary since Emacs 27.1.

Windowing systems generally have a means of telling programs whether their windows are currently in focus or not, and Emacs, being able to have multiple windows ("frames") at once, needs to keep track of this information, if only just to know which input buffer the incoming keystrokes refer to. The X example above, which I originally found in the depths of EmacsWiki, predates the easy availability of this information in elisp:

(frame-focus-state)

Which is t if the window is currently in focus, nil if it is not, and unknown if this can't be determined, which may happen when running in terminal.

Since PGTK branch itself has only been merged with Emacs 29, this is guaranteed to be available if the problem exists.

RN3AOH
  • 53
  • 6