Repository: libsdl-org/SDL
File: src/core/linux/SDL_dbus.c (C)

Code before:
        if (msg) {
            if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
                retval = SDL_DBus_CallWithBasicReply(conn, save_reply, msg, expectedtype, result);
            }
            dbus.message_unref(msg);
        }
    }

    return retval;
}

bool SDL_DBus_QueryProperty(DBusMessage **save_reply, const char *node, const char *path, const char *interface, const char *property, int expectedtype, void *result)
{
    return SDL_DBus_QueryPropertyOnConnection(dbus.session_conn, save_reply, node, path, interface, property, expectedtype, result);
}

void SDL_DBus_ScreensaverTickle(void)
{
    if (screensaver_cookie == 0 && !inhibit_handle) { // no need to tickle if we're inhibiting.
        // org.gnome.ScreenSaver is the legacy interface, but it'll either do nothing or just be a second harmless tickle on newer systems, so we leave it for now.
        SDL_DBus_CallMethod(NULL, "org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity",
                            DBUS_TYPE_INVALID,
                            DBUS_TYPE_INVALID);
        SDL_DBus_CallMethod(NULL, "org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", "SimulateUserActivity",
                            DBUS_TYPE_INVALID,
                            DBUS_TYPE_INVALID);
    }
}

void SDL_DBus_FreeReply(DBusMessage **saved_reply)
{
    DBusMessage *reply = *saved_reply;
    if (reply) {
        dbus.message_unref(reply);
        *saved_reply = NULL;
    }
}

static bool SDL_DBus_AppendDictWithKeysAndValues(DBusMessageIter *iterInit, const char **keys, const char **values, int count)
{
    DBusMessageIter iterDict;

    if (!dbus.message_iter_open_container(iterInit, DBUS_TYPE_ARRAY, "{sv}", &iterDict)) {
        goto failed;
    }

    for (int i = 0; i < count; i++) {
        DBusMessageIter iterEntry, iterValue;
        const char *key = keys[i];
        const char *value = values[i];


Review comment (bug):
Note that the `SDL_DBus_CallVoidMethod` family (which you remove here) previously consisted of:

- build a method-call message
- send it
- don't wait for a reply
- we will never know whether the method call succeeded or failed

and you are changing them here to:

- build a method-call message
- send it
- *do* wait for a reply
- if the reply is success (but contains no further information), return true (which in this case is ignored)
- if the reply is failure, set the error indicator and return false (which in this case is ignored)
- if the reply is success but is non-empty, probably set the error indicator to indicate a type mismatch?

Was that intended?

On D-Bus there are valid use-cases for both "call a method, don't wait, don't care what happens" and "call a method, wait to see whether it succeeded". The latter is more common, but the former avoids blocking your main loop, and if you tell dbus-daemon that this is what you're doing, it lets dbus-daemon apply some optimizations (it doesn't bother to track replies, and suggests to the service that the service should not bother to send a reply either).

The more common D-Bus terminology is that if we don't wait for a reply, that's a "no reply" call - internally, the flag that gets set in the message is `DBUS_HEADER_FLAG_NO_REPLY_EXPECTED`.

Code after:
    result = SDL_DBus_CallVoidMethodInternal(dbus.session_conn, node, path, interface, method, ap);
    va_end(ap);
    return result;
}

static bool SDL_DBus_CallWithBasicReply(DBusConnection *conn, DBusMessage **save_reply, DBusMessage *msg, const int expectedtype, void *result)
{
    bool retval = false;

    // Make sure we're not looking up strings here, otherwise we'd have to save and return the reply
    SDL_assert(save_reply == NULL || *save_reply == NULL);
    SDL_assert(save_reply != NULL || dbus.type_is_fixed(expectedtype));

    DBusMessage *reply = dbus.connection_send_with_reply_and_block(conn, msg, 300, NULL);
    if (reply) {
        DBusMessageIter iter, actual_iter;
        dbus.message_iter_init(reply, &iter);
        if (dbus.message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
            dbus.message_iter_recurse(&iter, &actual_iter);
        } else {
            actual_iter = iter;
        }

        if (dbus.message_iter_get_arg_type(&actual_iter) == expectedtype) {
            dbus.message_iter_get_basic(&actual_iter, result);
            retval = true;
        }

        if (save_reply) {
            *save_reply = reply;
        } else {
            dbus.message_unref(reply);
        }
    }

    return retval;
}

bool SDL_DBus_QueryPropertyOnConnection(DBusConnection *conn, DBusMessage **save_reply, const char *node, const char *path, const char *interface, const char *property, int expectedtype, void *result)
{
    bool retval = false;

    if (conn) {
        DBusMessage *msg = dbus.message_new_method_call(node, path, "org.freedesktop.DBus.Properties", "Get");
        if (msg) {
            if (dbus.message_append_args(msg, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
                retval = SDL_DBus_CallWithBasicReply(conn, save_reply, msg, expectedtype, result);
            }
            dbus.message_unref(msg);
        }
    }