Simplify DBus notification assembly
This commit is contained in:
parent
a8faea725d
commit
b10bb292c6
131
src/dbus.c
131
src/dbus.c
@ -142,96 +142,84 @@ static void on_get_capabilities(GDBusConnection *connection,
|
|||||||
|
|
||||||
static struct notification *dbus_message_to_notification(const gchar *sender, GVariant *parameters)
|
static struct notification *dbus_message_to_notification(const gchar *sender, GVariant *parameters)
|
||||||
{
|
{
|
||||||
|
/* Assert that the parameters' type is actually correct. Albeit usually DBus
|
||||||
|
* already rejects ill typed parameters, it may not be always the case. */
|
||||||
|
GVariantType *required_type = g_variant_type_new("(susssasa{sv}i)");
|
||||||
|
if (!g_variant_is_of_type(parameters, required_type)) {
|
||||||
|
g_variant_type_free(required_type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
struct notification *n = notification_create();
|
struct notification *n = notification_create();
|
||||||
|
|
||||||
n->dbus_client = g_strdup(sender);
|
n->dbus_client = g_strdup(sender);
|
||||||
n->dbus_valid = true;
|
n->dbus_valid = true;
|
||||||
|
|
||||||
{
|
GVariant *hints;
|
||||||
GVariantIter *iter = g_variant_iter_new(parameters);
|
gchar **actions;
|
||||||
GVariant *content;
|
int timeout;
|
||||||
GVariant *dict_value;
|
|
||||||
int idx = 0;
|
|
||||||
while ((content = g_variant_iter_next_value(iter))) {
|
|
||||||
|
|
||||||
switch (idx) {
|
GVariantIter i;
|
||||||
case 0:
|
g_variant_iter_init(&i, parameters);
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
|
|
||||||
n->appname = g_variant_dup_string(content, NULL);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_UINT32))
|
|
||||||
n->id = g_variant_get_uint32(content);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
|
|
||||||
n->icon = g_variant_dup_string(content, NULL);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
|
|
||||||
n->summary = g_variant_dup_string(content, NULL);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING))
|
|
||||||
n->body = g_variant_dup_string(content, NULL);
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_STRING_ARRAY)) {
|
|
||||||
gsize amount;
|
|
||||||
const gchar **out = g_variant_get_strv(content, &amount);
|
|
||||||
|
|
||||||
for(gsize i = 0; i+1 < amount; i+=2)
|
g_variant_iter_next(&i, "s", &n->appname);
|
||||||
g_hash_table_insert(n->actions, g_strdup(out[i]), g_strdup(out[i+1]));
|
g_variant_iter_next(&i, "u", &n->id);
|
||||||
|
g_variant_iter_next(&i, "s", &n->icon);
|
||||||
|
g_variant_iter_next(&i, "s", &n->summary);
|
||||||
|
g_variant_iter_next(&i, "s", &n->body);
|
||||||
|
g_variant_iter_next(&i, "^a&s", &actions);
|
||||||
|
g_variant_iter_next(&i, "@a{?*}", &hints);
|
||||||
|
g_variant_iter_next(&i, "i", &timeout);
|
||||||
|
|
||||||
g_free(out);
|
gsize num = 0;
|
||||||
|
while (actions[num]) {
|
||||||
|
if (actions[num+1]) {
|
||||||
|
g_hash_table_insert(n->actions,
|
||||||
|
g_strdup(actions[num]),
|
||||||
|
g_strdup(actions[num+1]));
|
||||||
|
num+=2;
|
||||||
|
} else {
|
||||||
|
LOG_W("Odd length in actions array. Ignoring element: %s", actions[num]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_DICTIONARY)) {
|
|
||||||
|
|
||||||
dict_value = g_variant_lookup_value(content, "urgency", G_VARIANT_TYPE_BYTE);
|
GVariant *dict_value;
|
||||||
if (dict_value) {
|
if ((dict_value = g_variant_lookup_value(hints, "urgency", G_VARIANT_TYPE_BYTE))) {
|
||||||
n->urgency = g_variant_get_byte(dict_value);
|
n->urgency = g_variant_get_byte(dict_value);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_value = g_variant_lookup_value(content, "fgcolor", G_VARIANT_TYPE_STRING);
|
if ((dict_value = g_variant_lookup_value(hints, "fgcolor", G_VARIANT_TYPE_STRING))) {
|
||||||
if (dict_value) {
|
|
||||||
n->colors.fg = g_variant_dup_string(dict_value, NULL);
|
n->colors.fg = g_variant_dup_string(dict_value, NULL);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_value = g_variant_lookup_value(content, "bgcolor", G_VARIANT_TYPE_STRING);
|
if ((dict_value = g_variant_lookup_value(hints, "bgcolor", G_VARIANT_TYPE_STRING))) {
|
||||||
if (dict_value) {
|
|
||||||
n->colors.bg = g_variant_dup_string(dict_value, NULL);
|
n->colors.bg = g_variant_dup_string(dict_value, NULL);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_value = g_variant_lookup_value(content, "frcolor", G_VARIANT_TYPE_STRING);
|
if ((dict_value = g_variant_lookup_value(hints, "frcolor", G_VARIANT_TYPE_STRING))) {
|
||||||
if (dict_value) {
|
|
||||||
n->colors.frame = g_variant_dup_string(dict_value, NULL);
|
n->colors.frame = g_variant_dup_string(dict_value, NULL);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_value = g_variant_lookup_value(content, "category", G_VARIANT_TYPE_STRING);
|
if ((dict_value = g_variant_lookup_value(hints, "category", G_VARIANT_TYPE_STRING))) {
|
||||||
if (dict_value) {
|
|
||||||
n->category = g_variant_dup_string(dict_value, NULL);
|
n->category = g_variant_dup_string(dict_value, NULL);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_value = g_variant_lookup_value(content, "image-path", G_VARIANT_TYPE_STRING);
|
if ((dict_value = g_variant_lookup_value(hints, "image-path", G_VARIANT_TYPE_STRING))) {
|
||||||
if (dict_value) {
|
|
||||||
g_free(n->icon);
|
g_free(n->icon);
|
||||||
n->icon = g_variant_dup_string(dict_value, NULL);
|
n->icon = g_variant_dup_string(dict_value, NULL);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_value = g_variant_lookup_value(content, "image-data", G_VARIANT_TYPE("(iiibiiay)"));
|
dict_value = g_variant_lookup_value(hints, "image-data", G_VARIANT_TYPE("(iiibiiay)"));
|
||||||
if (!dict_value)
|
if (!dict_value)
|
||||||
dict_value = g_variant_lookup_value(content, "image_data", G_VARIANT_TYPE("(iiibiiay)"));
|
dict_value = g_variant_lookup_value(hints, "image_data", G_VARIANT_TYPE("(iiibiiay)"));
|
||||||
if (!dict_value)
|
if (!dict_value)
|
||||||
dict_value = g_variant_lookup_value(content, "icon_data", G_VARIANT_TYPE("(iiibiiay)"));
|
dict_value = g_variant_lookup_value(hints, "icon_data", G_VARIANT_TYPE("(iiibiiay)"));
|
||||||
if (dict_value) {
|
if (dict_value) {
|
||||||
n->raw_icon = get_raw_image_from_data_hint(dict_value);
|
n->raw_icon = get_raw_image_from_data_hint(dict_value);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
@ -243,21 +231,21 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
|
|||||||
* But notify-send does not support hints of type 'boolean'.
|
* But notify-send does not support hints of type 'boolean'.
|
||||||
* So let's check for int and boolean until notify-send is fixed.
|
* So let's check for int and boolean until notify-send is fixed.
|
||||||
*/
|
*/
|
||||||
if((dict_value = g_variant_lookup_value(content, "transient", G_VARIANT_TYPE_BOOLEAN))) {
|
if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_BOOLEAN))) {
|
||||||
n->transient = g_variant_get_boolean(dict_value);
|
n->transient = g_variant_get_boolean(dict_value);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
} else if((dict_value = g_variant_lookup_value(content, "transient", G_VARIANT_TYPE_UINT32))) {
|
} else if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_UINT32))) {
|
||||||
n->transient = g_variant_get_uint32(dict_value) > 0;
|
n->transient = g_variant_get_uint32(dict_value) > 0;
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
} else if((dict_value = g_variant_lookup_value(content, "transient", G_VARIANT_TYPE_INT32))) {
|
} else if ((dict_value = g_variant_lookup_value(hints, "transient", G_VARIANT_TYPE_INT32))) {
|
||||||
n->transient = g_variant_get_int32(dict_value) > 0;
|
n->transient = g_variant_get_int32(dict_value) > 0;
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((dict_value = g_variant_lookup_value(content, "value", G_VARIANT_TYPE_INT32))) {
|
if ((dict_value = g_variant_lookup_value(hints, "value", G_VARIANT_TYPE_INT32))) {
|
||||||
n->progress = g_variant_get_int32(dict_value);
|
n->progress = g_variant_get_int32(dict_value);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
} else if((dict_value = g_variant_lookup_value(content, "value", G_VARIANT_TYPE_UINT32))) {
|
} else if ((dict_value = g_variant_lookup_value(hints, "value", G_VARIANT_TYPE_UINT32))) {
|
||||||
n->progress = g_variant_get_uint32(dict_value);
|
n->progress = g_variant_get_uint32(dict_value);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
}
|
}
|
||||||
@ -267,27 +255,19 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
|
|||||||
* Only accept to first one we find.
|
* Only accept to first one we find.
|
||||||
*/
|
*/
|
||||||
for (int i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i) {
|
for (int i = 0; i < sizeof(stack_tag_hints)/sizeof(*stack_tag_hints); ++i) {
|
||||||
dict_value = g_variant_lookup_value(content, stack_tag_hints[i], G_VARIANT_TYPE_STRING);
|
if ((dict_value = g_variant_lookup_value(hints, stack_tag_hints[i], G_VARIANT_TYPE_STRING))) {
|
||||||
if (dict_value) {
|
|
||||||
n->stack_tag = g_variant_dup_string(dict_value, NULL);
|
n->stack_tag = g_variant_dup_string(dict_value, NULL);
|
||||||
g_variant_unref(dict_value);
|
g_variant_unref(dict_value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (timeout >= 0)
|
||||||
break;
|
n->timeout = timeout * 1000;
|
||||||
case 7:
|
|
||||||
if (g_variant_is_of_type(content, G_VARIANT_TYPE_INT32))
|
|
||||||
n->timeout = g_variant_get_int32(content) * 1000;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
g_variant_unref(content);
|
|
||||||
idx++;
|
|
||||||
}
|
|
||||||
|
|
||||||
g_variant_iter_free(iter);
|
g_variant_unref(hints);
|
||||||
}
|
g_variant_type_free(required_type);
|
||||||
|
g_free(actions); // the strv is only a shallow copy
|
||||||
|
|
||||||
notification_init(n);
|
notification_init(n);
|
||||||
return n;
|
return n;
|
||||||
@ -299,6 +279,13 @@ static void on_notify(GDBusConnection *connection,
|
|||||||
GDBusMethodInvocation *invocation)
|
GDBusMethodInvocation *invocation)
|
||||||
{
|
{
|
||||||
struct notification *n = dbus_message_to_notification(sender, parameters);
|
struct notification *n = dbus_message_to_notification(sender, parameters);
|
||||||
|
if (!n) {
|
||||||
|
g_dbus_method_invocation_return_dbus_error(
|
||||||
|
invocation,
|
||||||
|
"Cannot decode notification!",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
|
||||||
int id = queues_notification_insert(n);
|
int id = queues_notification_insert(n);
|
||||||
|
|
||||||
GVariant *reply = g_variant_new("(u)", id);
|
GVariant *reply = g_variant_new("(u)", id);
|
||||||
|
13
test/dbus.c
13
test/dbus.c
@ -145,6 +145,18 @@ TEST test_dbus_teardown(void)
|
|||||||
PASS();
|
PASS();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST test_invalid_notification(void)
|
||||||
|
{
|
||||||
|
GVariant *faulty = g_variant_new_boolean(true);
|
||||||
|
|
||||||
|
ASSERT(NULL == dbus_message_to_notification(":123", faulty));
|
||||||
|
ASSERT(NULL == dbus_invoke("Notify", faulty));
|
||||||
|
|
||||||
|
g_variant_unref(faulty);
|
||||||
|
PASS();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST test_basic_notification(void)
|
TEST test_basic_notification(void)
|
||||||
{
|
{
|
||||||
struct dbus_notification *n = dbus_notification_new();
|
struct dbus_notification *n = dbus_notification_new();
|
||||||
@ -210,6 +222,7 @@ gpointer run_threaded_tests(gpointer data)
|
|||||||
RUN_TEST(test_dbus_init);
|
RUN_TEST(test_dbus_init);
|
||||||
|
|
||||||
RUN_TEST(test_basic_notification);
|
RUN_TEST(test_basic_notification);
|
||||||
|
RUN_TEST(test_invalid_notification);
|
||||||
RUN_TESTp(test_server_caps, MARKUP_FULL);
|
RUN_TESTp(test_server_caps, MARKUP_FULL);
|
||||||
RUN_TESTp(test_server_caps, MARKUP_STRIP);
|
RUN_TESTp(test_server_caps, MARKUP_STRIP);
|
||||||
RUN_TESTp(test_server_caps, MARKUP_NO);
|
RUN_TESTp(test_server_caps, MARKUP_NO);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user