DBus:当名字从总线上消失时观察

DBus: Watch when name disappears from bus

我正在使用低级 DBus C 库实现 StatusNotifierWatcher 服务。 StatusNotifierWatcher 规范要求 watcher 可以知道什么时候 "A StatusNotifierItem instance has disappeared from the bus" 以便它可以发送 StatusNotifierItemUnregistered 信号。

实现示例:

#include <stdio.h>
#include <stdlib.h>
#include <dbus/dbus.h>

DBusConnection *conn = NULL;

void item_unregistered_signal(const char *name) {
    DBusMessage *signal = dbus_message_new_signal(
            "/org/freedesktop/StatusNotifierWatcher",
            "org.freedesktop.StatusNotifierWatcher",
            "StatusNotifierItemUnregistered");
    dbus_message_append_args(signal,
            DBUS_TYPE_STRING, &name,
            DBUS_TYPE_INVALID);
    dbus_connection_send(conn, signal, NULL);
    dbus_message_unref(signal);
}

void watch_name(const char *name, void(*cb)(const char *)) {
    // Not sure how to impliment
}

dbus_bool_t register_item(DBusConnection *connection, DBusMessage *message, void *_data) {
    DBusError error;
    char *name;

    if (!dbus_message_get_args(message, &error,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_INVALID)) {
        fprintf(stderr, "Error parsing method args: %s\n", error.message);
        return FALSE;
    }

    watch_name(name, item_unregistered_signal);
    return TRUE;
}

static void check_and_abort(DBusError *error) {
    if (dbus_error_is_set(error)) {
        fprintf(stderr, "dbus_err: %s\n", error->message);
        exit(EXIT_FAILURE);
    }
}

int main() {
    DBusError error;
    dbus_error_init(&error);
    conn = dbus_bus_get(DBUS_BUS_SESSION, &error);
    check_and_abort(&error);

    dbus_bus_request_name(conn, "org.freedesktop.StatusNotifierWatcher",
            DBUS_NAME_FLAG_REPLACE_EXISTING,
            &error);
    check_and_abort(&error);

    dbus_connection_add_filter(conn, register_item, NULL, free);

    while(1) {
        dbus_connection_read_write_dispatch(conn, 1000);
    }
}

如果我有 DBus 服务的知名名称,我怎么知道该名称何时从总线上消失?

好吧,我想通了,我会 post 为任何未来需要使用 libdbus 的可怜人提供答案。

每当任何 DBus 名称更改时,

org.freedesktop.DBus 都会发送 NameOwnerChanged 信号。可以使用此信号来跟踪某项是否消失,因为 NewOwner 参数是空字符串。 这个函数可以做到这一点:

static DBusHandlerResult signal_handler(DBusConnection *connection,
        DBusMessage *message, void *_usr_data) {

    if (dbus_message_is_signal(message, "org.freedesktop.DBus",
            "NameOwnerChanged")) {
        const char *name;
        const char *old_owner;
        const char *new_owner;

        if (!dbus_message_get_args(message, NULL,
                DBUS_TYPE_STRING, &name,
                DBUS_TYPE_STRING, &old_owner,
                DBUS_TYPE_STRING, &new_owner,
                DBUS_TYPE_INVALID)) {
            fprintf(stderr, "Error getting OwnerChanged args");
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }
        if (strcmp(name, "") != 0) {
            // Name not lost, just swapped owners
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
        }
        name_lost(name);
        return DBUS_HANDLER_RESULT_HANDLED;
    }
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}

还需要添加一个匹配项,以便使用此信号调用您的程序。我在 main()

中添加了这个
dbus_bus_add_match(conn, 
        "type='signal',\
        sender='org.freedesktop.DBus',\
        interface='org.freedesktop.DBus',\
        member='NameOwnerChanged'",
        &error);
check_and_abort(&error);

dbus_connection_add_filter(conn, signal_handler, NULL, free);

对于那些使用 GDBus (recommended) instead of libdbus (discouraged), the equivalent is g_bus_watch_name().

的人