3

When emacsclient is invoked with the option -c it creates a new frame.

In both Windows and Linux, this frame is a window at the top of the Z-stack and has input focus.

With option -n (non-blocking) the command window in which emacsclient is invoked regains this position but the new Emacs frame only takes one step down the Z-order.

I can put the focus back on the Emacs frame just by closing the command window.

Is there any way to get this behavior with an existing frame, i.e. without -c?

The focus question has been asked many times without being clear about whether a new or existing frame is involved. The generally accepted answers seem to revolve around the elisp functions select-frame-set-input-focus and server-raise-frame. I find that these do nothing with existing frame (no -c) and are not needed otherwise.
I'm wondering if a viable but ugly solution would be to always invoke emacsclient with -c and in the command line eval an expression that detects the previous frame and deletes it but I don't know how to do this.

Windows 10 and 7; emacsclient version 26.1
Linux Ubuntu-Mate version 18.04; emacsclient version 25.2

3 Answers 3

2

In both Linux and Windows a separate program must be invoked after emacsclient (if it succeeds) to find and elevate the frame window. This is pretty simple in Linux because most of the work can be done by wmctrl, a general-purpose X window control program. This is not included in the Ubuntu distro but is listed in the repository, making installation easy (sudo apt-get install wmctrl). There are similar programs for Windows but virus scanners call them out as PUP (Potentially Unwanted Program) because they do too many things that can be exploited (wmctrl is more limited and safer). I wrote a Win32 console program to do what I want wmctrl to do in Linux. wmctrl (and my Windows program) find the requested window by its title. The Emacs default title tells the Emacs version and computer name. This is a lousy title in general so I was happy to change it to something the programs can find. I put (setq frame-title-format "Emacs>%b") in .emacs, making every frame window title still tell the program but also the name of the file (buffer). In Linux all the rest can be done by a simple Bash script. The heart of this is the command wmctrl -a "${1##*/}" which tells wmctrl to "activate" (bring forward and give focus) to the file name parsed from the path+name given by command parameter 1. The Windows program invokes the OS function EnumWindows, which iterates over all windows, invoking my callback, which looks for the file name in the title bar and calls OS function SetForegroundWindow on match.

Since this is not a forum about Bash or Windows programming I won't include code unless requested but I will mention that both of my programs do more than elevate the window. They try emacsclient and, if it fails, invoke emacs including the command argument --eval "(server-start)". They also optionally search for a string. Nevertheless, they are not very complicated.

1

I use xdotool. This won't work on Wayland. It does on Gnome with Xorg.

I have a shell script:-

#!/bin/bash
WID=`xdotool search --name "OneEmacs"|head -1`
if [[ -z ${WID} ]]; then
    notify-send "Starting Emacs daemon..."
    emacsclient --alternate-editor=''  -c 
else
    notify-send "restoring Emacs instance..."
    xdotool windowactivate $WID
fi

This looks for a frame with the title "OneEmacs" and restores it if it's there.

I call this from a desktop key binding.

In my init.el (or command line magic is another way)

 (setq frame-title-format "OneEmacs")

You could only do this if daemon mode maybe if you prefer:-

(if daemonp (...))

The notify-send functionality comes from libnotify

0

I use the following command to create a new Emacs server (Ubuntu 19.10):

emacs --eval '(progn (setq server-name "foo-server")(server-start))' &

After that I can focus it by running:

emacsclient -s foo-server --eval "(progn (select-frame-set-input-focus (selected-frame)))"

from the terminal window..

1
  • 1
    Your suggestion answers part of the question. I should have been more clear that the main issue is Z-order, while input focus is ancillary. In fact, giving the input focus to a hidden window invites disaster. I should have also been more clear that select-frame-set-input-focus does nothing at all in Windows and doesn't move the frame forward in either Windows or Linux. Regarding your code, it can be simplified a bit. I used the following for the same effect: emacs --eval '(server-start)' & and emacsclient -e "(select-frame-set-input-focus (selected-frame))" '(find-file "whatever")'. Commented Dec 5, 2019 at 20:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.