Subject: Re: bug#49505: 28.0.50; Multiple launchers in GNOME

From: Tim Ruffing <[email-masked]>
Date: Tue, 24 May 2022 14:33:17 +0200

Hi,

this is not yet solved. I tried to investigate it and it's quite a
rabbit hole:

So GNOME (and I suppose the same for KDE?) can't track "windows"
started by emacsclient properly, which is the problem as initially
reported by Manuel here. This problem still exists and I encounter it,
too: 

We currently offer two .desktop files both specifying *the same*
StartupWMClass=Emacs. This means that desktop environments can't match
windows to applications. When my GNOME sees a windows with WMClass
"Emacs", it assigns it arbitrarily to emacs.desktop ("Emacs") and not
emacsclient.desktop ("Emacs (Client)") because there's no unique match.
That means that when I click the "Emacs (Client)" icon in my dash, a
window is created but GNOME assumes it belongs to "Emacs", creating
another icon in my dash representing the "Emacs" window. This is wrong
and very inconvenient.

There are two ways that can be fixed, either we should have only a
single application (i.e., .desktop file) or we should make sure that
windows from emacs and emacsclient can be distinguished based on their
wmclass:

----

1. Unify the .desktop files

I know this has been tried already and was reverted because that
particular approach has forced users into using the daemon, which I
fully agree was not a good idea. What we could do instead is to have
have a single emacs.desktop that simply does the following:

Try to connect to daemon and create a new frame, if there's no daemon,
just launch a new instance (e.g., using emacsclient -a emacs).

This will get an automatic "New Window" action in the context menu (at
least in GNOME, need to check for others), because if you left-click
again, you'll simply switch to an existing window.

That's very simple, and it always will manage to bring up emacs, so
it's "safe" for the average user. It won't confuse new users because
who don't know whether they should launch "Emacs" or "Emacs (Client)".

And it leaves decision of using the daemon to the user, who can enable
or disable it using systemctl (or other ways) on normal desktops. If
didn't opt in to run a daemon, you won't even notice that emacs has a
daemon mode.

Advanced users who need something special, e.g, they want to bring up a
new non-daemon instance even though a daemon is running, can still
customize and create their own .desktop files or shortcuts. This is
nothing we should optimize for.

The only drawback of this approach is that ideally "New Window" would
bring up a just a new frame but this will work only in daemon mode. In
non-daemon mode, you'll get a new instance.

But I'm not sure if this could be solved quickly because I'm not sure
if there's a way to ask a non-daemon emacs to create a new frame. I
think in the long-term we could for example use D-Bus activation [1]
and make non-daemon emacs expose a dbus service that can create frames.
But that's a larger project. Ideally there would be a "semi-daemon"
mode, which is in between the daemon mode and the normal mode: The
first invocation launches a daemon, further invocations (e.g., using
emacsclient, or dbus) would just create new frames BUT if you close the
last frame, no daemon will stay around. This would exactly match the
behavior of other desktop applications.

----

2. Keep the .desktop files separate, and use separate wmclasses for
daemon and non-daemon mode

This has also been attempted in
1a845a672dc73c8e98e6cb9bb734616e168e60ba by changing argv[0] but this
was reverted by f355f32e69b1389f7d51b8a50c0a9c064dc2cb32 because
changing argv[0] is not a great idea. But we could change wmclass
differently, just by calling gtk_init() with a different string
depending on whether we're in daemon mode or not.

I think that would also work. This comes with a risk of breaking some
user scripts / config that rely on the wmclass instance name (similar
to how some things relied on matching argv[0]) but I don't think
that'll be a big deal.

----

In the end, I'd favor the first approach. A single .desktop will offer
the same functionality as we have currently, will confuse users less
than the currently separate files, and is on the right track for an
better solution in the long-term.

Moreover, the first approach can probably simplify the mess a little
bit because we should be able to drop "StartupWMClass" entirely, which
would probably avoid some more problems [4]. 

What do you think? I'd be willing to create a patch for either of the
approaches but I first wanted to check here because this seems a
complex and controversial topic.

Tim

PS: An entirely different issue is "startup notification" with the
emacsclient, i.e., the desktop environment has noticed that the app has
started up and can turn off the "waiting spinner" for example. This
needs some passing around of startup ids, which we currently don't do
via emacsclient. But that's far less annoying in practice. I can create
a separate bug for that.

[1] https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#dbus
[2] Currently on GNOME on Wayland, the match based on StartupWMClass
doesn't work due to the different capitalization in the Wayland appid
(somewhat equivalent to WM_CLASS on X), which is "emacs". Setting
StartupWMClass is not necessary AFAIU, and desktop environments will
simply match based on the filename of the .desktop file and case
doesn't seem to matter here. The actual logic is pretty ugly (GNOME
[3], KDE [4]) and we so we should test this. One of the problems here
is that WM_CLASS consists of two strings in fact, the "name" and the
"class". In our case that's "emacs" and "Emacs", and the freedesktop
spec for .desktop doesn't specify which one should be taken...
[3] https://github.com/GNOME/gnome-shell/blob/main/src/shell-window-tracker.c#L198
[4] https://github.com/KDE/plasma-workspace/blob/070009a5cb9387596230c6008102a288f7972ba5/libtaskmanager/tasktools.cpp#L195