Cross-process window activation on wayland

Hi There,

my Gtk3 app https://horizon-eda.org/ consists of multiple processes that need to raise each other’s windows on user request.

This of course requires some special care to not run into focus stealing prevention measures.

On X11, passing the event’s timestamp across the process boundary to gtk_window_present_with_time worked well.

On wayland however, things work differently. xdg_activation_v1_activate requires a token to be created with a recent-enough serial.

So far I haven’t found a way to get such a serial by other means than listening to the mouse and keyboard events from wayland directly. See wip · horizon-eda/horizon@1ac4fbb · GitHub for a proof-of-concept implementation. Someone please tell me that there’s a better way to do this.

The annoying thing is that Gtk can do what I need, it’s just not part of any public API as far as I can tell:

This isn’t yet possible, but a solution is being discussed at https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/203.

To me this, looks like a different problem from mine. In my case, I know precisely which window to activate, but it’s from another process.

I see, then what you can do is use the xdg-activation protocol as is. Do this:

  • In response to a focus or input event use xdg_activation_v1.get_activation_token() to create a new token
  • Set the serial and surface that was the recipient to the above focus/input event on the token (xdg_activation_token_v1.set_serial and xdg_activation_token_v1.set_surface.
  • Commit the token (xdg_activation_token_v1.commit)
  • Wait for the xdg_activation_token_v1.done event which carries the exported token string
  • Pass this string to the application process you want to activate via whatever way you prefer

In the process you want to activate the window do this:

  • Receive the token from the last step above
  • Call xdg_activation_v1.activate with said token string and the surface you want to activate

This should activate (i.e. raise / bring to focus) the surface in the second process.

Looking a bit at gtk3, I think you can achieve this by using gdk_display_get_app_launch_context() then get said token from the last step above via g_app_launch_context_get_startup_notify_id().

And in the other process, achieve the last step via gdk_window_set_startup_id().

That’s pretty much what I did in the linked branch.

Excellent, that works, though none of the function names hint at what they actually do.

This function is only useful on X11, not with other GTK+ targets.