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
*/
///@{