Equake: A Geas on Gnomish Smiths
A new version of Equake, the drop-down “terminal emulator” for Emacs, should be hitting Melpa shortly. This version includes a number of bug fixes, and some new features.
Jeff Kowalski added code for a “close Equake frame on loss of focus feature” (similar to the Tilda feature) and a number of bug fixes and code-cleanup.
Further: I’m (half-)jokingly calling this the Geas on Gnomish Smiths release as I’ve finally figured out how to make it behave properly under GNOME Shell Wayland.
To my knowledge, the only other currently working drop-down terminal for GNOME Shell Wayland is the JavaScript GNOME extension ddterm. Wayland (at least GNOME Shell’s Wayland) seems very restrictive in how non-user-initiated events can affect window properties. E.g., it is difficult to programmatically affect window focus in GNOME Shell under Wayland. The default “hide window” behaviour of Equake doesn’t work.
However, I did have a legacy feature where closing/hiding Equake involved destroying the frame rather than hiding it. This is somewhat complicated, as re-invoking Equake then involves creating a new frame and restoring the tabs and buffer history. This is how Equake originally worked, but it is simpler (and slightly faster) just to hide the frame on “close” and then unhide it on “re-open”, and this became the default behaviour for Equake some time ago. But I left the old code in place as another option.
However, various changes apparently ended up with the restoration behaviour not working quite properly. I have fixed this (more or less, see https://gitlab.com/emacsomancer/equake/-/issues/26). With that fix in place, we can then trick GNOME Shell under Wayland into behaving properly. Rather than hiding the Equake frame on “close”, we destroy it and then recreate it on “open”. This involves quite a bit of trickery behind the scenes. Essentially, opening a new window under GNOME Shell Wayland can result in that window being placed on top of any existing windows (though to do it properly, employing a it of Elisp (select-frame-set-input-focus (selected-frame))
seems to result in the new Emacs client frame being on top (and focussed) [this is a potentially useful trick for opening regular new Emacsclient frames as well].
But, the usual way that Equake frames are created internally is via
Emacs make-frame
, which doesn’t automatically focus the new
frame. So rather than doing this, we need to have the user call emacsclient -c
and then transform that frame into an Equake frame. A new Equake function equake--transform-existing-frame-into-equake-frame
takes care of this. The transformation and the old code restoring tabs and history doesn’t quite take care of everything though as the point/cursor is left by default at the top of the frame, which is not the user-expected behaviour. So an addition bit of elisp (goto-char (1- (point-max)))
generally moves the point/cursor to the end of the buffer where the user might expect it.
So I have a bit of shell script as a helper function which is what one should create a keybinding for in GNOME Shell Wayland:
#!/bin/sh
equakestatus=$(emacsclient -n -e '(frame-live-p (alist-get (equake--get-monitor) equake--frame))')
if [ "$equakestatus" = "nil" ]; then
emacsclient -c -e "(progn (select-frame-set-input-focus (selected-frame))
(equake--transform-existing-frame-into-equake-frame)
(goto-char (1- (point-max))))"
else
emacsclient -n -e '(progn (setq equake-use-frame-hide nil)
(equake-invoke))'
fi
This checks if there is a live Equake frame; if there is, it is hidden; otherwise a new frame is created and transformed.
Finally, in order to be able to get the “Always on Top” behaviour, the new Equake frame transmutation function calls (shell-command "wmctrl -r :ACTIVE: -b toggle,above")
(so one needs wmctrl
installed), which seems to trigger the “Always on Top” feature at least for Xwayland windows.
And, presto, change-o, voilà, we have a version of Equake which exhibits its normal X11 behaviour in GNOME Shell Wayland.
(As long as Emacs is run as an Xwayland application; otherwise the “always on top” behaviour doesn’t work properly.)