messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/application.c | 39+++++++++++++++++++++++++++++++++++----
Msrc/event.c | 14+++++++-------
Msrc/file.c | 8++++----
Msrc/meson.build | 2+-
Msrc/request.c | 9+++++----
Msrc/ui/accounts.c | 4++--
Msrc/ui/chat.c | 18++++++++----------
Msrc/ui/chat_entry.c | 4+++-
Msrc/ui/contacts.c | 2+-
Msrc/ui/messenger.c | 6+++---
Msrc/ui/new_account.c | 2+-
Msrc/ui/play_media.c | 16++++++++--------
Msrc/ui/send_file.c | 8+++++---
Asrc/util.c | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/util.h | 46++++++++++++++++++++++++++++++++++++++++++++++
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_ */