messenger-gtk

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

commit 3090047dcd647bd1daddf904472a7f909b00f875
parent 43e1bdf4a87b0e6979aa75f36a920e21028c4f74
Author: TheJackiMonster <thejackimonster@gmail.com>
Date:   Sat, 19 Feb 2022 21:31:03 +0100

Refactored setting ui content and binding widgets

Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>

Diffstat:
MMakefile | 1+
Mresources/ui/accounts.ui | 1+
Msrc/application.c | 4++--
Msrc/application.h | 5+++--
Asrc/bindings.c | 129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/bindings.h | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/event.c | 81+++++++++++++++++++++----------------------------------------------------------
Msrc/ui/account_entry.c | 26++++++++++++++++++++++++++
Msrc/ui/account_entry.h | 8++++++++
Msrc/ui/accounts.c | 57+++++++++++++++------------------------------------------
Msrc/ui/accounts.h | 4++--
Msrc/ui/chat.c | 94+++++++++++++++++++++----------------------------------------------------------
Msrc/ui/chat_entry.c | 4++++
Msrc/ui/chat_entry.h | 3+++
Msrc/ui/contact_entry.c | 25+++++++++++++++++++++++++
Msrc/ui/contact_entry.h | 4++++
Msrc/ui/contacts.c | 83+++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ui/contacts.h | 6+++---
Msrc/ui/delete_messages.c | 2+-
Msrc/ui/delete_messages.h | 2+-
Msrc/ui/invite_contact.c | 93++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Msrc/ui/invite_contact.h | 6+++---
Msrc/ui/message.c | 78++++++++++++++++++++++++++++++++++--------------------------------------------
Msrc/ui/message.h | 4+---
Msrc/ui/messenger.c | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Msrc/ui/messenger.h | 7++++++-
Msrc/ui/new_group.c | 22+++++-----------------
Msrc/ui/send_file.c | 6+++---
28 files changed, 561 insertions(+), 347 deletions(-)

