Implement refcounting for notifications

This commit is contained in:
Benedikt Heine 2018-07-06 19:41:02 +02:00
parent c5c4b2cafb
commit 837b4fe125
5 changed files with 54 additions and 12 deletions

View File

@ -282,7 +282,7 @@ static void on_notify(GDBusConnection *connection,
// The message got discarded // The message got discarded
if (id == 0) { if (id == 0) {
signal_notification_closed(n, 2); signal_notification_closed(n, 2);
notification_free(n); notification_unref(n);
} }
wake_up(); wake_up();

View File

@ -42,6 +42,10 @@ const char *enum_to_string_fullscreen(enum behavior_fullscreen in)
} }
} }
struct _notification_private {
gint refcount;
};
/* see notification.h */ /* see notification.h */
void notification_print(const struct notification *n) void notification_print(const struct notification *n)
{ {
@ -206,12 +210,28 @@ void rawimage_free(struct raw_image *i)
g_free(i); g_free(i);
} }
static void notification_private_free(NotificationPrivate *p)
{
g_free(p);
}
/* see notification.h */ /* see notification.h */
void notification_free(struct notification *n) void notification_ref(struct notification *n)
{
assert(n->priv->refcount > 0);
g_atomic_int_inc(&n->priv->refcount);
}
/* see notification.h */
void notification_unref(struct notification *n)
{ {
if (!n) if (!n)
return; return;
assert(n->priv->refcount > 0);
if (!g_atomic_int_dec_and_test(&n->priv->refcount))
return;
g_free(n->appname); g_free(n->appname);
g_free(n->summary); g_free(n->summary);
g_free(n->body); g_free(n->body);
@ -228,6 +248,8 @@ void notification_free(struct notification *n)
actions_free(n->actions); actions_free(n->actions);
rawimage_free(n->raw_icon); rawimage_free(n->raw_icon);
notification_private_free(n->priv);
g_free(n); g_free(n);
} }
@ -255,11 +277,21 @@ void notification_replace_single_field(char **haystack,
g_free(input); g_free(input);
} }
static NotificationPrivate *notification_private_create(void)
{
NotificationPrivate *priv = g_malloc0(sizeof(NotificationPrivate));
g_atomic_int_set(&priv->refcount, 1);
return priv;
}
/* see notification.h */ /* see notification.h */
struct notification *notification_create(void) struct notification *notification_create(void)
{ {
struct notification *n = g_malloc0(sizeof(struct notification)); struct notification *n = g_malloc0(sizeof(struct notification));
n->priv = notification_private_create();
/* Unparameterized default values */ /* Unparameterized default values */
n->first_render = true; n->first_render = true;
n->markup = settings.markup; n->markup = settings.markup;

View File

@ -42,7 +42,10 @@ struct actions {
gsize count; gsize count;
}; };
typedef struct _notification_private NotificationPrivate;
struct notification { struct notification {
NotificationPrivate *priv;
int id; int id;
char *dbus_client; char *dbus_client;
@ -90,11 +93,18 @@ struct notification {
* - the default (if it's not needed to be freed later) * - the default (if it's not needed to be freed later)
* - its undefined representation (NULL, -1) * - its undefined representation (NULL, -1)
* *
* The reference counter is set to 1.
*
* This function is guaranteed to return a valid pointer. * This function is guaranteed to return a valid pointer.
* @returns The generated notification * @returns The generated notification
*/ */
struct notification *notification_create(void); struct notification *notification_create(void);
/**
* Increase the reference counter of the notification.
*/
void notification_ref(struct notification *n);
/** /**
* Sanitize values of notification, apply all matching rules * Sanitize values of notification, apply all matching rules
* and generate derived fields. * and generate derived fields.
@ -118,11 +128,11 @@ void actions_free(struct actions *a);
void rawimage_free(struct raw_image *i); void rawimage_free(struct raw_image *i);
/** /**
* Free the memory used by the given notification. * Decrease the reference counter of the notification.
* *
* @param n (nullable): pointer to #notification * If the reference count drops to 0, the object gets freed.
*/ */
void notification_free(struct notification *n); void notification_unref(struct notification *n);
/** /**
* Helper function to compare two given notifications. * Helper function to compare two given notifications.

View File

@ -191,7 +191,7 @@ static bool queues_stack_duplicate(struct notification *n)
if ( allqueues[i] == displayed ) if ( allqueues[i] == displayed )
n->start = time_monotonic_now(); n->start = time_monotonic_now();
notification_free(orig); notification_unref(orig);
return true; return true;
} }
} }
@ -218,7 +218,7 @@ bool queues_notification_replace_id(struct notification *new)
notification_run_script(new); notification_run_script(new);
} }
notification_free(old); notification_unref(old);
return true; return true;
} }
} }
@ -278,12 +278,12 @@ void queues_history_push(struct notification *n)
if (!n->history_ignore) { if (!n->history_ignore) {
if (settings.history_length > 0 && history->length >= settings.history_length) { if (settings.history_length > 0 && history->length >= settings.history_length) {
struct notification *to_free = g_queue_pop_head(history); struct notification *to_free = g_queue_pop_head(history);
notification_free(to_free); notification_unref(to_free);
} }
g_queue_push_tail(history, n); g_queue_push_tail(history, n);
} else { } else {
notification_free(n); notification_unref(n);
} }
} }
@ -488,7 +488,7 @@ bool queues_pause_status(void)
static void teardown_notification(gpointer data) static void teardown_notification(gpointer data)
{ {
struct notification *n = data; struct notification *n = data;
notification_free(n); notification_unref(n);
} }
/* see queues.h */ /* see queues.h */

View File

@ -121,8 +121,8 @@ SUITE(suite_notification)
struct notification *n[2] = {a, b}; struct notification *n[2] = {a, b};
RUN_TEST1(test_notification_is_duplicate, (void*) n); RUN_TEST1(test_notification_is_duplicate, (void*) n);
notification_free(a); notification_unref(a);
notification_free(b); notification_unref(b);
RUN_TEST(test_notification_replace_single_field); RUN_TEST(test_notification_replace_single_field);