You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过GLib GDBus API获取GNOME Shell Eval方法返回结果?

解决GNOME Shell DBus Eval方法调用的问题

问题根源

你的代码存在两个核心错误,直接导致了CRITICAL断言失败:

  • 对象路径格式错误:创建DBus代理时传入的"/org/gnome/Shell/"末尾多了斜杠,DBus对象路径不允许以斜杠结尾,正确路径应为"/org/gnome/Shell"。
  • 无效代理引发连锁错误:由于代理创建失败,后续g_dbus_proxy_call_sync传入的proxy无效,返回的result为NULL,进而触发g_variant_get的断言错误。

此外,即使解决上述问题,Eval返回的字符串是JavaScript字面量格式(带转义引号),需要额外处理才能得到真实的窗口标题。

修正后的代码

#include <stdbool.h>
#include <stdio.h>
#include <glib/gprintf.h>
#include <gio/gio.h>
#include <string.h>

void test_getwindows(GDBusProxy *proxy)
{
    GError *error = NULL;
    g_printf("Calling Eval()...\n");
    
    // 调用Eval方法,获取聚焦窗口标题的JS代码
    GVariant *result = g_dbus_proxy_call_sync(proxy,
            "Eval",
            g_variant_new("s", "global.get_window_actors().find(actor => actor.meta_window.has_focus()).meta_window.get_title()"),
            G_DBUS_CALL_FLAGS_NONE,
            -1,
            NULL,
            &error);
    
    if (error != NULL) {
        g_printerr("调用失败: %s\n", error->message);
        g_error_free(error);
        return;
    }

    // 提取返回的成功状态和结果字符串
    gboolean success;
    gchar *raw_title;
    g_variant_get(result, "(bs)", &success, &raw_title);
    
    if (success && raw_title != NULL) {
        // 处理JS字符串的转义:去掉前后引号,解析转义字符
        gchar *window_title = NULL;
        if (strlen(raw_title) >= 2 && raw_title[0] == '"' && raw_title[strlen(raw_title)-1] == '"') {
            // 去掉首尾引号,解析转义序列
            window_title = g_strcompress(raw_title + 1);
            // 截断结尾的引号
            window_title[strlen(window_title)-1] = '\0';
        } else {
            window_title = g_strdup(raw_title);
        }
        
        g_printf("window_title: %s\nsuccess: %d\n", window_title, success);
        g_free(window_title);
    } else {
        g_printf("获取窗口标题失败\nsuccess: %d\n", success);
    }
    
    g_free(raw_title);
    g_variant_unref(result);
}

int main(void)
{
    GDBusProxy *proxy = NULL;
    GDBusConnection *conn = NULL;
    GError *error = NULL;

    // 获取会话总线连接
    conn = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
    if (error != NULL) {
        g_printerr("获取总线连接失败: %s\n", error->message);
        g_error_free(error);
        return 1;
    }

    // 创建DBus代理:修正对象路径,去掉末尾斜杠
    proxy = g_dbus_proxy_new_sync(conn,
                G_DBUS_PROXY_FLAGS_NONE,
                NULL,
                "org.gnome.Shell", 
                "/org/gnome/Shell",  // 正确的对象路径
                "org.gnome.Shell",
                NULL,
                &error);
    
    if (error != NULL) {
        g_printerr("创建代理失败: %s\n", error->message);
        g_error_free(error);
        g_object_unref(conn);
        return 1;
    }

    test_getwindows(proxy);

    // 释放资源
    g_object_unref(proxy);
    g_object_unref(conn);
    return 0;
}

关键修正点说明

  1. 对象路径规范:将"/org/gnome/Shell/"改为"/org/gnome/Shell",符合DBus对象路径的语法要求。
  2. 错误处理增强:添加了对总线连接、代理创建、方法调用的错误检查,避免断言失败导致程序崩溃。
  3. 字符串转义处理:Eval返回的是JavaScript格式的字符串(如"\"ibse@ibse-VirtualBox: ~\""),通过g_strcompress解析转义字符,并去掉首尾引号,得到真实的窗口标题。
  4. 资源管理:添加了g_variant_unref、g_free和g_object_unref来正确释放GLib资源,避免内存泄漏。

编译与运行

使用以下命令编译(需安装GLib和GIO开发库):

gcc -o get_focused_window get_focused_window.c `pkg-config --cflags --libs glib-2.0 gio-2.0`

运行时需确保当前用户为桌面会话的活跃用户,以获得GNOME Shell DBus接口的访问权限。

内容的提问来源于stack exchange,提问作者ibse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 16:08:21