accounts.c (6289B)
1 /* 2 This file is part of GNUnet. 3 Copyright (C) 2022--2024 GNUnet e.V. 4 5 GNUnet is free software: you can redistribute it and/or modify it 6 under the terms of the GNU Affero General Public License as published 7 by the Free Software Foundation, either version 3 of the License, 8 or (at your option) any later version. 9 10 GNUnet is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 SPDX-License-Identifier: AGPL3.0-or-later 19 */ 20 /* 21 * @author Tobias Frisch 22 * @file ui/accounts.c 23 */ 24 25 #include "accounts.h" 26 27 #include "account_entry.h" 28 29 #include "../account.h" 30 #include "../application.h" 31 #include "../ui.h" 32 33 static void 34 handle_close_button_click(UNUSED GtkButton *button, 35 gpointer user_data) 36 { 37 g_assert(user_data); 38 39 GtkDialog *dialog = GTK_DIALOG(user_data); 40 gtk_window_close(GTK_WINDOW(dialog)); 41 } 42 43 static gboolean 44 _open_new_account_dialog(gpointer user_data) 45 { 46 g_assert(user_data); 47 48 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 49 50 ui_new_account_dialog_init(app, &(app->ui.new_account)); 51 52 gtk_widget_show(GTK_WIDGET(app->ui.new_account.dialog)); 53 return FALSE; 54 } 55 56 static void 57 handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox, 58 GtkListBoxRow* row, 59 gpointer user_data) 60 { 61 g_assert((row) && (user_data)); 62 63 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 64 65 // Drop activations of rows which do not contain accounts 66 if (!gtk_list_box_row_get_selectable(row)) 67 { 68 app->ui.accounts.show_queued = util_idle_add( 69 G_SOURCE_FUNC(_open_new_account_dialog), app 70 ); 71 72 goto close_dialog; 73 } 74 75 struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( 76 g_object_get_qdata(G_OBJECT(row), app->quarks.data) 77 ); 78 79 if (!account) 80 goto close_dialog; 81 82 app->ui.state = MESSENGER_STATE_MAIN_WINDOW; 83 84 application_chat_lock(app); 85 GNUNET_CHAT_connect(app->chat.messenger.handle, account); 86 application_chat_unlock(app); 87 88 gtk_list_box_unselect_all(app->ui.messenger.accounts_listbox); 89 gtk_widget_set_sensitive(GTK_WIDGET(app->ui.accounts.dialog), FALSE); 90 91 close_dialog: 92 gtk_window_close(GTK_WINDOW(app->ui.accounts.dialog)); 93 } 94 95 static void 96 handle_dialog_destroy(UNUSED GtkWidget *window, 97 gpointer user_data) 98 { 99 g_assert(user_data); 100 101 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 102 103 ui_accounts_dialog_cleanup(&(app->ui.accounts), app); 104 105 if ((app->ui.accounts.show_queued) || 106 (MESSENGER_STATE_MAIN_WINDOW == app->ui.state)) 107 return; 108 109 gtk_widget_destroy(GTK_WIDGET(app->ui.messenger.main_window)); 110 } 111 112 static int 113 _iterate_accounts(void *cls, 114 UNUSED struct GNUNET_CHAT_Handle *handle, 115 struct GNUNET_CHAT_Account *account) 116 { 117 g_assert((cls) && (account)); 118 119 MESSENGER_Application *app = (MESSENGER_Application*) cls; 120 121 UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app); 122 123 ui_account_entry_set_account(entry, account); 124 125 gtk_list_box_prepend(app->ui.accounts.accounts_listbox, entry->entry_box); 126 127 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 128 gtk_widget_get_parent(entry->entry_box) 129 ); 130 131 g_object_set_qdata(G_OBJECT(row), app->quarks.data, account); 132 133 g_object_set_qdata( 134 G_OBJECT(row), 135 app->quarks.ui, 136 entry 137 ); 138 139 return GNUNET_YES; 140 } 141 142 void 143 ui_accounts_dialog_init(MESSENGER_Application *app, 144 UI_ACCOUNTS_Handle *handle) 145 { 146 g_assert((app) && (handle)); 147 148 handle->show_queued = 0; 149 150 handle->builder = ui_builder_from_resource( 151 application_get_resource_path(app, "ui/accounts.ui") 152 ); 153 154 handle->dialog = GTK_DIALOG( 155 gtk_builder_get_object(handle->builder, "accounts_dialog") 156 ); 157 158 gtk_window_set_transient_for( 159 GTK_WINDOW(handle->dialog), 160 GTK_WINDOW(app->ui.messenger.main_window) 161 ); 162 163 handle->accounts_listbox = GTK_LIST_BOX( 164 gtk_builder_get_object(handle->builder, "accounts_listbox") 165 ); 166 167 g_signal_connect( 168 handle->accounts_listbox, 169 "row-activated", 170 G_CALLBACK(handle_accounts_listbox_row_activated), 171 app 172 ); 173 174 handle->close_button = GTK_BUTTON( 175 gtk_builder_get_object(handle->builder, "close_button") 176 ); 177 178 g_signal_connect( 179 handle->close_button, 180 "clicked", 181 G_CALLBACK(handle_close_button_click), 182 handle->dialog 183 ); 184 185 g_signal_connect( 186 handle->dialog, 187 "destroy", 188 G_CALLBACK(handle_dialog_destroy), 189 app 190 ); 191 } 192 193 static void 194 _ui_accounts_cleanup_listbox(UI_ACCOUNTS_Handle *handle, 195 MESSENGER_Application *app) 196 { 197 g_assert(handle); 198 199 GList *list = gtk_container_get_children( 200 GTK_CONTAINER(handle->accounts_listbox) 201 ); 202 203 GList *item = list; 204 while (item) 205 { 206 GtkListBoxRow *row = GTK_LIST_BOX_ROW(item->data); 207 208 if ((!row) || (!gtk_list_box_row_get_selectable(row))) 209 goto skip_row; 210 211 UI_ACCOUNT_ENTRY_Handle *entry = g_object_get_qdata( 212 G_OBJECT(row), 213 app->quarks.ui 214 ); 215 216 gtk_container_remove( 217 GTK_CONTAINER(handle->accounts_listbox), 218 GTK_WIDGET(row) 219 ); 220 221 ui_account_entry_delete(entry); 222 223 skip_row: 224 item = item->next; 225 } 226 227 if (list) 228 g_list_free(list); 229 } 230 231 void 232 ui_accounts_dialog_refresh(MESSENGER_Application *app, 233 UI_ACCOUNTS_Handle *handle) 234 { 235 g_assert((app) && (handle)); 236 237 if (!(handle->accounts_listbox)) 238 return; 239 240 _ui_accounts_cleanup_listbox(handle, app); 241 242 application_chat_lock(app); 243 244 GNUNET_CHAT_iterate_accounts( 245 app->chat.messenger.handle, 246 _iterate_accounts, 247 app 248 ); 249 250 application_chat_unlock(app); 251 } 252 253 void 254 ui_accounts_dialog_cleanup(UI_ACCOUNTS_Handle *handle, 255 MESSENGER_Application *app) 256 { 257 g_assert((handle) && (app)); 258 259 _ui_accounts_cleanup_listbox(handle, app); 260 261 g_object_unref(handle->builder); 262 263 guint show = handle->show_queued; 264 memset(handle, 0, sizeof(*handle)); 265 handle->show_queued = show; 266 }