diff --git a/src/dbus.c b/src/dbus.c index 55dad27..521015b 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -73,6 +73,7 @@ typedef uint32_t cdbus_enum_t; (srcmsg), (err_name), (err_format), ##__VA_ARGS__)) static DBusHandlerResult cdbus_process(DBusConnection *conn, DBusMessage *m, void *); +static DBusHandlerResult cdbus_process_windows(DBusConnection *c, DBusMessage *msg, void *ud); static dbus_bool_t cdbus_callback_add_timeout(DBusTimeout *timeout, void *data); @@ -182,6 +183,9 @@ bool cdbus_init(session_t *ps, const char *uniq) { dbus_connection_register_object_path( cd->dbus_conn, CDBUS_OBJECT_NAME, (DBusObjectPathVTable[]){{NULL, cdbus_process}}, ps); + dbus_connection_register_fallback( + cd->dbus_conn, CDBUS_OBJECT_NAME "/windows", + (DBusObjectPathVTable[]){{NULL, cdbus_process_windows}}, ps); return true; fail: ps->dbus_data = NULL; @@ -467,6 +471,19 @@ cdbus_apdarg_string(session_t *ps attr_unused, DBusMessage *msg, const void *dat return true; } +static bool cdbus_append_empty_dict(session_t *ps attr_unused, DBusMessage *msg, + const void *data attr_unused) { + DBusMessageIter it, it2; + dbus_message_iter_init_append(msg, &it); + if (!dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "{sv}", &it2)) { + return false; + } + if (!dbus_message_iter_close_container(&it, &it2)) { + return false; + } + return true; +} + /** * Callback to append all window IDs to a message. */ @@ -1212,6 +1229,7 @@ static bool cdbus_process_introspect(session_t *ps, DBusMessage *msg) { " \n" " \n" " \n" + " \n" "\n"; cdbus_reply_string(ps, msg, str_introspect); @@ -1220,6 +1238,80 @@ static bool cdbus_process_introspect(session_t *ps, DBusMessage *msg) { } ///@} +/** + * Process an D-Bus Introspect request, for /windows. + */ +static bool cdbus_process_windows_root_introspect(session_t *ps, DBusMessage *msg) { + static const char *str_introspect = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n"; + + char *ret = NULL; + mstrextend(&ret, str_introspect); + + HASH_ITER2(ps->windows, w) { + assert(!w->destroyed); + if (!w->managed) { + continue; + } + char *tmp = NULL; + asprintf(&tmp, "\n", w->id); + mstrextend(&ret, tmp); + free(tmp); + } + mstrextend(&ret, ""); + + bool success = cdbus_reply_string(ps, msg, ret); + free(ret); + return success; +} + +static bool cdbus_process_window_introspect(session_t *ps, DBusMessage *msg) { + // clang-format off + static const char *str_introspect = + "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + // clang-format on + + return cdbus_reply_string(ps, msg, str_introspect); +} + /** * Process a message from D-Bus. */ @@ -1304,6 +1396,72 @@ cdbus_process(DBusConnection *c attr_unused, DBusMessage *msg, void *ud) { return handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } +/** + * Process a message from D-Bus, for /windows path. + */ +static DBusHandlerResult +cdbus_process_windows(DBusConnection *c attr_unused, DBusMessage *msg, void *ud) { + session_t *ps = ud; + bool handled = false; + const char *path = dbus_message_get_path(msg); + const char *last_segment = strrchr(path, '/'); + if (last_segment == NULL) { + if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg) && + !dbus_message_get_no_reply(msg)) + cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S); + return DBUS_HANDLER_RESULT_HANDLED; + } + bool is_root = strncmp(last_segment, "/windows", 8) == 0; + if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", + "Introspect")) { + if (is_root) { + handled = cdbus_process_windows_root_introspect(ps, msg); + } else { + handled = cdbus_process_window_introspect(ps, msg); + } + goto finished; + } + + if (!is_root) { + auto wid = (cdbus_window_t)strtol(last_segment + 1, NULL, 0); + if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Properties", + "GetAll")) { + handled = cdbus_reply(ps, msg, cdbus_append_empty_dict, NULL); + goto finished; + + } + } + + if (dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameAcquired") || + dbus_message_is_signal(msg, "org.freedesktop.DBus", "NameLost")) { + return DBUS_HANDLER_RESULT_HANDLED; + } + + if (DBUS_MESSAGE_TYPE_ERROR == dbus_message_get_type(msg)) { + log_error("Error message of path \"%s\" " + "interface \"%s\", member \"%s\", error \"%s\"", + dbus_message_get_path(msg), dbus_message_get_interface(msg), + dbus_message_get_member(msg), dbus_message_get_error_name(msg)); + } else { + log_error("Illegal message of type \"%s\", path \"%s\" " + "interface \"%s\", member \"%s\"", + cdbus_repr_msgtype(msg), dbus_message_get_path(msg), + dbus_message_get_interface(msg), dbus_message_get_member(msg)); + } + if (DBUS_MESSAGE_TYPE_METHOD_CALL == dbus_message_get_type(msg) && + !dbus_message_get_no_reply(msg)) { + handled = cdbus_reply_err(ps, msg, CDBUS_ERROR_BADMSG, CDBUS_ERROR_BADMSG_S); + } + +finished: + if (!handled && dbus_message_get_type(msg) == DBUS_MESSAGE_TYPE_METHOD_CALL && + !dbus_message_get_no_reply(msg)) { + handled = + cdbus_reply_err(ps, msg, CDBUS_ERROR_UNKNOWN, CDBUS_ERROR_UNKNOWN_S); + } + return handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + /** @name Core callbacks */ ///@{