Supporting Wayland’s XDG activation protocol with Gtk/Glib
嗯,用户让我帮忙总结一下这篇文章的内容,控制在一百个字以内,而且不需要用“文章内容总结”之类的开头。首先,我得仔细阅读文章,理解它的主要观点。 这篇文章主要讲的是Wayland的焦点窃取保护机制。焦点窃取保护是指一个应用不应该在未经允许的情况下突然获得焦点。Wayland在这方面比X11更好,因为它需要应用之间的明确授权。 文章详细解释了XDG激活协议的工作原理。这个协议要求在应用之间转移焦点时必须有明确的同意。比如,文件管理器要打开浏览器时,必须先给浏览器一个激活令牌,这样浏览器才能获取焦点。 然后,文章讨论了Gtk和Glib对这个协议的支持情况。接收方的支持已经实现,并且不需要开发者做额外的工作。但发送方的支持则需要一些代码改动,而且这部分文档似乎不完善。 接着,文章提供了两种启动应用的方法:一种是使用Gio.AppInfo,另一种是通过execve函数手动设置环境变量。这两种方法都需要正确处理激活令牌。 总的来说,这篇文章旨在帮助开发者理解和实现Wayland的焦点管理机制,确保应用之间的协作更加顺畅。 现在我需要把这些信息浓缩到100字以内。要抓住重点:Wayland的焦点保护机制、XDG激活协议、Gtk/Glib的支持情况以及两种启动应用的方法。 可能的结构是:首先说明主题和机制,然后提到协议的工作原理和文档不足的问题,最后提到两种启动方法和注意事项。 这样组织起来应该能简洁明了地概括文章内容。 </think> 这篇文章探讨了Wayland的焦点窃取保护机制及其背后的XDG激活协议。该协议要求应用间转移焦点需经授权,默认情况下文件管理器无法直接使浏览器获取焦点。文章指出Gtk/Glib已部分实现该协议但文档不足,并介绍了通过Gio.AppInfo或手动设置环境变量启动应用的方法以确保焦点正确转移。 2026-2-3 11:3:53 Author: palant.info(查看原文) 阅读量:1 收藏

 Linux  4 mins

One of the biggest sore points with Wayland is its focus stealing protection. The idea is good: an application should not be able to bring itself into focus at an unexpected time, only when the currently active application allows it. Support is still lacking however, which might also be due to Gtk/Glib implementing the required XDG activation protocol but not really documenting it. It took me a bit of time to figure this out without any public information, this article will hopefully make things easier for other people.

How the XDG activation protocol works

The main idea behind the XDG activation protocol is that focus transfer from one application to another requires consent. With X11 a file manager could just launch the browser for an HTML file and the browser would immediately take focus, even if that browser was already running. With Wayland the file manager has to indicate that the browser is allowed to take focus.

It does that by giving the browser its XDG activation token, typically via XDG_ACTIVATION_TOKEN environment variable. The browser can then use that activation token to prove consent and take focus. For this to work the protocol has to be supported on both ends: the file manager must know how to retrieve an activation token and pass it on via XDG_ACTIVATION_TOKEN environment variable, and the browser has to know how to use that token.

State of implementation in Gtk/Glib

The receiving side has been implemented in Gtk with merge request 7118 and is available starting with Gtk 4.14.6 and 4.15.1. This is the unproblematic part: it is handled automatically and doesn’t require the application developer to change anything.

The sending side has been implemented in Gtk with merge request 3502 and Glib with merge request 3090, so it is available starting with Gtk 4.10.0 and Glib 2.75.1. This is the part which might require some changes to the application – changes that I couldn’t find documented anywhere.

Starting applications via Gio.AppInfo

When a Gtk-based file manager wants to open an HTML file, this usually involves Gio.AppInfo and g_app_info_launch or similar:

GAppInfo* app_info = g_app_info_get_default_for_type("text/html", TRUE);

GList *list = NULL;
list = g_list_append(list, "https://example.com/");

GdkDisplay *display = gdk_display_get_default();
GdkAppLaunchContext* context = (display ?
  gdk_display_get_app_launch_context(display) :
  NULL);

g_app_info_launch_uris(app_info, list, G_APP_LAUNCH_CONTEXT(context), NULL);
g_list_free(list);

This should normally transfer focus to the browser automatically. That app launch context parameter is important however, you cannot omit it. Also, this will only work if the desktop file corresponding to the AppInfo has the StartupNotify key set – the Gtk developers decided to merge the handling of X11 startup notifications and XDG activations.

Starting applications by other means

But what if you are using something like execve function to start applications? You can still set XDG_ACTIVATION_TOKEN environment variable manually. It’s important to know however that the token has to be retrieved via g_app_launch_context_get_startup_notify_id (please pardon my C):

char** extend_env(char** env, char* value)
{
  int env_size = 0;
  while (env[env_size])
    env_size++;

  char **new_env = malloc((env_size + 2) * sizeof(char*));
  memcpy(new_env, env, env_size * sizeof(char*));
  new_env[env_size++] = value;
  new_env[env_size++] = NULL;
  return new_env;
}

char *argv[] = {"/usr/bin/firefox", "https://example.com/", NULL};
char *default_env[] = {NULL};
char **env = default_env;
bool should_free_env = FALSE;

GdkDisplay *display = gdk_display_get_default();
if (display)
{
  GdkAppLaunchContext* context = gdk_display_get_app_launch_context(display);
  env = g_app_launch_context_get_environment(G_APP_LAUNCH_CONTEXT(context));

  char* sn_id = g_app_launch_context_get_startup_notify_id(
    G_APP_LAUNCH_CONTEXT(context), NULL, NULL);
  if (sn_id)
  {
    char token_var[256];
    snprintf(token_var, sizeof(token_var), "XDG_ACTIVATION_TOKEN=%s", sn_id);
    env = extend_env(env, token_var);
    should_free_env = TRUE;
  }
}

if (!fork())
  execve(argv[0], argv, env);

if (should_free_env)
  free(env);

As before, it’s worth noting that Gtk developers decided to merge the handling of X11 startup notifications and XDG activations, hence the function name to retrieve the token. The last two parameters of g_app_launch_context_get_startup_notify_id are unused for Wayland, these are only relevant for X11 startup notifications. If you pass in an AppInfo instance here you might actually get an X11 notification ID back that you should write into the DESKTOP_STARTUP_ID environment variable. However, if you have an AppInfo instance it should be easier to use one of its launch functions as described above, these will do it automatically.


文章来源: https://palant.info/2026/02/03/supporting-waylands-xdg-activation-protocol-with-gtk/glib/
如有侵权请联系:admin#unsafe.sh