diff --git a/Makefile b/Makefile @@ -8,6 +8,7 @@ INSTALL_DIR ?= /usr/local/ BINARY = messenger-gtk SOURCES = messenger_gtk.c\ application.c\ + bindings.c\ contact.c\ event.c\ file.c\ diff --git a/resources/ui/accounts.ui b/resources/ui/accounts.ui @@ -72,6 +72,7 @@ Author: Tobias Frisch <object class="GtkListBox" id="accounts_listbox"> <property name="visible">True</property> <property name="can-focus">False</property> + <property name="selection-mode">none</property> <child> <object class="GtkListBoxRow"> <property name="visible">True</property> diff --git a/src/application.c b/src/application.c @@ -100,7 +100,7 @@ application_init(MESSENGER_Application *app, pthread_mutex_init(&(app->chat.mutex), NULL); - app->ui.bindings = g_hash_table_new(g_direct_hash, g_direct_equal); + app->bindings = bindings_create(); g_application_add_main_option( G_APPLICATION(app->application), @@ -195,7 +195,7 @@ application_run(MESSENGER_Application *app) pthread_join(app->chat.tid, NULL); - g_hash_table_destroy(app->ui.bindings); + bindings_destroy(app->bindings); close(app->chat.pipe[0]); close(app->chat.pipe[1]); diff --git a/src/application.h b/src/application.h @@ -42,6 +42,7 @@ #include "ui/send_file.h" #include "ui/settings.h" +#include "bindings.h" #include "util.h" typedef enum MESSENGER_ApplicationSignal @@ -59,6 +60,8 @@ typedef struct MESSENGER_Application GtkApplication *application; GList *notifications; + MESSENGER_Bindings *bindings; + struct { int status; pthread_t tid; @@ -73,8 +76,6 @@ typedef struct MESSENGER_Application struct { int status; - GHashTable *bindings; - UI_MESSENGER_Handle messenger; UI_INVITE_CONTACT_Handle invite_contact; diff --git a/src/bindings.c b/src/bindings.c @@ -0,0 +1,129 @@ +/* + This file is part of GNUnet. + Copyright (C) 2022 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 bindings.h + */ + +#include "bindings.h" +#include "util.h" + +MESSENGER_Bindings* +bindings_create() +{ + MESSENGER_Bindings *bindings = GNUNET_new(MESSENGER_Bindings); + + bindings->map = GNUNET_CONTAINER_multishortmap_create(8, GNUNET_NO); + + return bindings; +} + +void +bindings_put(MESSENGER_Bindings *bindings, + gconstpointer key, + gpointer value) +{ + struct GNUNET_ShortHashCode hash; + memset(&hash, 0, sizeof(hash)); + memcpy(&hash, &key, sizeof(key)); + + GNUNET_CONTAINER_multishortmap_put( + bindings->map, + &hash, + (void*) value, + GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE + ); +} + +int +_bindings_append_list(void *cls, + UNUSED const struct GNUNET_ShortHashCode *key, + void *value) +{ + GList **list = (GList**) cls; + *list = g_list_append(*list, (gpointer) value); + return GNUNET_YES; +} + +void +bindings_remove(MESSENGER_Bindings *bindings, + const void *key, + void *value, + void (destroy)(void*)) +{ + struct GNUNET_ShortHashCode hash; + memset(&hash, 0, sizeof(hash)); + memcpy(&hash, &key, sizeof(key)); + + if (value) + { + GNUNET_CONTAINER_multishortmap_remove( + bindings->map, + &hash, + (void*) value + ); + + if (destroy) + destroy(value); + } + else + { + GList *values = NULL; + + GNUNET_CONTAINER_multishortmap_get_multiple( + bindings->map, + &hash, + _bindings_append_list, + &values + ); + + GNUNET_CONTAINER_multishortmap_remove_all( + bindings->map, + &hash + ); + + if (destroy) + g_list_free_full(values, destroy); + else + g_list_free(values); + } +} + +void* +bindings_get(const MESSENGER_Bindings *bindings, + const void *key) +{ + struct GNUNET_ShortHashCode hash; + memset(&hash, 0, sizeof(hash)); + memcpy(&hash, &key, sizeof(key)); + + return GNUNET_CONTAINER_multishortmap_get( + bindings->map, + &hash + ); +} + +void +bindings_destroy(MESSENGER_Bindings *bindings) +{ + GNUNET_CONTAINER_multishortmap_destroy(bindings->map); + + GNUNET_free(bindings); +} diff --git a/src/bindings.h b/src/bindings.h @@ -0,0 +1,60 @@ +/* + This file is part of GNUnet. + Copyright (C) 2022 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 bindings.h + */ + +#ifndef BINDINGS_H_ +#define BINDINGS_H_ + +#include <gnunet/platform.h> +#include <gnunet/gnunet_common.h> +#include <gnunet/gnunet_container_lib.h> + +#include <glib.h> + +typedef struct MESSENGER_Bindings +{ + struct GNUNET_CONTAINER_MultiShortmap *map; +} MESSENGER_Bindings; + +MESSENGER_Bindings* +bindings_create(); + +void +bindings_put(MESSENGER_Bindings *bindings, + gconstpointer key, + gpointer value); + +void +bindings_remove(MESSENGER_Bindings *bindings, + gconstpointer key, + gpointer value, + GDestroyNotify destroy); + +void* +bindings_get(const MESSENGER_Bindings *bindings, + gconstpointer key); + +void +bindings_destroy(MESSENGER_Bindings *bindings); + +#endif /* BINDINGS_H_ */ diff --git a/src/event.c b/src/event.c @@ -93,57 +93,11 @@ _clear_each_selectable_widget(GtkWidget *widget, gtk_container_remove(container, widget); } -static int -_iterate_accounts(void *cls, - const struct GNUNET_CHAT_Handle *handle, - struct GNUNET_CHAT_Account *account) -{ - MESSENGER_Application *app = (MESSENGER_Application*) cls; - UI_MESSENGER_Handle *ui = &(app->ui.messenger); - - const gchar *name = GNUNET_CHAT_account_get_name(account); - - UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app); - - hdy_avatar_set_text(entry->entry_avatar, name); - gtk_label_set_text(entry->entry_label, name); - - gtk_list_box_prepend(ui->accounts_listbox, entry->entry_box); - - GtkListBoxRow *row = GTK_LIST_BOX_ROW( - gtk_widget_get_parent(entry->entry_box) - ); - - g_hash_table_insert(ui->bindings, row, account); - - if ((account == GNUNET_CHAT_get_connected(handle)) || - ((app->chat.identity) && (0 == g_strcmp0(app->chat.identity, name)))) - gtk_widget_activate(GTK_WIDGET(row)); - - ui_account_entry_delete(entry); - return GNUNET_YES; -} - void event_refresh_accounts(MESSENGER_Application *app) { - UI_MESSENGER_Handle *ui = &(app->ui.messenger); - CHAT_MESSENGER_Handle *chat = &(app->chat.messenger); - ui_accounts_dialog_refresh(app, &(app->ui.accounts)); - - if (!(ui->accounts_listbox)) - return; - - gtk_list_box_unselect_all(ui->accounts_listbox); - - gtk_container_foreach( - GTK_CONTAINER(ui->accounts_listbox), - _clear_each_selectable_widget, - ui->accounts_listbox - ); - - GNUNET_CHAT_iterate_accounts(chat->handle, _iterate_accounts, app); + ui_messenger_refresh(app, &(app->ui.messenger)); } static void @@ -163,11 +117,7 @@ _add_new_chat_entry(MESSENGER_Application *app, entry->chat->chat_box ); - g_hash_table_insert( - app->ui.bindings, - entry->chat->send_text_view, - context - ); + bindings_put(app->bindings, entry->chat->send_text_view, context); ui->chat_entries = g_list_append(ui->chat_entries, entry); @@ -175,11 +125,7 @@ _add_new_chat_entry(MESSENGER_Application *app, gtk_widget_get_parent(entry->entry_box) ); - g_hash_table_insert( - app->ui.bindings, - row, - entry - ); + bindings_put(app->bindings, row, entry); gtk_list_box_select_row(ui->chats_listbox, row); gtk_list_box_invalidate_filter(ui->chats_listbox); @@ -298,13 +244,23 @@ event_joining_contact(MESSENGER_Application *app, if (!handle) return; - UI_MESSAGE_Handle *message = ui_message_new(app, UI_MESSAGE_STATUS); - ui_message_update(message, app, msg); - struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( msg ); + if (!contact) + return; + + UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) ( + bindings_get(handle->joining, contact) + ); + + if (message) + ui_chat_remove_message(handle->chat, app, message); + + message = ui_message_new(app, UI_MESSAGE_STATUS); + ui_message_update(message, app, msg); + contact_create_info(contact); _update_contact_context(app, contact); @@ -332,6 +288,8 @@ event_joining_contact(MESSENGER_Application *app, gtk_label_set_text(message->timestamp_label, time? time : ""); ui_chat_add_message(handle->chat, app, message); + bindings_put(handle->joining, contact, message); + ui_chat_entry_update(handle, app, context); } @@ -344,6 +302,9 @@ event_update_contacts(MESSENGER_Application *app, msg ); + if (!contact) + return; + contact_update_info(contact); _update_contact_context(app, contact); diff --git a/src/ui/account_entry.c b/src/ui/account_entry.c @@ -51,6 +51,32 @@ ui_account_entry_new(MESSENGER_Application *app) } void +ui_account_entry_set_account(UI_ACCOUNT_ENTRY_Handle* handle, + const struct GNUNET_CHAT_Account *account) +{ + const gchar *name = GNUNET_CHAT_account_get_name(account); + + if (!name) + return; + + hdy_avatar_set_text(handle->entry_avatar, name); + gtk_label_set_text(handle->entry_label, name); +} + +void +ui_account_entry_set_contact(UI_ACCOUNT_ENTRY_Handle* handle, + const struct GNUNET_CHAT_Contact *contact) +{ + const gchar *name = GNUNET_CHAT_contact_get_name(contact); + + if (!name) + return; + + hdy_avatar_set_text(handle->entry_avatar, name); + gtk_label_set_text(handle->entry_label, name); +} + +void ui_account_entry_delete(UI_ACCOUNT_ENTRY_Handle *handle) { g_object_unref(handle->builder); diff --git a/src/ui/account_entry.h b/src/ui/account_entry.h @@ -41,6 +41,14 @@ UI_ACCOUNT_ENTRY_Handle* ui_account_entry_new(MESSENGER_Application *app); void +ui_account_entry_set_account(UI_ACCOUNT_ENTRY_Handle* handle, + const struct GNUNET_CHAT_Account *account); + +void +ui_account_entry_set_contact(UI_ACCOUNT_ENTRY_Handle* handle, + const struct GNUNET_CHAT_Contact *contact); + +void ui_account_entry_delete(UI_ACCOUNT_ENTRY_Handle *handle); #endif /* UI_ACCOUNT_ENTRY_H_ */ diff --git a/src/ui/accounts.c b/src/ui/accounts.c @@ -72,7 +72,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, } struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( - g_hash_table_lookup(app->ui.bindings, row) + bindings_get(app->bindings, row) ); if (!account) @@ -109,25 +109,18 @@ _iterate_accounts(void *cls, { MESSENGER_Application *app = (MESSENGER_Application*) cls; - const gchar *name = GNUNET_CHAT_account_get_name(account); - UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app); - hdy_avatar_set_text(entry->entry_avatar, name); - gtk_label_set_text(entry->entry_label, name); + ui_account_entry_set_account(entry, account); gtk_list_box_prepend(app->ui.accounts.accounts_listbox, entry->entry_box); GtkListBoxRow *row = GTK_LIST_BOX_ROW( - gtk_widget_get_parent(entry->entry_box) + gtk_widget_get_parent(entry->entry_box) ); - g_hash_table_insert(app->ui.bindings, row, account); - - app->ui.accounts.account_entries = g_list_append( - app->ui.accounts.account_entries, - entry - ); + bindings_put(app->bindings, row, account); + bindings_put(app->ui.accounts.bindings, row, entry); return GNUNET_YES; } @@ -136,8 +129,7 @@ void ui_accounts_dialog_init(MESSENGER_Application *app, UI_ACCOUNTS_Handle *handle) { - handle->account_entries = NULL; - handle->bindings = app->ui.bindings; + handle->bindings = bindings_create(); handle->show_queued = 0; handle->builder = gtk_builder_new_from_resource( @@ -198,35 +190,22 @@ _clear_accounts_listbox_rows(UI_ACCOUNTS_Handle *handle, if ((!row) || (!gtk_list_box_row_get_selectable(row))) goto skip_row; - g_hash_table_remove(handle->bindings, row); - if (!bindings_only) gtk_container_remove( GTK_CONTAINER(handle->accounts_listbox), GTK_WIDGET(row) ); - skip_row: - list = list->next; - } -} - -static void -_clear_accounts_entries(UI_ACCOUNTS_Handle *handle) -{ - GList *list = handle->account_entries; - - while (list) { - if (list->data) - ui_account_entry_delete((UI_ACCOUNT_ENTRY_Handle*) list->data); + bindings_remove( + handle->bindings, + row, + NULL, + (GDestroyNotify) ui_account_entry_delete + ); + skip_row: list = list->next; } - - if (handle->account_entries) - g_list_free(handle->account_entries); - - handle->account_entries = NULL; } void @@ -236,20 +215,13 @@ ui_accounts_dialog_refresh(MESSENGER_Application *app, if (!(handle->accounts_listbox)) return; - if (!(handle->account_entries)) - goto add_account_entries; - _clear_accounts_listbox_rows(handle, FALSE); - _clear_accounts_entries(handle); -add_account_entries: GNUNET_CHAT_iterate_accounts( app->chat.messenger.handle, _iterate_accounts, app ); - - gtk_list_box_unselect_all(handle->accounts_listbox); } void @@ -259,7 +231,8 @@ ui_accounts_dialog_cleanup(UI_ACCOUNTS_Handle *handle) g_object_unref(handle->builder); - _clear_accounts_entries(handle); + bindings_destroy(handle->bindings); + handle->bindings = NULL; handle->accounts_listbox = NULL; } diff --git a/src/ui/accounts.h b/src/ui/accounts.h @@ -26,11 +26,11 @@ #define UI_ACCOUNTS_H_ #include "messenger.h" +#include "../bindings.h" typedef struct UI_ACCOUNTS_Handle { - GList *account_entries; - GHashTable *bindings; + MESSENGER_Bindings *bindings; guint show_queued; GtkBuilder *builder; diff --git a/src/ui/chat.c b/src/ui/chat.c @@ -76,7 +76,7 @@ handle_chat_contacts_listbox_row_activated(GtkListBox *listbox, MESSENGER_Application *app = (MESSENGER_Application*) user_data; GtkTextView *text_view = GTK_TEXT_VIEW( - g_hash_table_lookup(app->ui.bindings, listbox) + bindings_get(app->bindings, listbox) ); if (!text_view) @@ -86,18 +86,14 @@ handle_chat_contacts_listbox_row_activated(GtkListBox *listbox, { ui_invite_contact_dialog_init(app, &(app->ui.invite_contact)); - g_hash_table_insert( - app->ui.bindings, - app->ui.invite_contact.contacts_listbox, - text_view - ); + bindings_put(app->bindings, app->ui.invite_contact.contacts_listbox, text_view); gtk_widget_show(GTK_WIDGET(app->ui.invite_contact.dialog)); return; } struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( - g_hash_table_lookup(app->ui.bindings, row) + bindings_get(app->bindings, row) ); if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) || @@ -159,11 +155,11 @@ handle_chat_messages_sort(GtkListBoxRow* row0, MESSENGER_Application *app = (MESSENGER_Application*) user_data; UI_MESSAGE_Handle *message0 = (UI_MESSAGE_Handle*) ( - g_hash_table_lookup(app->ui.bindings, row0) + bindings_get(app->bindings, row0) ); UI_MESSAGE_Handle *message1 = (UI_MESSAGE_Handle*) ( - g_hash_table_lookup(app->ui.bindings, row1) + bindings_get(app->bindings, row1) ); if ((!message0) || (!message1)) @@ -216,7 +212,7 @@ handle_chat_selection_close_button_click(UNUSED GtkButton *button, } void -_delete_messages_callback(GHashTable *bindings, +_delete_messages_callback(MESSENGER_Application *app, GList *selected, gulong delay) { @@ -229,7 +225,7 @@ _delete_messages_callback(GHashTable *bindings, if (!row) goto skip_row; - message = g_hash_table_lookup(bindings, row); + message = bindings_get(app->bindings, row); if ((!message) || (!(message->msg))) goto skip_row; @@ -258,7 +254,7 @@ handle_chat_selection_delete_button_click(UNUSED GtkButton *button, GList *selected = gtk_list_box_get_selected_rows(handle->messages_listbox); if (app->settings.hide_delete_dialog) - _delete_messages_callback(app->ui.bindings, selected, 0); + _delete_messages_callback(app, selected, 0); else { ui_delete_messages_dialog_init(app, &(app->ui.delete_messages)); @@ -280,7 +276,7 @@ handle_attach_file_button_click(GtkButton *button, MESSENGER_Application *app = (MESSENGER_Application*) user_data; GtkTextView *text_view = GTK_TEXT_VIEW( - g_hash_table_lookup(app->ui.bindings, button) + bindings_get(app->bindings, button) ); if (!text_view) @@ -312,11 +308,7 @@ handle_attach_file_button_click(GtkButton *button, g_free(filename); - g_hash_table_insert( - app->ui.bindings, - app->ui.send_file.send_button, - text_view - ); + bindings_put(app->bindings, app->ui.send_file.send_button, text_view); gtk_widget_show(GTK_WIDGET(app->ui.send_file.dialog)); @@ -360,8 +352,8 @@ _send_text_from_view(MESSENGER_Application *app, if (0 == strlen(text)) return FALSE; - struct GNUNET_CHAT_Context *context = g_hash_table_lookup( - app->ui.bindings, text_view + struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) ( + bindings_get(app->bindings, text_view) ); if (context) @@ -378,7 +370,7 @@ handle_send_record_button_click(GtkButton *button, MESSENGER_Application *app = (MESSENGER_Application*) user_data; GtkTextView *text_view = GTK_TEXT_VIEW( - g_hash_table_lookup(app->ui.bindings, button) + bindings_get(app->bindings, button) ); if (!_send_text_from_view(app, text_view)) @@ -654,23 +646,9 @@ ui_chat_new(MESSENGER_Application *app) app ); - g_hash_table_insert( - app->ui.bindings, - handle->chat_contacts_listbox, - handle->send_text_view - ); - - g_hash_table_insert( - app->ui.bindings, - handle->attach_file_button, - handle->send_text_view - ); - - g_hash_table_insert( - app->ui.bindings, - handle->send_record_button, - handle->send_text_view - ); + bindings_put(app->bindings, handle->chat_contacts_listbox, handle->send_text_view); + bindings_put(app->bindings, handle->attach_file_button, handle->send_text_view); + bindings_put(app->bindings, handle->send_record_button, handle->send_text_view); handle->picker_revealer = GTK_REVEALER( gtk_builder_get_object(handle->builder, "picker_revealer") @@ -695,7 +673,6 @@ ui_chat_new(MESSENGER_Application *app) struct IterateChatGroupClosure { MESSENGER_Application *app; - GHashTable *bindings; GtkListBox *listbox; }; @@ -711,10 +688,7 @@ iterate_ui_chat_update_group_contacts(void *cls, GtkListBox *listbox = closure->listbox; UI_ACCOUNT_ENTRY_Handle* entry = ui_account_entry_new(closure->app); - const char *name = GNUNET_CHAT_contact_get_name(contact); - - gtk_label_set_text(entry->entry_label, name? name : ""); - hdy_avatar_set_text(entry->entry_avatar, name? name : ""); + ui_account_entry_set_contact(entry, contact); gtk_list_box_prepend(listbox, entry->entry_box); @@ -722,7 +696,7 @@ iterate_ui_chat_update_group_contacts(void *cls, gtk_widget_get_parent(entry->entry_box) ); - g_hash_table_insert(closure->bindings, row, contact); + bindings_put(closure->app->bindings, row, contact); ui_account_entry_delete(entry); return GNUNET_YES; @@ -776,8 +750,7 @@ ui_chat_update(UI_CHAT_Handle *handle, GtkWidget *widget = GTK_WIDGET(children->data); children = children->next; - if (g_hash_table_contains(app->ui.bindings, widget)) - g_hash_table_remove(app->ui.bindings, widget); + bindings_remove(app->bindings, widget, NULL, NULL); gtk_container_remove( GTK_CONTAINER(handle->chat_contacts_listbox), @@ -789,7 +762,6 @@ ui_chat_update(UI_CHAT_Handle *handle, { struct IterateChatGroupClosure closure; closure.app = app; - closure.bindings = app->ui.bindings; closure.listbox = handle->chat_contacts_listbox; GNUNET_CHAT_group_iterate_contacts( @@ -845,29 +817,11 @@ ui_chat_delete(UI_CHAT_Handle *handle) g_object_unref(handle->builder); - GList *list = handle->messages; - - while (list) { - if (list->data) - ui_message_delete((UI_MESSAGE_Handle*) list->data); - - list = list->next; - } - - list = handle->loads; - - while (list) { - if (list->data) - ui_file_load_entry_delete((UI_FILE_LOAD_ENTRY_Handle*) list->data); - - list = list->next; - } - if (handle->messages) - g_list_free(handle->messages); + g_list_free_full(handle->messages, (GDestroyNotify) ui_message_delete); if (handle->loads) - g_list_free(handle->loads); + g_list_free_full(handle->loads, (GDestroyNotify) ui_file_load_entry_delete); g_free(handle); } @@ -886,7 +840,7 @@ ui_chat_add_message(UI_CHAT_Handle *handle, GtkWidget *row = gtk_widget_get_parent(message->message_box); - g_hash_table_insert(app->ui.bindings, row, message); + bindings_put(app->bindings, row, message); handle->messages = g_list_prepend(handle->messages, message); @@ -904,12 +858,14 @@ ui_chat_remove_message(UI_CHAT_Handle *handle, GtkWidget *row = gtk_widget_get_parent(message->message_box); - g_hash_table_remove(app->ui.bindings, row); + bindings_remove(app->bindings, row, NULL, NULL); gtk_container_remove( GTK_CONTAINER(handle->messages_listbox), gtk_widget_get_parent(GTK_WIDGET(message->message_box)) ); + + handle->messages = g_list_append(handle->messages, message); } void diff --git a/src/ui/chat_entry.c b/src/ui/chat_entry.c @@ -34,6 +34,8 @@ ui_chat_entry_new(MESSENGER_Application *app) { UI_CHAT_ENTRY_Handle* handle = g_malloc(sizeof(UI_CHAT_ENTRY_Handle)); + handle->joining = bindings_create(); + handle->chat = ui_chat_new(app); handle->builder = gtk_builder_new_from_resource( application_get_resource_path(app, "ui/chat_entry.ui") @@ -153,5 +155,7 @@ ui_chat_entry_delete(UI_CHAT_ENTRY_Handle *handle) g_object_unref(handle->builder); + bindings_destroy(handle->joining); + g_free(handle); } diff --git a/src/ui/chat_entry.h b/src/ui/chat_entry.h @@ -26,9 +26,12 @@ #define UI_CHAT_ENTRY_H_ #include "chat.h" +#include "../bindings.h" typedef struct UI_CHAT_ENTRY_Handle { + MESSENGER_Bindings *joining; + UI_CHAT_Handle *chat; GtkBuilder *builder; diff --git a/src/ui/contact_entry.c b/src/ui/contact_entry.c @@ -55,6 +55,31 @@ ui_contact_entry_new(MESSENGER_Application *app) } void +ui_contact_entry_set_contact(UI_CONTACT_ENTRY_Handle* handle, + const struct GNUNET_CHAT_Contact *contact) +{ + + const gchar *name; + const gchar *key; + + name = GNUNET_CHAT_contact_get_name(contact); + + if (!name) + goto skip_name; + + hdy_avatar_set_text(handle->entry_avatar, name); + gtk_label_set_text(handle->title_label, name); + +skip_name: + key = GNUNET_CHAT_contact_get_key(contact); + + if (!key) + return; + + gtk_label_set_text(handle->subtitle_label, name); +} + +void ui_contact_entry_delete(UI_CONTACT_ENTRY_Handle *handle) { g_object_unref(handle->builder); diff --git a/src/ui/contact_entry.h b/src/ui/contact_entry.h @@ -43,6 +43,10 @@ UI_CONTACT_ENTRY_Handle* ui_contact_entry_new(MESSENGER_Application *app); void +ui_contact_entry_set_contact(UI_CONTACT_ENTRY_Handle* handle, + const struct GNUNET_CHAT_Contact *contact); + +void ui_contact_entry_delete(UI_CONTACT_ENTRY_Handle *handle); #endif /* UI_CONTACT_ENTRY_H_ */ diff --git a/src/ui/contacts.c b/src/ui/contacts.c @@ -61,7 +61,7 @@ handle_contacts_listbox_row_activated(UNUSED GtkListBox* listbox, } struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( - g_hash_table_lookup(app->ui.bindings, row) + bindings_get(app->bindings, row) ); if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) || @@ -88,7 +88,7 @@ handle_contacts_listbox_filter_func(GtkListBoxRow *row, { UI_CONTACTS_Handle *handle = (UI_CONTACTS_Handle*) user_data; - if (!gtk_list_box_row_get_selectable(row)) + if ((!row) || (!gtk_list_box_row_get_selectable(row))) return TRUE; const gchar *filter = gtk_entry_get_text( @@ -98,14 +98,14 @@ handle_contacts_listbox_filter_func(GtkListBoxRow *row, if (!filter) return TRUE; - struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( - g_hash_table_lookup(handle->bindings, row) + UI_CONTACT_ENTRY_Handle *entry = (UI_CONTACT_ENTRY_Handle*) ( + bindings_get(handle->bindings, row) ); - if (!contact) + if (!entry) return FALSE; - const gchar *name = GNUNET_CHAT_contact_get_name(contact); + const gchar *name = gtk_label_get_text(entry->title_label); if (!name) return FALSE; @@ -139,36 +139,20 @@ _iterate_contacts(void *cls, MESSENGER_Application *app = (MESSENGER_Application*) cls; - const char *title; - title = GNUNET_CHAT_contact_get_name(contact); - - const char *key = GNUNET_CHAT_contact_get_key(contact); - UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app); + ui_contact_entry_set_contact(entry, contact); + gtk_list_box_prepend( app->ui.contacts.contacts_listbox, entry->entry_box ); - if (title) - { - gtk_label_set_text(entry->title_label, title); - hdy_avatar_set_text(entry->entry_avatar, title); - } - - if (key) - gtk_label_set_text(entry->subtitle_label, key); - GtkListBoxRow *row = GTK_LIST_BOX_ROW( gtk_widget_get_parent(entry->entry_box) ); - g_hash_table_insert(app->ui.bindings, row, contact); - - app->ui.contacts.contact_entries = g_list_append( - app->ui.contacts.contact_entries, - entry - ); + bindings_put(app->bindings, row, contact); + bindings_put(app->ui.contacts.bindings, row, entry); return GNUNET_YES; } @@ -177,8 +161,7 @@ void ui_contacts_dialog_init(MESSENGER_Application *app, UI_CONTACTS_Handle *handle) { - handle->contact_entries = NULL; - handle->bindings = app->ui.bindings; + handle->bindings = bindings_create(); handle->builder = gtk_builder_new_from_resource( application_get_resource_path(app, "ui/contacts.ui") @@ -249,8 +232,9 @@ ui_contacts_dialog_init(MESSENGER_Application *app, gtk_list_box_invalidate_filter(handle->contacts_listbox); } -void -ui_contacts_dialog_cleanup(UI_CONTACTS_Handle *handle) +static void +_clear_contacts_listbox_rows(UI_CONTACTS_Handle *handle, + gboolean bindings_only) { GList *list = gtk_container_get_children( GTK_CONTAINER(handle->contacts_listbox) @@ -258,23 +242,38 @@ ui_contacts_dialog_cleanup(UI_CONTACTS_Handle *handle) while (list) { - if (list->data) - g_hash_table_remove(handle->bindings, list->data); + GtkListBoxRow *row = GTK_LIST_BOX_ROW(list->data); - list = list->next; - } + if ((!row) || (!gtk_list_box_row_get_selectable(row))) + goto skip_row; - g_object_unref(handle->builder); + if (!bindings_only) + gtk_container_remove( + GTK_CONTAINER(handle->contacts_listbox), + GTK_WIDGET(row) + ); - list = handle->contact_entries; - - while (list) { - if (list->data) - ui_contact_entry_delete((UI_CONTACT_ENTRY_Handle*) list->data); + bindings_remove( + handle->bindings, + row, + NULL, + (GDestroyNotify) ui_contact_entry_delete + ); + skip_row: list = list->next; } +} + +void +ui_contacts_dialog_cleanup(UI_CONTACTS_Handle *handle) +{ + _clear_contacts_listbox_rows(handle, TRUE); + + g_object_unref(handle->builder); + + bindings_destroy(handle->bindings); + handle->bindings = NULL; - if (handle->contact_entries) - g_list_free(handle->contact_entries); + handle->contacts_listbox = NULL; } diff --git a/src/ui/contacts.h b/src/ui/contacts.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021 GNUnet e.V. + Copyright (C) 2021--2022 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 @@ -26,11 +26,11 @@ #define UI_CONTACTS_H_ #include "messenger.h" +#include "../bindings.h" typedef struct UI_CONTACTS_Handle { - GList *contact_entries; - GHashTable *bindings; + MESSENGER_Bindings *bindings; GtkBuilder *builder; GtkDialog *dialog; diff --git a/src/ui/delete_messages.c b/src/ui/delete_messages.c @@ -57,7 +57,7 @@ handle_confirm_button_click(UNUSED GtkButton *button, if (app->ui.delete_messages.callback) app->ui.delete_messages.callback( - app->ui.bindings, + app, app->ui.delete_messages.selected, delay ); diff --git a/src/ui/delete_messages.h b/src/ui/delete_messages.h @@ -28,7 +28,7 @@ #include "messenger.h" typedef void -(*UI_DELETE_MESSAGES_Callback) (GHashTable *bindings, +(*UI_DELETE_MESSAGES_Callback) (MESSENGER_Application *app, GList *selected, gulong delay); diff --git a/src/ui/invite_contact.c b/src/ui/invite_contact.c @@ -44,11 +44,11 @@ handle_contacts_listbox_row_activated(GtkListBox* listbox, MESSENGER_Application *app = (MESSENGER_Application*) user_data; GtkTextView *text_view = GTK_TEXT_VIEW( - g_hash_table_lookup(app->ui.bindings, listbox) + bindings_get(app->bindings, listbox) ); struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( - g_hash_table_lookup(app->ui.bindings, row) + bindings_get(app->bindings, row) ); if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) || @@ -56,8 +56,8 @@ handle_contacts_listbox_row_activated(GtkListBox* listbox, (!text_view)) goto close_dialog; - struct GNUNET_CHAT_Context *context = g_hash_table_lookup( - app->ui.bindings, text_view + struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) ( + bindings_get(app->bindings, text_view) ); if (!context) @@ -78,9 +78,9 @@ static gboolean handle_contacts_listbox_filter_func(GtkListBoxRow *row, gpointer user_data) { - UI_CONTACTS_Handle *handle = (UI_CONTACTS_Handle*) user_data; + UI_INVITE_CONTACT_Handle *handle = (UI_INVITE_CONTACT_Handle*) user_data; - if (!gtk_list_box_row_get_selectable(row)) + if ((!row) || (!gtk_list_box_row_get_selectable(row))) return TRUE; const gchar *filter = gtk_entry_get_text( @@ -90,14 +90,14 @@ handle_contacts_listbox_filter_func(GtkListBoxRow *row, if (!filter) return TRUE; - struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( - g_hash_table_lookup(handle->bindings, row) + UI_CONTACT_ENTRY_Handle *entry = (UI_CONTACT_ENTRY_Handle*) ( + bindings_get(handle->bindings, row) ); - if (!contact) + if (!entry) return FALSE; - const gchar *name = GNUNET_CHAT_contact_get_name(contact); + const gchar *name = gtk_label_get_text(entry->title_label); if (!name) return FALSE; @@ -131,36 +131,20 @@ _iterate_contacts(void *cls, MESSENGER_Application *app = (MESSENGER_Application*) cls; - const char *title; - title = GNUNET_CHAT_contact_get_name(contact); - - const char *key = GNUNET_CHAT_contact_get_key(contact); - UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app); + ui_contact_entry_set_contact(entry, contact); + gtk_list_box_prepend( app->ui.invite_contact.contacts_listbox, entry->entry_box ); - if (title) - { - gtk_label_set_text(entry->title_label, title); - hdy_avatar_set_text(entry->entry_avatar, title); - } - - if (key) - gtk_label_set_text(entry->subtitle_label, key); - GtkListBoxRow *row = GTK_LIST_BOX_ROW( gtk_widget_get_parent(entry->entry_box) ); - g_hash_table_insert(app->ui.bindings, row, contact); - - app->ui.invite_contact.contact_entries = g_list_append( - app->ui.invite_contact.contact_entries, - entry - ); + bindings_put(app->bindings, row, contact); + bindings_put(app->ui.invite_contact.bindings, row, entry); return GNUNET_YES; } @@ -169,8 +153,7 @@ void ui_invite_contact_dialog_init(MESSENGER_Application *app, UI_INVITE_CONTACT_Handle *handle) { - handle->contact_entries = NULL; - handle->bindings = app->ui.bindings; + handle->bindings = bindings_create(); handle->builder = gtk_builder_new_from_resource( application_get_resource_path(app, "ui/invite_contact.ui") @@ -241,20 +224,48 @@ ui_invite_contact_dialog_init(MESSENGER_Application *app, gtk_list_box_invalidate_filter(handle->contacts_listbox); } -void -ui_invite_contact_dialog_cleanup(UI_INVITE_CONTACT_Handle *handle) +static void +_clear_contacts_listbox_rows(UI_INVITE_CONTACT_Handle *handle, + gboolean bindings_only) { - g_object_unref(handle->builder); + GList *list = gtk_container_get_children( + GTK_CONTAINER(handle->contacts_listbox) + ); + + while (list) + { + GtkListBoxRow *row = GTK_LIST_BOX_ROW(list->data); - GList *list = handle->contact_entries; + if ((!row) || (!gtk_list_box_row_get_selectable(row))) + goto skip_row; - while (list) { - if (list->data) - ui_contact_entry_delete((UI_CONTACT_ENTRY_Handle*) list->data); + if (!bindings_only) + gtk_container_remove( + GTK_CONTAINER(handle->contacts_listbox), + GTK_WIDGET(row) + ); + bindings_remove( + handle->bindings, + row, + NULL, + (GDestroyNotify) ui_contact_entry_delete + ); + + skip_row: list = list->next; } +} + +void +ui_invite_contact_dialog_cleanup(UI_INVITE_CONTACT_Handle *handle) +{ + _clear_contacts_listbox_rows(handle, TRUE); + + g_object_unref(handle->builder); + + bindings_destroy(handle->bindings); + handle->bindings = NULL; - if (handle->contact_entries) - g_list_free(handle->contact_entries); + handle->contacts_listbox = NULL; } diff --git a/src/ui/invite_contact.h b/src/ui/invite_contact.h @@ -1,6 +1,6 @@ /* This file is part of GNUnet. - Copyright (C) 2021 GNUnet e.V. + Copyright (C) 2021--2022 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 @@ -26,11 +26,11 @@ #define UI_INVITE_CONTACT_H_ #include "messenger.h" +#include "../bindings.h" typedef struct UI_INVITE_CONTACT_Handle { - GList *contact_entries; - GHashTable *bindings; + MESSENGER_Bindings *bindings; GtkBuilder *builder; GtkDialog *dialog; diff --git a/src/ui/message.c b/src/ui/message.c @@ -49,15 +49,15 @@ handle_file_button_click(GtkButton *button, { MESSENGER_Application *app = (MESSENGER_Application*) user_data; - UI_MESSAGE_Handle* handle = g_hash_table_lookup( - app->ui.bindings, button + UI_MESSAGE_Handle* handle = (UI_MESSAGE_Handle*) ( + bindings_get(app->bindings, button) ); if (!handle) return; - struct GNUNET_CHAT_File *file = g_hash_table_lookup( - app->ui.bindings, handle->file_progress_bar + struct GNUNET_CHAT_File *file = (struct GNUNET_CHAT_File*) ( + bindings_get(app->bindings, handle->file_progress_bar) ); if (!file) @@ -266,38 +266,38 @@ ui_message_new(MESSENGER_Application *app, break; } - handle->builder = gtk_builder_new_from_resource( + handle->builder[0] = gtk_builder_new_from_resource( application_get_resource_path(app, ui_builder_file) ); handle->message_box = GTK_WIDGET( - gtk_builder_get_object(handle->builder, "message_box") + gtk_builder_get_object(handle->builder[0], "message_box") ); handle->sender_avatar = HDY_AVATAR( - gtk_builder_get_object(handle->builder, "sender_avatar") + gtk_builder_get_object(handle->builder[0], "sender_avatar") ); handle->sender_label = GTK_LABEL( - gtk_builder_get_object(handle->builder, "sender_label") + gtk_builder_get_object(handle->builder[0], "sender_label") ); if (UI_MESSAGE_STATUS == handle->type) { handle->deny_revealer = GTK_REVEALER( - gtk_builder_get_object(handle->builder, "deny_revealer") + gtk_builder_get_object(handle->builder[0], "deny_revealer") ); handle->accept_revealer = GTK_REVEALER( - gtk_builder_get_object(handle->builder, "accept_revealer") + gtk_builder_get_object(handle->builder[0], "accept_revealer") ); handle->deny_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "deny_button") + gtk_builder_get_object(handle->builder[0], "deny_button") ); handle->accept_button = GTK_BUTTON( - gtk_builder_get_object(handle->builder, "accept_button") + gtk_builder_get_object(handle->builder[0], "accept_button") ); } else @@ -310,43 +310,43 @@ ui_message_new(MESSENGER_Application *app, } GtkContainer *content_box = GTK_CONTAINER( - gtk_builder_get_object(handle->builder, "content_box") + gtk_builder_get_object(handle->builder[0], "content_box") ); - GtkBuilder *builder = gtk_builder_new_from_resource( + handle->builder[1] = gtk_builder_new_from_resource( application_get_resource_path(app, "ui/message_content.ui") ); handle->timestamp_label = GTK_LABEL( - gtk_builder_get_object(builder, "timestamp_label") + gtk_builder_get_object(handle->builder[1], "timestamp_label") ); handle->read_receipt_image = GTK_IMAGE( - gtk_builder_get_object(builder, "read_receipt_image") + gtk_builder_get_object(handle->builder[1], "read_receipt_image") ); handle->content_stack = GTK_STACK( - gtk_builder_get_object(builder, "content_stack") + gtk_builder_get_object(handle->builder[1], "content_stack") ); handle->text_label = GTK_LABEL( - gtk_builder_get_object(builder, "text_label") + gtk_builder_get_object(handle->builder[1], "text_label") ); handle->file_revealer = GTK_REVEALER( - gtk_builder_get_object(builder, "file_revealer") + gtk_builder_get_object(handle->builder[1], "file_revealer") ); handle->filename_label = GTK_LABEL( - gtk_builder_get_object(builder, "filename_label") + gtk_builder_get_object(handle->builder[1], "filename_label") ); handle->file_progress_bar = GTK_PROGRESS_BAR( - gtk_builder_get_object(builder, "file_progress_bar") + gtk_builder_get_object(handle->builder[1], "file_progress_bar") ); handle->file_button = GTK_BUTTON( - gtk_builder_get_object(builder, "file_button") + gtk_builder_get_object(handle->builder[1], "file_button") ); g_signal_connect( @@ -357,16 +357,16 @@ ui_message_new(MESSENGER_Application *app, ); handle->file_status_image = GTK_IMAGE( - gtk_builder_get_object(builder, "file_status_image") + gtk_builder_get_object(handle->builder[1], "file_status_image") ); - g_hash_table_insert(app->ui.bindings, handle->file_button, handle); + bindings_put(app->bindings, handle->file_button, handle); handle->preview_drawing_area = GTK_DRAWING_AREA( - gtk_builder_get_object(builder, "preview_drawing_area") + gtk_builder_get_object(handle->builder[1], "preview_drawing_area") ); - handle->preview_draw_signal = g_signal_connect( + g_signal_connect( handle->preview_drawing_area, "draw", G_CALLBACK(handle_preview_drawing_area_draw), @@ -383,11 +383,9 @@ ui_message_new(MESSENGER_Application *app, } gtk_container_add(content_box, GTK_WIDGET( - gtk_builder_get_object(builder, "message_content_box") + gtk_builder_get_object(handle->builder[1], "message_content_box") )); - g_object_unref(builder); - handle->preview_image = NULL; handle->preview_animation = NULL; handle->preview_animation_iter = NULL; @@ -445,15 +443,14 @@ ui_message_update(UI_MESSAGE_Handle *handle, handle->timestamp = GNUNET_CHAT_message_get_timestamp(msg); } else - file = g_hash_table_lookup(app->ui.bindings, handle->message_box); + file = (struct GNUNET_CHAT_File*) ( + bindings_get(app->bindings, handle->message_box) + ); if (!file) return; - if (g_hash_table_contains(app->ui.bindings, handle->message_box)) - g_hash_table_replace(app->ui.bindings, handle->message_box, file); - else - g_hash_table_insert(app->ui.bindings, handle->message_box, file); + bindings_put(app->bindings, handle->message_box, file); uint64_t size = GNUNET_CHAT_file_get_size(file); uint64_t local_size = GNUNET_CHAT_file_get_local_size(file); @@ -522,10 +519,7 @@ file_content: gtk_revealer_set_reveal_child(handle->file_revealer, TRUE); - if (g_hash_table_contains(app->ui.bindings, handle->file_progress_bar)) - g_hash_table_replace(app->ui.bindings, handle->file_progress_bar, file); - else - g_hash_table_insert(app->ui.bindings, handle->file_progress_bar, file); + bindings_put(app->bindings, handle->file_progress_bar, file); } void @@ -533,12 +527,8 @@ ui_message_delete(UI_MESSAGE_Handle *handle) { _clear_message_preview_data(handle); - g_signal_handler_disconnect( - handle->preview_drawing_area, - handle->preview_draw_signal - ); - - g_object_unref(handle->builder); + g_object_unref(handle->builder[1]); + g_object_unref(handle->builder[0]); g_free(handle); } diff --git a/src/ui/message.h b/src/ui/message.h @@ -48,7 +48,7 @@ typedef struct UI_MESSAGE_Handle struct GNUNET_TIME_Absolute timestamp; const struct GNUNET_CHAT_Message *msg; - GtkBuilder *builder; + GtkBuilder *builder [2]; GtkWidget *message_box; HdyAvatar *sender_avatar; @@ -75,8 +75,6 @@ typedef struct UI_MESSAGE_Handle GtkDrawingArea *preview_drawing_area; - gulong preview_draw_signal; - GdkPixbuf *preview_image; GdkPixbufAnimation *preview_animation; GdkPixbufAnimationIter *preview_animation_iter; diff --git a/src/ui/messenger.c b/src/ui/messenger.c @@ -26,6 +26,7 @@ #include <gtk-3.0/gdk/gdkkeys.h> +#include "account_entry.h" #include "chat_entry.h" #include "contacts.h" #include "message.h" @@ -105,7 +106,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, } struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( - g_hash_table_lookup(app->ui.bindings, row) + bindings_get(app->bindings, row) ); if (!account) @@ -192,8 +193,8 @@ handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox, if (!gtk_list_box_row_get_selectable(row)) return; - UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) g_hash_table_lookup( - handle->bindings, row + UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) ( + bindings_get(handle->app->bindings, row) ); if ((!entry) || (!(entry->chat)) || (!(entry->chat->chat_box))) @@ -217,7 +218,7 @@ handle_chats_listbox_filter_func(GtkListBoxRow *row, { UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data; - if ((!gtk_list_box_row_get_selectable(row)) || + if ((!row) || (!gtk_list_box_row_get_selectable(row)) || (gtk_list_box_row_is_selected(row))) return TRUE; @@ -228,8 +229,8 @@ handle_chats_listbox_filter_func(GtkListBoxRow *row, if (!filter) return TRUE; - UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) g_hash_table_lookup( - handle->bindings, row + UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) ( + bindings_get(handle->app->bindings, row) ); if ((!entry) || (!(entry->title_label))) @@ -267,8 +268,8 @@ void ui_messenger_init(MESSENGER_Application *app, UI_MESSENGER_Handle *handle) { + handle->app = app; handle->chat_entries = NULL; - handle->bindings = app->ui.bindings; handle->builder = gtk_builder_new_from_resource( application_get_resource_path(app, "ui/messenger.ui") @@ -490,6 +491,79 @@ ui_messenger_init(MESSENGER_Application *app, ); } +static void +_messenger_clear_accounts_listbox_rows(UI_MESSENGER_Handle *handle) +{ + GList *list = gtk_container_get_children( + GTK_CONTAINER(handle->accounts_listbox) + ); + + while (list) + { + GtkListBoxRow *row = GTK_LIST_BOX_ROW(list->data); + + if ((!row) || (!gtk_list_box_row_get_selectable(row))) + goto skip_row; + + bindings_remove(handle->app->bindings, row, NULL, NULL); + + gtk_container_remove( + GTK_CONTAINER(handle->accounts_listbox), + GTK_WIDGET(row) + ); + + skip_row: + list = list->next; + } +} + +static int +_messenger_iterate_accounts(void *cls, + const struct GNUNET_CHAT_Handle *handle, + struct GNUNET_CHAT_Account *account) +{ + MESSENGER_Application *app = (MESSENGER_Application*) cls; + UI_MESSENGER_Handle *ui = &(app->ui.messenger); + + const gchar *name = GNUNET_CHAT_account_get_name(account); + + UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app); + + hdy_avatar_set_text(entry->entry_avatar, name); + gtk_label_set_text(entry->entry_label, name); + + gtk_list_box_prepend(ui->accounts_listbox, entry->entry_box); + + GtkListBoxRow *row = GTK_LIST_BOX_ROW( + gtk_widget_get_parent(entry->entry_box) + ); + + bindings_put(app->bindings, row, account); + + if ((account == GNUNET_CHAT_get_connected(handle)) || + ((app->chat.identity) && (0 == g_strcmp0(app->chat.identity, name)))) + gtk_widget_activate(GTK_WIDGET(row)); + + ui_account_entry_delete(entry); + return GNUNET_YES; +} + +void +ui_messenger_refresh(MESSENGER_Application *app, + UI_MESSENGER_Handle *handle) +{ + if (!(handle->accounts_listbox)) + return; + + _messenger_clear_accounts_listbox_rows(handle); + + GNUNET_CHAT_iterate_accounts( + app->chat.messenger.handle, + _messenger_iterate_accounts, + app + ); +} + gboolean ui_messenger_is_context_active(UI_MESSENGER_Handle *handle, struct GNUNET_CHAT_Context *context) @@ -514,11 +588,8 @@ ui_messenger_cleanup(UI_MESSENGER_Handle *handle) { g_object_unref(handle->builder); - for (GList *list = handle->chat_entries; list; list = list->next) - ui_chat_entry_delete((UI_CHAT_ENTRY_Handle*) list->data); - if (handle->chat_entries) - g_list_free(handle->chat_entries); + g_list_free_full(handle->chat_entries, (GDestroyNotify) ui_chat_entry_delete); memset(handle, 0, sizeof(*handle)); } diff --git a/src/ui/messenger.h b/src/ui/messenger.h @@ -35,8 +35,9 @@ typedef struct MESSENGER_Application MESSENGER_Application; typedef struct UI_MESSENGER_Handle { + MESSENGER_Application *app; + GList *chat_entries; - GHashTable *bindings; GtkBuilder *builder; GtkApplicationWindow *main_window; @@ -77,6 +78,10 @@ void ui_messenger_init(MESSENGER_Application *app, UI_MESSENGER_Handle *handle); +void +ui_messenger_refresh(MESSENGER_Application *app, + UI_MESSENGER_Handle *handle); + gboolean ui_messenger_is_context_active(UI_MESSENGER_Handle *handle, struct GNUNET_CHAT_Context *context); diff --git a/src/ui/new_group.c b/src/ui/new_group.c @@ -50,8 +50,8 @@ _open_new_group(GtkEntry *entry, { GtkListBoxRow *row = GTK_LIST_BOX_ROW(selected->data); - struct GNUNET_CHAT_Contact* contact = g_hash_table_lookup( - app->ui.bindings, row + struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( + bindings_get(app->bindings, row) ); GNUNET_CHAT_group_invite_contact(group, contact); @@ -158,31 +158,19 @@ _iterate_contacts(void *cls, MESSENGER_Application *app = (MESSENGER_Application*) cls; - const char *title; - title = GNUNET_CHAT_contact_get_name(contact); - - const char *key = GNUNET_CHAT_contact_get_key(contact); - UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app); + ui_contact_entry_set_contact(entry, contact); + gtk_list_box_prepend( app->ui.new_group.contacts_listbox, entry->entry_box ); - if (title) - { - gtk_label_set_text(entry->title_label, title); - hdy_avatar_set_text(entry->entry_avatar, title); - } - - if (key) - gtk_label_set_text(entry->subtitle_label, key); - GtkListBoxRow *row = GTK_LIST_BOX_ROW( gtk_widget_get_parent(entry->entry_box) ); - g_hash_table_insert(app->ui.bindings, row, contact); + bindings_put(app->bindings, row, contact); app->ui.new_group.contact_entries = g_list_append( app->ui.new_group.contact_entries, diff --git a/src/ui/send_file.c b/src/ui/send_file.c @@ -65,7 +65,7 @@ handle_send_button_click(GtkButton *button, MESSENGER_Application *app = (MESSENGER_Application*) user_data; GtkTextView *text_view = GTK_TEXT_VIEW( - g_hash_table_lookup(app->ui.bindings, button) + bindings_get(app->bindings, button) ); if (!text_view) @@ -78,8 +78,8 @@ handle_send_button_click(GtkButton *button, if (!filename) return; - struct GNUNET_CHAT_Context *context = g_hash_table_lookup( - app->ui.bindings, text_view + struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) ( + bindings_get(app->bindings, text_view) ); UI_CHAT_ENTRY_Handle *entry = GNUNET_CHAT_context_get_user_pointer(context);