commit 40e11dc56e320eba25dec0036733d4409d37ff47
parent 03cfa31ddd0c86e654a7843b3827416dc40e23fd
Author: Jacki <jacki@thejackimonster.de>
Date: Tue, 23 Apr 2024 03:45:32 +0200
Abstraction of glib scheduling functions to cancel all tasks at once
Signed-off-by: Jacki <jacki@thejackimonster.de>
Diffstat:
15 files changed, 339 insertions(+), 49 deletions(-)
diff --git a/src/application.c b/src/application.c
@@ -87,7 +87,7 @@ _application_init(MESSENGER_Application *app)
if (app->chat.identity)
application_show_window(app);
else
- app->init = g_idle_add(G_SOURCE_FUNC(_application_accounts), app);
+ app->init = util_idle_add(G_SOURCE_FUNC(_application_accounts), app);
}
static void
@@ -639,7 +639,25 @@ application_call_event(MESSENGER_Application *app,
call->app = app;
call->event = event;
- g_timeout_add(0, G_SOURCE_FUNC(_application_event_call), call);
+ util_idle_add(G_SOURCE_FUNC(_application_event_call), call);
+}
+
+static gboolean
+_application_sync_event_call(gpointer user_data)
+{
+ g_assert(user_data);
+
+ MESSENGER_ApplicationEventCall *call;
+
+ call = (MESSENGER_ApplicationEventCall*) user_data;
+
+ call->event(call->app);
+ util_scheduler_cleanup();
+
+ pthread_mutex_unlock(&(call->app->chat.mutex));
+
+ GNUNET_free(call);
+ return FALSE;
}
void
@@ -648,7 +666,20 @@ application_call_sync_event(MESSENGER_Application *app,
{
g_assert((app) && (event));
- event(app);
+ MESSENGER_ApplicationEventCall *call;
+
+ call = (MESSENGER_ApplicationEventCall*) GNUNET_malloc(
+ sizeof(MESSENGER_ApplicationEventCall)
+ );
+
+ call->app = app;
+ call->event = event;
+
+ util_scheduler_cleanup();
+ util_idle_add(G_SOURCE_FUNC(_application_sync_event_call), call);
+
+ // Locking the mutex for synchronization
+ pthread_mutex_lock(&(app->chat.mutex));
}
typedef struct MESSENGER_ApplicationMessageEventCall
@@ -698,7 +729,7 @@ application_call_message_event(MESSENGER_Application *app,
call->context = context;
call->message = message;
- g_idle_add(G_SOURCE_FUNC(_application_message_event_call), call);
+ util_idle_add(G_SOURCE_FUNC(_application_message_event_call), call);
}
void
diff --git a/src/event.c b/src/event.c
@@ -142,10 +142,10 @@ event_refresh_accounts(MESSENGER_Application *app)
g_assert(app);
if (app->ui.messenger.account_refresh)
- g_source_remove(app->ui.messenger.account_refresh);
+ util_source_remove(app->ui.messenger.account_refresh);
if (app->ui.messenger.main_window)
- app->ui.messenger.account_refresh = g_idle_add(
+ app->ui.messenger.account_refresh = util_idle_add(
G_SOURCE_FUNC(_idle_refresh_accounts),
app
);
@@ -217,9 +217,9 @@ enqueue_chat_entry_update(UI_CHAT_ENTRY_Handle *entry)
g_assert(entry);
if (entry->update)
- g_source_remove(entry->update);
+ util_source_remove(entry->update);
- entry->update = g_idle_add(
+ entry->update = util_idle_add(
G_SOURCE_FUNC(_idle_chat_entry_update),
entry
);
@@ -261,9 +261,9 @@ _add_new_chat_entry(MESSENGER_Application *app,
);
if (ui->chat_selection)
- g_source_remove(ui->chat_selection);
+ util_source_remove(ui->chat_selection);
- ui->chat_selection = g_idle_add(
+ ui->chat_selection = util_idle_add(
G_SOURCE_FUNC(_select_chat_to_activate),
entry
);
@@ -440,7 +440,7 @@ event_update_chats(MESSENGER_Application *app,
enqueue_chat_entry_update(handle);
if (app->settings.leave_chats_delay > 0)
- g_timeout_add_seconds(
+ util_timeout_add_seconds(
app->settings.leave_chats_delay,
_delayed_context_drop,
context
diff --git a/src/file.c b/src/file.c
@@ -64,7 +64,7 @@ file_destroy_info(struct GNUNET_CHAT_File *file)
file_unload_preview_image(file);
if (info->update_task)
- g_source_remove(info->update_task);
+ util_source_remove(info->update_task);
if (info->file_messages)
g_list_free(info->file_messages);
@@ -202,7 +202,7 @@ file_update_download_info(const struct GNUNET_CHAT_File *file,
return;
info->app = app;
- info->update_task = g_idle_add(file_update_messages, info);
+ info->update_task = util_idle_add(file_update_messages, info);
}
static void
@@ -269,7 +269,7 @@ file_unload_preview_image(const struct GNUNET_CHAT_File *file)
if (info->redraw_animation_task)
{
- g_source_remove(info->redraw_animation_task);
+ util_source_remove(info->redraw_animation_task);
info->redraw_animation_task = 0;
}
@@ -328,7 +328,7 @@ file_get_current_preview_image(const struct GNUNET_CHAT_File *file)
info->preview_animation_iter
);
- info->redraw_animation_task = g_timeout_add(
+ info->redraw_animation_task = util_timeout_add(
delay, file_redraw_animation, info
);
}
diff --git a/src/meson.build b/src/meson.build
@@ -29,6 +29,6 @@ messenger_gtk_sources = files([
'request.c', 'request.h',
'resources.c', 'resources.h',
'ui.c', 'ui.h',
- 'util.h',
+ 'util.c', 'util.h',
'messenger_gtk.c',
]) + messenger_gtk_chat_sources + messenger_gtk_ui_sources
diff --git a/src/request.c b/src/request.c
@@ -64,8 +64,9 @@ request_new(MESSENGER_Application *application,
request->user_data = user_data;
#ifdef MESSENGER_APPLICATION_NO_PORTAL
- request->timeout = g_timeout_add(
- 0, G_SOURCE_FUNC(_request_timeout_call), request
+ request->timeout = util_idle_add(
+ G_SOURCE_FUNC(_request_timeout_call),
+ request
);
#endif
@@ -228,7 +229,7 @@ request_cancel(MESSENGER_Request *request)
#ifdef MESSENGER_APPLICATION_NO_PORTAL
if (request->timeout)
- g_source_remove(request->timeout);
+ util_source_remove(request->timeout);
request->timeout = 0;
#endif
@@ -247,7 +248,7 @@ request_cleanup(MESSENGER_Request *request)
#ifdef MESSENGER_APPLICATION_NO_PORTAL
if (request->timeout)
- g_source_remove(request->timeout);
+ util_source_remove(request->timeout);
request->timeout = 0;
#endif
diff --git a/src/ui/accounts.c b/src/ui/accounts.c
@@ -77,7 +77,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox,
// Drop activations of rows which do not contain accounts
if (!gtk_list_box_row_get_selectable(row))
{
- app->ui.accounts.show_queued = g_idle_add(
+ app->ui.accounts.show_queued = util_idle_add(
G_SOURCE_FUNC(_open_new_account_dialog), app
);
@@ -93,7 +93,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox,
// Handle the GUI swap asyncronously
if (!gtk_widget_is_visible(GTK_WIDGET(app->ui.messenger.main_window)))
- app->ui.accounts.show_queued = g_idle_add(
+ app->ui.accounts.show_queued = util_idle_add(
G_SOURCE_FUNC(_show_messenger_main_window), app
);
diff --git a/src/ui/chat.c b/src/ui/chat.c
@@ -72,7 +72,7 @@ handle_chat_details_via_button_click(UNUSED GtkButton* button,
UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
gtk_widget_set_sensitive(GTK_WIDGET(handle->messages_listbox), FALSE);
- g_idle_add(
+ util_idle_add(
G_SOURCE_FUNC(_flap_chat_details_reveal_switch),
handle
);
@@ -1092,7 +1092,7 @@ _stop_playing_recording(UI_CHAT_Handle *handle,
if (handle->play_timer)
{
- g_source_remove(handle->play_timer);
+ util_source_remove(handle->play_timer);
handle->play_timer = 0;
}
}
@@ -1197,7 +1197,7 @@ _record_timer_func(gpointer user_data)
if (!(handle->recorded))
{
handle->record_time++;
- handle->record_timer = g_timeout_add_seconds(
+ handle->record_timer = util_timeout_add_seconds(
1,
_record_timer_func,
handle
@@ -1230,7 +1230,7 @@ _play_timer_func(gpointer user_data)
if (handle->playing)
{
handle->play_time++;
- handle->play_timer = g_timeout_add(
+ handle->play_timer = util_timeout_add(
10,
_play_timer_func,
handle
@@ -1256,8 +1256,7 @@ handle_record_bus_watch(UNUSED GstBus *bus,
{
case GST_MESSAGE_STREAM_START:
handle->record_time = 0;
- handle->record_timer = g_timeout_add_seconds(
- 0,
+ handle->record_timer = util_idle_add(
_record_timer_func,
handle
);
@@ -1282,8 +1281,7 @@ handle_play_bus_watch(UNUSED GstBus *bus,
{
case GST_MESSAGE_STREAM_START:
handle->play_time = 0;
- handle->play_timer = g_timeout_add_seconds(
- 0,
+ handle->play_timer = util_idle_add(
_play_timer_func,
handle
);
@@ -2320,10 +2318,10 @@ ui_chat_delete(UI_CHAT_Handle *handle)
remove(handle->recording_filename);
if (handle->record_timer)
- g_source_remove(handle->record_timer);
+ util_source_remove(handle->record_timer);
if (handle->play_timer)
- g_source_remove(handle->play_timer);
+ util_source_remove(handle->play_timer);
g_free(handle);
}
diff --git a/src/ui/chat_entry.c b/src/ui/chat_entry.c
@@ -242,7 +242,7 @@ ui_chat_entry_delete(UI_CHAT_ENTRY_Handle *handle)
g_object_unref(handle->builder);
if (handle->update)
- g_source_remove(handle->update);
+ util_source_remove(handle->update);
g_free(handle);
}
@@ -255,6 +255,8 @@ ui_chat_entry_dispose(UI_CHAT_ENTRY_Handle *handle,
UI_MESSENGER_Handle *ui = &(app->ui.messenger);
+ util_source_remove_by_data(handle);
+
ui->chat_entries = g_list_remove(ui->chat_entries, handle);
gtk_container_remove(
diff --git a/src/ui/contacts.c b/src/ui/contacts.c
@@ -62,7 +62,7 @@ handle_contacts_listbox_row_activated(UNUSED GtkListBox* listbox,
if (!gtk_list_box_row_get_selectable(row))
{
- g_idle_add(G_SOURCE_FUNC(_open_new_contact_dialog), app);
+ util_idle_add(G_SOURCE_FUNC(_open_new_contact_dialog), app);
goto close_dialog;
}
diff --git a/src/ui/messenger.c b/src/ui/messenger.c
@@ -85,7 +85,7 @@ handle_user_details_via_button_click(UNUSED GtkButton* button,
gtk_widget_set_sensitive(GTK_WIDGET(handle->chats_search), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(handle->chats_listbox), FALSE);
- g_idle_add(
+ util_idle_add(
G_SOURCE_FUNC(_flap_user_details_reveal_switch),
handle
);
@@ -801,10 +801,10 @@ ui_messenger_cleanup(UI_MESSENGER_Handle *handle)
g_list_free_full(handle->chat_entries, (GDestroyNotify) ui_chat_entry_delete);
if (handle->chat_selection)
- g_source_remove(handle->chat_selection);
+ util_source_remove(handle->chat_selection);
if (handle->account_refresh)
- g_source_remove(handle->account_refresh);
+ util_source_remove(handle->account_refresh);
memset(handle, 0, sizeof(*handle));
}
diff --git a/src/ui/new_account.c b/src/ui/new_account.c
@@ -57,7 +57,7 @@ _open_new_account(GtkEntry *entry,
app->chat.identity = GNUNET_strdup(name);
if (!gtk_widget_is_visible(GTK_WIDGET(app->ui.messenger.main_window)))
- app->ui.new_account.show_queued = g_idle_add(
+ app->ui.new_account.show_queued = util_idle_add(
G_SOURCE_FUNC(_show_messenger_main_window), app
);
}
diff --git a/src/ui/play_media.c b/src/ui/play_media.c
@@ -196,11 +196,11 @@ _set_timeout_callback_of_timeline(UI_PLAY_MEDIA_Handle *handle,
g_assert(handle);
if (handle->timeline)
- g_source_remove(handle->timeline);
+ util_source_remove(handle->timeline);
if (connected)
- handle->timeline = g_timeout_add(
- 1000,
+ handle->timeline = util_timeout_add_seconds(
+ 1,
G_SOURCE_FUNC(_adjust_playing_media_position),
handle
);
@@ -399,7 +399,7 @@ handle_fullscreen_button_click(GtkButton *button,
else
{
if (handle->motion_lost)
- g_source_remove(handle->motion_lost);
+ util_source_remove(handle->motion_lost);
handle->motion_lost = 0;
}
@@ -434,14 +434,14 @@ handle_media_motion_notify(GtkWidget *widget,
return FALSE;
if (handle->motion_lost)
- g_source_remove(handle->motion_lost);
+ util_source_remove(handle->motion_lost);
hdy_flap_set_reveal_flap(handle->controls_flap, TRUE);
if (!(handle->fullscreen))
return FALSE;
- handle->motion_lost = g_timeout_add_seconds(
+ handle->motion_lost = util_timeout_add_seconds(
3,
G_SOURCE_FUNC(handle_media_motion_lost),
handle
@@ -841,10 +841,10 @@ ui_play_media_window_cleanup(UI_PLAY_MEDIA_Handle *handle)
g_object_unref(handle->builder);
if (handle->timeline)
- g_source_remove(handle->timeline);
+ util_source_remove(handle->timeline);
if (handle->motion_lost)
- g_source_remove(handle->motion_lost);
+ util_source_remove(handle->motion_lost);
if (handle->pipeline)
{
diff --git a/src/ui/send_file.c b/src/ui/send_file.c
@@ -186,8 +186,10 @@ handle_file_drawing_area_draw(GtkWidget* drawing_area,
handle->animation_iter
);
- handle->redraw_animation = g_timeout_add(
- delay, handle_file_redraw_animation, handle
+ handle->redraw_animation = util_timeout_add(
+ delay,
+ handle_file_redraw_animation,
+ handle
);
render_image:
@@ -241,7 +243,7 @@ _clear_file_preview_data(UI_SEND_FILE_Handle *handle)
if (handle->redraw_animation)
{
- g_source_remove(handle->redraw_animation);
+ util_source_remove(handle->redraw_animation);
handle->redraw_animation = 0;
}
diff --git a/src/util.c b/src/util.c
@@ -0,0 +1,210 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2024 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/*
+ * @author Tobias Frisch
+ * @file util.c
+ */
+
+#include "util.h"
+
+#include <stdio.h>
+
+static GList *tasks = NULL;
+
+struct UTIL_CompleteTask
+{
+ GSourceFunc function;
+ gpointer data;
+ guint id;
+};
+
+static void
+util_kill_task(gpointer task_data)
+{
+ g_assert(task_data);
+
+ struct UTIL_CompleteTask *task = (struct UTIL_CompleteTask*) task_data;
+
+ if (task->id)
+ g_source_remove(task->id);
+
+ g_free(task);
+}
+
+void
+util_scheduler_cleanup()
+{
+ if (tasks)
+ g_list_free_full(tasks, (GDestroyNotify) util_kill_task);
+
+ tasks = NULL;
+}
+
+static gboolean
+util_complete_task(gpointer task_data)
+{
+ g_assert(task_data);
+
+ struct UTIL_CompleteTask *task = (struct UTIL_CompleteTask*) task_data;
+
+ const GSourceFunc function = task->function;
+ gpointer data = task->data;
+
+ if (tasks)
+ tasks = g_list_remove(tasks, task);
+
+ g_free(task);
+
+ return function(data);
+}
+
+guint
+util_idle_add(GSourceFunc function,
+ gpointer data)
+{
+ struct UTIL_CompleteTask *task = g_malloc(sizeof(struct UTIL_CompleteTask));
+
+ task->function = function;
+ task->data = data;
+ task->id = g_idle_add(
+ G_SOURCE_FUNC(util_complete_task),
+ task
+ );
+
+ tasks = g_list_append(
+ tasks,
+ task
+ );
+
+ return task->id;
+}
+
+guint
+util_timeout_add(guint interval,
+ GSourceFunc function,
+ gpointer data)
+{
+ struct UTIL_CompleteTask *task = g_malloc(sizeof(struct UTIL_CompleteTask));
+
+ task->function = function;
+ task->data = data;
+ task->id = g_timeout_add(
+ interval,
+ G_SOURCE_FUNC(util_complete_task),
+ task
+ );
+
+ tasks = g_list_append(
+ tasks,
+ task
+ );
+
+ return task->id;
+}
+
+guint
+util_timeout_add_seconds(guint interval,
+ GSourceFunc function,
+ gpointer data)
+{
+ struct UTIL_CompleteTask *task = g_malloc(sizeof(struct UTIL_CompleteTask));
+
+ task->function = function;
+ task->data = data;
+ task->id = g_timeout_add_seconds(
+ interval,
+ G_SOURCE_FUNC(util_complete_task),
+ task
+ );
+
+ tasks = g_list_append(
+ tasks,
+ task
+ );
+
+ return task->id;
+}
+
+gboolean
+util_source_remove(guint tag)
+{
+ struct UTIL_CompleteTask *task = NULL;
+ GList *current = tasks;
+
+ while (current)
+ {
+ task = (struct UTIL_CompleteTask*) current->data;
+
+ if (task->id == tag)
+ break;
+
+ current = g_list_next(current);
+ task = NULL;
+ }
+
+ if (!task)
+ return FALSE;
+
+ const gboolean result = g_source_remove(task->id);
+
+ tasks = g_list_remove(tasks, task);
+ g_free(task);
+
+ return result;
+}
+
+gboolean
+util_source_remove_by_data(gpointer data)
+{
+ struct UTIL_CompleteTask *task = NULL;
+ GList *current = tasks;
+ GList *matches = NULL;
+
+ while (current)
+ {
+ task = (struct UTIL_CompleteTask*) current->data;
+
+ if (task->data == data)
+ matches = g_list_append(matches, task);
+
+ current = g_list_next(current);
+ task = NULL;
+ }
+
+ if (!matches)
+ return FALSE;
+
+ gboolean result = TRUE;
+
+ current = matches;
+ while (current)
+ {
+ task = (struct UTIL_CompleteTask*) current->data;
+
+ result &= g_source_remove(task->id);
+ tasks = g_list_remove(tasks, task);
+ g_free(task);
+
+ current = g_list_next(current);
+ }
+
+ g_list_free(matches);
+ return result;
+}
diff --git a/src/util.h b/src/util.h
@@ -36,4 +36,50 @@
) \
)
+/**
+ * Cancel all open asynchronous tasks.
+ */
+void
+util_scheduler_cleanup();
+
+/**
+ * Abstraction of `g_idle_add()` task
+ * to be cancelled externally.
+ */
+guint
+util_idle_add(GSourceFunc function,
+ gpointer data);
+
+/**
+ * Abstraction of `g_timeout_add()` task
+ * to be cancelled externally.
+ */
+guint
+util_timeout_add(guint interval,
+ GSourceFunc function,
+ gpointer data);
+
+/**
+ * Abstraction of `g_timeout_add_seconds()` task
+ * to be cancelled externally.
+ */
+guint
+util_timeout_add_seconds(guint interval,
+ GSourceFunc function,
+ gpointer data);
+
+/**
+ * Abstraction of `g_source_remove()` to
+ * cancel a task by its tag.
+ */
+gboolean
+util_source_remove(guint tag);
+
+/**
+ * Abstraction of `g_source_remove_by_userdata()` to
+ * cancel a task by its data.
+ */
+gboolean
+util_source_remove_by_data(gpointer data);
+
#endif /* UTIL_H_ */