aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheJackiMonster <thejackimonster@gmail.com>2022-02-19 21:31:03 +0100
committerTheJackiMonster <thejackimonster@gmail.com>2022-02-19 21:31:03 +0100
commit3090047dcd647bd1daddf904472a7f909b00f875 (patch)
tree85b246e1e8ce0729b2426f24e57cc4c40ae1ccc0
parent43e1bdf4a87b0e6979aa75f36a920e21028c4f74 (diff)
downloadmessenger-gtk-3090047dcd647bd1daddf904472a7f909b00f875.tar.gz
messenger-gtk-3090047dcd647bd1daddf904472a7f909b00f875.zip
Refactored setting ui content and binding widgets
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
-rw-r--r--Makefile1
-rw-r--r--resources/ui/accounts.ui1
-rw-r--r--src/application.c4
-rw-r--r--src/application.h5
-rw-r--r--src/bindings.c129
-rw-r--r--src/bindings.h60
-rw-r--r--src/event.c81
-rw-r--r--src/ui/account_entry.c26
-rw-r--r--src/ui/account_entry.h8
-rw-r--r--src/ui/accounts.c57
-rw-r--r--src/ui/accounts.h4
-rw-r--r--src/ui/chat.c94
-rw-r--r--src/ui/chat_entry.c4
-rw-r--r--src/ui/chat_entry.h3
-rw-r--r--src/ui/contact_entry.c25
-rw-r--r--src/ui/contact_entry.h4
-rw-r--r--src/ui/contacts.c83
-rw-r--r--src/ui/contacts.h6
-rw-r--r--src/ui/delete_messages.c2
-rw-r--r--src/ui/delete_messages.h2
-rw-r--r--src/ui/invite_contact.c93
-rw-r--r--src/ui/invite_contact.h6
-rw-r--r--src/ui/message.c78
-rw-r--r--src/ui/message.h4
-rw-r--r--src/ui/messenger.c93
-rw-r--r--src/ui/messenger.h7
-rw-r--r--src/ui/new_group.c22
-rw-r--r--src/ui/send_file.c6
28 files changed, 561 insertions, 347 deletions
diff --git a/Makefile b/Makefile
index 0ccef0c..b19a57a 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,7 @@ INSTALL_DIR ?= /usr/local/
8BINARY = messenger-gtk 8BINARY = messenger-gtk
9SOURCES = messenger_gtk.c\ 9SOURCES = messenger_gtk.c\
10 application.c\ 10 application.c\
11 bindings.c\
11 contact.c\ 12 contact.c\
12 event.c\ 13 event.c\
13 file.c\ 14 file.c\
diff --git a/resources/ui/accounts.ui b/resources/ui/accounts.ui
index 5fe3390..fa46d46 100644
--- a/resources/ui/accounts.ui
+++ b/resources/ui/accounts.ui
@@ -72,6 +72,7 @@ Author: Tobias Frisch
72 <object class="GtkListBox" id="accounts_listbox"> 72 <object class="GtkListBox" id="accounts_listbox">
73 <property name="visible">True</property> 73 <property name="visible">True</property>
74 <property name="can-focus">False</property> 74 <property name="can-focus">False</property>
75 <property name="selection-mode">none</property>
75 <child> 76 <child>
76 <object class="GtkListBoxRow"> 77 <object class="GtkListBoxRow">
77 <property name="visible">True</property> 78 <property name="visible">True</property>
diff --git a/src/application.c b/src/application.c
index 46456b9..397621c 100644
--- a/src/application.c
+++ b/src/application.c
@@ -100,7 +100,7 @@ application_init(MESSENGER_Application *app,
100 100
101 pthread_mutex_init(&(app->chat.mutex), NULL); 101 pthread_mutex_init(&(app->chat.mutex), NULL);
102 102
103 app->ui.bindings = g_hash_table_new(g_direct_hash, g_direct_equal); 103 app->bindings = bindings_create();
104 104
105 g_application_add_main_option( 105 g_application_add_main_option(
106 G_APPLICATION(app->application), 106 G_APPLICATION(app->application),
@@ -195,7 +195,7 @@ application_run(MESSENGER_Application *app)
195 195
196 pthread_join(app->chat.tid, NULL); 196 pthread_join(app->chat.tid, NULL);
197 197
198 g_hash_table_destroy(app->ui.bindings); 198 bindings_destroy(app->bindings);
199 199
200 close(app->chat.pipe[0]); 200 close(app->chat.pipe[0]);
201 close(app->chat.pipe[1]); 201 close(app->chat.pipe[1]);
diff --git a/src/application.h b/src/application.h
index 8e3e51a..99fcc69 100644
--- a/src/application.h
+++ b/src/application.h
@@ -42,6 +42,7 @@
42#include "ui/send_file.h" 42#include "ui/send_file.h"
43#include "ui/settings.h" 43#include "ui/settings.h"
44 44
45#include "bindings.h"
45#include "util.h" 46#include "util.h"
46 47
47typedef enum MESSENGER_ApplicationSignal 48typedef enum MESSENGER_ApplicationSignal
@@ -59,6 +60,8 @@ typedef struct MESSENGER_Application
59 GtkApplication *application; 60 GtkApplication *application;
60 GList *notifications; 61 GList *notifications;
61 62
63 MESSENGER_Bindings *bindings;
64
62 struct { 65 struct {
63 int status; 66 int status;
64 pthread_t tid; 67 pthread_t tid;
@@ -73,8 +76,6 @@ typedef struct MESSENGER_Application
73 struct { 76 struct {
74 int status; 77 int status;
75 78
76 GHashTable *bindings;
77
78 UI_MESSENGER_Handle messenger; 79 UI_MESSENGER_Handle messenger;
79 80
80 UI_INVITE_CONTACT_Handle invite_contact; 81 UI_INVITE_CONTACT_Handle invite_contact;
diff --git a/src/bindings.c b/src/bindings.c
new file mode 100644
index 0000000..b7325d4
--- /dev/null
+++ b/src/bindings.c
@@ -0,0 +1,129 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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 bindings.h
23 */
24
25#include "bindings.h"
26#include "util.h"
27
28MESSENGER_Bindings*
29bindings_create()
30{
31 MESSENGER_Bindings *bindings = GNUNET_new(MESSENGER_Bindings);
32
33 bindings->map = GNUNET_CONTAINER_multishortmap_create(8, GNUNET_NO);
34
35 return bindings;
36}
37
38void
39bindings_put(MESSENGER_Bindings *bindings,
40 gconstpointer key,
41 gpointer value)
42{
43 struct GNUNET_ShortHashCode hash;
44 memset(&hash, 0, sizeof(hash));
45 memcpy(&hash, &key, sizeof(key));
46
47 GNUNET_CONTAINER_multishortmap_put(
48 bindings->map,
49 &hash,
50 (void*) value,
51 GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE
52 );
53}
54
55int
56_bindings_append_list(void *cls,
57 UNUSED const struct GNUNET_ShortHashCode *key,
58 void *value)
59{
60 GList **list = (GList**) cls;
61 *list = g_list_append(*list, (gpointer) value);
62 return GNUNET_YES;
63}
64
65void
66bindings_remove(MESSENGER_Bindings *bindings,
67 const void *key,
68 void *value,
69 void (destroy)(void*))
70{
71 struct GNUNET_ShortHashCode hash;
72 memset(&hash, 0, sizeof(hash));
73 memcpy(&hash, &key, sizeof(key));
74
75 if (value)
76 {
77 GNUNET_CONTAINER_multishortmap_remove(
78 bindings->map,
79 &hash,
80 (void*) value
81 );
82
83 if (destroy)
84 destroy(value);
85 }
86 else
87 {
88 GList *values = NULL;
89
90 GNUNET_CONTAINER_multishortmap_get_multiple(
91 bindings->map,
92 &hash,
93 _bindings_append_list,
94 &values
95 );
96
97 GNUNET_CONTAINER_multishortmap_remove_all(
98 bindings->map,
99 &hash
100 );
101
102 if (destroy)
103 g_list_free_full(values, destroy);
104 else
105 g_list_free(values);
106 }
107}
108
109void*
110bindings_get(const MESSENGER_Bindings *bindings,
111 const void *key)
112{
113 struct GNUNET_ShortHashCode hash;
114 memset(&hash, 0, sizeof(hash));
115 memcpy(&hash, &key, sizeof(key));
116
117 return GNUNET_CONTAINER_multishortmap_get(
118 bindings->map,
119 &hash
120 );
121}
122
123void
124bindings_destroy(MESSENGER_Bindings *bindings)
125{
126 GNUNET_CONTAINER_multishortmap_destroy(bindings->map);
127
128 GNUNET_free(bindings);
129}
diff --git a/src/bindings.h b/src/bindings.h
new file mode 100644
index 0000000..bf6e10b
--- /dev/null
+++ b/src/bindings.h
@@ -0,0 +1,60 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2022 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 bindings.h
23 */
24
25#ifndef BINDINGS_H_
26#define BINDINGS_H_
27
28#include <gnunet/platform.h>
29#include <gnunet/gnunet_common.h>
30#include <gnunet/gnunet_container_lib.h>
31
32#include <glib.h>
33
34typedef struct MESSENGER_Bindings
35{
36 struct GNUNET_CONTAINER_MultiShortmap *map;
37} MESSENGER_Bindings;
38
39MESSENGER_Bindings*
40bindings_create();
41
42void
43bindings_put(MESSENGER_Bindings *bindings,
44 gconstpointer key,
45 gpointer value);
46
47void
48bindings_remove(MESSENGER_Bindings *bindings,
49 gconstpointer key,
50 gpointer value,
51 GDestroyNotify destroy);
52
53void*
54bindings_get(const MESSENGER_Bindings *bindings,
55 gconstpointer key);
56
57void
58bindings_destroy(MESSENGER_Bindings *bindings);
59
60#endif /* BINDINGS_H_ */
diff --git a/src/event.c b/src/event.c
index c1f7502..71701db 100644
--- a/src/event.c
+++ b/src/event.c
@@ -93,57 +93,11 @@ _clear_each_selectable_widget(GtkWidget *widget,
93 gtk_container_remove(container, widget); 93 gtk_container_remove(container, widget);
94} 94}
95 95
96static int
97_iterate_accounts(void *cls,
98 const struct GNUNET_CHAT_Handle *handle,
99 struct GNUNET_CHAT_Account *account)
100{
101 MESSENGER_Application *app = (MESSENGER_Application*) cls;
102 UI_MESSENGER_Handle *ui = &(app->ui.messenger);
103
104 const gchar *name = GNUNET_CHAT_account_get_name(account);
105
106 UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app);
107
108 hdy_avatar_set_text(entry->entry_avatar, name);
109 gtk_label_set_text(entry->entry_label, name);
110
111 gtk_list_box_prepend(ui->accounts_listbox, entry->entry_box);
112
113 GtkListBoxRow *row = GTK_LIST_BOX_ROW(
114 gtk_widget_get_parent(entry->entry_box)
115 );
116
117 g_hash_table_insert(ui->bindings, row, account);
118
119 if ((account == GNUNET_CHAT_get_connected(handle)) ||
120 ((app->chat.identity) && (0 == g_strcmp0(app->chat.identity, name))))
121 gtk_widget_activate(GTK_WIDGET(row));
122
123 ui_account_entry_delete(entry);
124 return GNUNET_YES;
125}
126
127void 96void
128event_refresh_accounts(MESSENGER_Application *app) 97event_refresh_accounts(MESSENGER_Application *app)
129{ 98{
130 UI_MESSENGER_Handle *ui = &(app->ui.messenger);
131 CHAT_MESSENGER_Handle *chat = &(app->chat.messenger);
132
133 ui_accounts_dialog_refresh(app, &(app->ui.accounts)); 99 ui_accounts_dialog_refresh(app, &(app->ui.accounts));
134 100 ui_messenger_refresh(app, &(app->ui.messenger));
135 if (!(ui->accounts_listbox))
136 return;
137
138 gtk_list_box_unselect_all(ui->accounts_listbox);
139
140 gtk_container_foreach(
141 GTK_CONTAINER(ui->accounts_listbox),
142 _clear_each_selectable_widget,
143 ui->accounts_listbox
144 );
145
146 GNUNET_CHAT_iterate_accounts(chat->handle, _iterate_accounts, app);
147} 101}
148 102
149static void 103static void
@@ -163,11 +117,7 @@ _add_new_chat_entry(MESSENGER_Application *app,
163 entry->chat->chat_box 117 entry->chat->chat_box
164 ); 118 );
165 119
166 g_hash_table_insert( 120 bindings_put(app->bindings, entry->chat->send_text_view, context);
167 app->ui.bindings,
168 entry->chat->send_text_view,
169 context
170 );
171 121
172 ui->chat_entries = g_list_append(ui->chat_entries, entry); 122 ui->chat_entries = g_list_append(ui->chat_entries, entry);
173 123
@@ -175,11 +125,7 @@ _add_new_chat_entry(MESSENGER_Application *app,
175 gtk_widget_get_parent(entry->entry_box) 125 gtk_widget_get_parent(entry->entry_box)
176 ); 126 );
177 127
178 g_hash_table_insert( 128 bindings_put(app->bindings, row, entry);
179 app->ui.bindings,
180 row,
181 entry
182 );
183 129
184 gtk_list_box_select_row(ui->chats_listbox, row); 130 gtk_list_box_select_row(ui->chats_listbox, row);
185 gtk_list_box_invalidate_filter(ui->chats_listbox); 131 gtk_list_box_invalidate_filter(ui->chats_listbox);
@@ -298,13 +244,23 @@ event_joining_contact(MESSENGER_Application *app,
298 if (!handle) 244 if (!handle)
299 return; 245 return;
300 246
301 UI_MESSAGE_Handle *message = ui_message_new(app, UI_MESSAGE_STATUS);
302 ui_message_update(message, app, msg);
303
304 struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender( 247 struct GNUNET_CHAT_Contact *contact = GNUNET_CHAT_message_get_sender(
305 msg 248 msg
306 ); 249 );
307 250
251 if (!contact)
252 return;
253
254 UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) (
255 bindings_get(handle->joining, contact)
256 );
257
258 if (message)
259 ui_chat_remove_message(handle->chat, app, message);
260
261 message = ui_message_new(app, UI_MESSAGE_STATUS);
262 ui_message_update(message, app, msg);
263
308 contact_create_info(contact); 264 contact_create_info(contact);
309 _update_contact_context(app, contact); 265 _update_contact_context(app, contact);
310 266
@@ -332,6 +288,8 @@ event_joining_contact(MESSENGER_Application *app,
332 gtk_label_set_text(message->timestamp_label, time? time : ""); 288 gtk_label_set_text(message->timestamp_label, time? time : "");
333 289
334 ui_chat_add_message(handle->chat, app, message); 290 ui_chat_add_message(handle->chat, app, message);
291 bindings_put(handle->joining, contact, message);
292
335 ui_chat_entry_update(handle, app, context); 293 ui_chat_entry_update(handle, app, context);
336} 294}
337 295
@@ -344,6 +302,9 @@ event_update_contacts(MESSENGER_Application *app,
344 msg 302 msg
345 ); 303 );
346 304
305 if (!contact)
306 return;
307
347 contact_update_info(contact); 308 contact_update_info(contact);
348 _update_contact_context(app, contact); 309 _update_contact_context(app, contact);
349 310
diff --git a/src/ui/account_entry.c b/src/ui/account_entry.c
index 3c0c52c..4d8355a 100644
--- a/src/ui/account_entry.c
+++ b/src/ui/account_entry.c
@@ -51,6 +51,32 @@ ui_account_entry_new(MESSENGER_Application *app)
51} 51}
52 52
53void 53void
54ui_account_entry_set_account(UI_ACCOUNT_ENTRY_Handle* handle,
55 const struct GNUNET_CHAT_Account *account)
56{
57 const gchar *name = GNUNET_CHAT_account_get_name(account);
58
59 if (!name)
60 return;
61
62 hdy_avatar_set_text(handle->entry_avatar, name);
63 gtk_label_set_text(handle->entry_label, name);
64}
65
66void
67ui_account_entry_set_contact(UI_ACCOUNT_ENTRY_Handle* handle,
68 const struct GNUNET_CHAT_Contact *contact)
69{
70 const gchar *name = GNUNET_CHAT_contact_get_name(contact);
71
72 if (!name)
73 return;
74
75 hdy_avatar_set_text(handle->entry_avatar, name);
76 gtk_label_set_text(handle->entry_label, name);
77}
78
79void
54ui_account_entry_delete(UI_ACCOUNT_ENTRY_Handle *handle) 80ui_account_entry_delete(UI_ACCOUNT_ENTRY_Handle *handle)
55{ 81{
56 g_object_unref(handle->builder); 82 g_object_unref(handle->builder);
diff --git a/src/ui/account_entry.h b/src/ui/account_entry.h
index e5cc446..fa9bc32 100644
--- a/src/ui/account_entry.h
+++ b/src/ui/account_entry.h
@@ -41,6 +41,14 @@ UI_ACCOUNT_ENTRY_Handle*
41ui_account_entry_new(MESSENGER_Application *app); 41ui_account_entry_new(MESSENGER_Application *app);
42 42
43void 43void
44ui_account_entry_set_account(UI_ACCOUNT_ENTRY_Handle* handle,
45 const struct GNUNET_CHAT_Account *account);
46
47void
48ui_account_entry_set_contact(UI_ACCOUNT_ENTRY_Handle* handle,
49 const struct GNUNET_CHAT_Contact *contact);
50
51void
44ui_account_entry_delete(UI_ACCOUNT_ENTRY_Handle *handle); 52ui_account_entry_delete(UI_ACCOUNT_ENTRY_Handle *handle);
45 53
46#endif /* UI_ACCOUNT_ENTRY_H_ */ 54#endif /* UI_ACCOUNT_ENTRY_H_ */
diff --git a/src/ui/accounts.c b/src/ui/accounts.c
index fcd4ad9..0741654 100644
--- a/src/ui/accounts.c
+++ b/src/ui/accounts.c
@@ -72,7 +72,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox,
72 } 72 }
73 73
74 struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( 74 struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) (
75 g_hash_table_lookup(app->ui.bindings, row) 75 bindings_get(app->bindings, row)
76 ); 76 );
77 77
78 if (!account) 78 if (!account)
@@ -109,25 +109,18 @@ _iterate_accounts(void *cls,
109{ 109{
110 MESSENGER_Application *app = (MESSENGER_Application*) cls; 110 MESSENGER_Application *app = (MESSENGER_Application*) cls;
111 111
112 const gchar *name = GNUNET_CHAT_account_get_name(account);
113
114 UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app); 112 UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app);
115 113
116 hdy_avatar_set_text(entry->entry_avatar, name); 114 ui_account_entry_set_account(entry, account);
117 gtk_label_set_text(entry->entry_label, name);
118 115
119 gtk_list_box_prepend(app->ui.accounts.accounts_listbox, entry->entry_box); 116 gtk_list_box_prepend(app->ui.accounts.accounts_listbox, entry->entry_box);
120 117
121 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 118 GtkListBoxRow *row = GTK_LIST_BOX_ROW(
122 gtk_widget_get_parent(entry->entry_box) 119 gtk_widget_get_parent(entry->entry_box)
123 ); 120 );
124 121
125 g_hash_table_insert(app->ui.bindings, row, account); 122 bindings_put(app->bindings, row, account);
126 123 bindings_put(app->ui.accounts.bindings, row, entry);
127 app->ui.accounts.account_entries = g_list_append(
128 app->ui.accounts.account_entries,
129 entry
130 );
131 124
132 return GNUNET_YES; 125 return GNUNET_YES;
133} 126}
@@ -136,8 +129,7 @@ void
136ui_accounts_dialog_init(MESSENGER_Application *app, 129ui_accounts_dialog_init(MESSENGER_Application *app,
137 UI_ACCOUNTS_Handle *handle) 130 UI_ACCOUNTS_Handle *handle)
138{ 131{
139 handle->account_entries = NULL; 132 handle->bindings = bindings_create();
140 handle->bindings = app->ui.bindings;
141 handle->show_queued = 0; 133 handle->show_queued = 0;
142 134
143 handle->builder = gtk_builder_new_from_resource( 135 handle->builder = gtk_builder_new_from_resource(
@@ -198,35 +190,22 @@ _clear_accounts_listbox_rows(UI_ACCOUNTS_Handle *handle,
198 if ((!row) || (!gtk_list_box_row_get_selectable(row))) 190 if ((!row) || (!gtk_list_box_row_get_selectable(row)))
199 goto skip_row; 191 goto skip_row;
200 192
201 g_hash_table_remove(handle->bindings, row);
202
203 if (!bindings_only) 193 if (!bindings_only)
204 gtk_container_remove( 194 gtk_container_remove(
205 GTK_CONTAINER(handle->accounts_listbox), 195 GTK_CONTAINER(handle->accounts_listbox),
206 GTK_WIDGET(row) 196 GTK_WIDGET(row)
207 ); 197 );
208 198
209 skip_row: 199 bindings_remove(
210 list = list->next; 200 handle->bindings,
211 } 201 row,
212} 202 NULL,
213 203 (GDestroyNotify) ui_account_entry_delete
214static void 204 );
215_clear_accounts_entries(UI_ACCOUNTS_Handle *handle)
216{
217 GList *list = handle->account_entries;
218
219 while (list) {
220 if (list->data)
221 ui_account_entry_delete((UI_ACCOUNT_ENTRY_Handle*) list->data);
222 205
206 skip_row:
223 list = list->next; 207 list = list->next;
224 } 208 }
225
226 if (handle->account_entries)
227 g_list_free(handle->account_entries);
228
229 handle->account_entries = NULL;
230} 209}
231 210
232void 211void
@@ -236,20 +215,13 @@ ui_accounts_dialog_refresh(MESSENGER_Application *app,
236 if (!(handle->accounts_listbox)) 215 if (!(handle->accounts_listbox))
237 return; 216 return;
238 217
239 if (!(handle->account_entries))
240 goto add_account_entries;
241
242 _clear_accounts_listbox_rows(handle, FALSE); 218 _clear_accounts_listbox_rows(handle, FALSE);
243 _clear_accounts_entries(handle);
244 219
245add_account_entries:
246 GNUNET_CHAT_iterate_accounts( 220 GNUNET_CHAT_iterate_accounts(
247 app->chat.messenger.handle, 221 app->chat.messenger.handle,
248 _iterate_accounts, 222 _iterate_accounts,
249 app 223 app
250 ); 224 );
251
252 gtk_list_box_unselect_all(handle->accounts_listbox);
253} 225}
254 226
255void 227void
@@ -259,7 +231,8 @@ ui_accounts_dialog_cleanup(UI_ACCOUNTS_Handle *handle)
259 231
260 g_object_unref(handle->builder); 232 g_object_unref(handle->builder);
261 233
262 _clear_accounts_entries(handle); 234 bindings_destroy(handle->bindings);
235 handle->bindings = NULL;
263 236
264 handle->accounts_listbox = NULL; 237 handle->accounts_listbox = NULL;
265} 238}
diff --git a/src/ui/accounts.h b/src/ui/accounts.h
index 6a098d8..c8a8549 100644
--- a/src/ui/accounts.h
+++ b/src/ui/accounts.h
@@ -26,11 +26,11 @@
26#define UI_ACCOUNTS_H_ 26#define UI_ACCOUNTS_H_
27 27
28#include "messenger.h" 28#include "messenger.h"
29#include "../bindings.h"
29 30
30typedef struct UI_ACCOUNTS_Handle 31typedef struct UI_ACCOUNTS_Handle
31{ 32{
32 GList *account_entries; 33 MESSENGER_Bindings *bindings;
33 GHashTable *bindings;
34 guint show_queued; 34 guint show_queued;
35 35
36 GtkBuilder *builder; 36 GtkBuilder *builder;
diff --git a/src/ui/chat.c b/src/ui/chat.c
index 7919989..cf0fa38 100644
--- a/src/ui/chat.c
+++ b/src/ui/chat.c
@@ -76,7 +76,7 @@ handle_chat_contacts_listbox_row_activated(GtkListBox *listbox,
76 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 76 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
77 77
78 GtkTextView *text_view = GTK_TEXT_VIEW( 78 GtkTextView *text_view = GTK_TEXT_VIEW(
79 g_hash_table_lookup(app->ui.bindings, listbox) 79 bindings_get(app->bindings, listbox)
80 ); 80 );
81 81
82 if (!text_view) 82 if (!text_view)
@@ -86,18 +86,14 @@ handle_chat_contacts_listbox_row_activated(GtkListBox *listbox,
86 { 86 {
87 ui_invite_contact_dialog_init(app, &(app->ui.invite_contact)); 87 ui_invite_contact_dialog_init(app, &(app->ui.invite_contact));
88 88
89 g_hash_table_insert( 89 bindings_put(app->bindings, app->ui.invite_contact.contacts_listbox, text_view);
90 app->ui.bindings,
91 app->ui.invite_contact.contacts_listbox,
92 text_view
93 );
94 90
95 gtk_widget_show(GTK_WIDGET(app->ui.invite_contact.dialog)); 91 gtk_widget_show(GTK_WIDGET(app->ui.invite_contact.dialog));
96 return; 92 return;
97 } 93 }
98 94
99 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( 95 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) (
100 g_hash_table_lookup(app->ui.bindings, row) 96 bindings_get(app->bindings, row)
101 ); 97 );
102 98
103 if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) || 99 if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) ||
@@ -159,11 +155,11 @@ handle_chat_messages_sort(GtkListBoxRow* row0,
159 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 155 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
160 156
161 UI_MESSAGE_Handle *message0 = (UI_MESSAGE_Handle*) ( 157 UI_MESSAGE_Handle *message0 = (UI_MESSAGE_Handle*) (
162 g_hash_table_lookup(app->ui.bindings, row0) 158 bindings_get(app->bindings, row0)
163 ); 159 );
164 160
165 UI_MESSAGE_Handle *message1 = (UI_MESSAGE_Handle*) ( 161 UI_MESSAGE_Handle *message1 = (UI_MESSAGE_Handle*) (
166 g_hash_table_lookup(app->ui.bindings, row1) 162 bindings_get(app->bindings, row1)
167 ); 163 );
168 164
169 if ((!message0) || (!message1)) 165 if ((!message0) || (!message1))
@@ -216,7 +212,7 @@ handle_chat_selection_close_button_click(UNUSED GtkButton *button,
216} 212}
217 213
218void 214void
219_delete_messages_callback(GHashTable *bindings, 215_delete_messages_callback(MESSENGER_Application *app,
220 GList *selected, 216 GList *selected,
221 gulong delay) 217 gulong delay)
222{ 218{
@@ -229,7 +225,7 @@ _delete_messages_callback(GHashTable *bindings,
229 if (!row) 225 if (!row)
230 goto skip_row; 226 goto skip_row;
231 227
232 message = g_hash_table_lookup(bindings, row); 228 message = bindings_get(app->bindings, row);
233 229
234 if ((!message) || (!(message->msg))) 230 if ((!message) || (!(message->msg)))
235 goto skip_row; 231 goto skip_row;
@@ -258,7 +254,7 @@ handle_chat_selection_delete_button_click(UNUSED GtkButton *button,
258 GList *selected = gtk_list_box_get_selected_rows(handle->messages_listbox); 254 GList *selected = gtk_list_box_get_selected_rows(handle->messages_listbox);
259 255
260 if (app->settings.hide_delete_dialog) 256 if (app->settings.hide_delete_dialog)
261 _delete_messages_callback(app->ui.bindings, selected, 0); 257 _delete_messages_callback(app, selected, 0);
262 else 258 else
263 { 259 {
264 ui_delete_messages_dialog_init(app, &(app->ui.delete_messages)); 260 ui_delete_messages_dialog_init(app, &(app->ui.delete_messages));
@@ -280,7 +276,7 @@ handle_attach_file_button_click(GtkButton *button,
280 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 276 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
281 277
282 GtkTextView *text_view = GTK_TEXT_VIEW( 278 GtkTextView *text_view = GTK_TEXT_VIEW(
283 g_hash_table_lookup(app->ui.bindings, button) 279 bindings_get(app->bindings, button)
284 ); 280 );
285 281
286 if (!text_view) 282 if (!text_view)
@@ -312,11 +308,7 @@ handle_attach_file_button_click(GtkButton *button,
312 308
313 g_free(filename); 309 g_free(filename);
314 310
315 g_hash_table_insert( 311 bindings_put(app->bindings, app->ui.send_file.send_button, text_view);
316 app->ui.bindings,
317 app->ui.send_file.send_button,
318 text_view
319 );
320 312
321 gtk_widget_show(GTK_WIDGET(app->ui.send_file.dialog)); 313 gtk_widget_show(GTK_WIDGET(app->ui.send_file.dialog));
322 314
@@ -360,8 +352,8 @@ _send_text_from_view(MESSENGER_Application *app,
360 if (0 == strlen(text)) 352 if (0 == strlen(text))
361 return FALSE; 353 return FALSE;
362 354
363 struct GNUNET_CHAT_Context *context = g_hash_table_lookup( 355 struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) (
364 app->ui.bindings, text_view 356 bindings_get(app->bindings, text_view)
365 ); 357 );
366 358
367 if (context) 359 if (context)
@@ -378,7 +370,7 @@ handle_send_record_button_click(GtkButton *button,
378 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 370 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
379 371
380 GtkTextView *text_view = GTK_TEXT_VIEW( 372 GtkTextView *text_view = GTK_TEXT_VIEW(
381 g_hash_table_lookup(app->ui.bindings, button) 373 bindings_get(app->bindings, button)
382 ); 374 );
383 375
384 if (!_send_text_from_view(app, text_view)) 376 if (!_send_text_from_view(app, text_view))
@@ -654,23 +646,9 @@ ui_chat_new(MESSENGER_Application *app)
654 app 646 app
655 ); 647 );
656 648
657 g_hash_table_insert( 649 bindings_put(app->bindings, handle->chat_contacts_listbox, handle->send_text_view);
658 app->ui.bindings, 650 bindings_put(app->bindings, handle->attach_file_button, handle->send_text_view);
659 handle->chat_contacts_listbox, 651 bindings_put(app->bindings, handle->send_record_button, handle->send_text_view);
660 handle->send_text_view
661 );
662
663 g_hash_table_insert(
664 app->ui.bindings,
665 handle->attach_file_button,
666 handle->send_text_view
667 );
668
669 g_hash_table_insert(
670 app->ui.bindings,
671 handle->send_record_button,
672 handle->send_text_view
673 );
674 652
675 handle->picker_revealer = GTK_REVEALER( 653 handle->picker_revealer = GTK_REVEALER(
676 gtk_builder_get_object(handle->builder, "picker_revealer") 654 gtk_builder_get_object(handle->builder, "picker_revealer")
@@ -695,7 +673,6 @@ ui_chat_new(MESSENGER_Application *app)
695 673
696struct IterateChatGroupClosure { 674struct IterateChatGroupClosure {
697 MESSENGER_Application *app; 675 MESSENGER_Application *app;
698 GHashTable *bindings;
699 GtkListBox *listbox; 676 GtkListBox *listbox;
700}; 677};
701 678
@@ -711,10 +688,7 @@ iterate_ui_chat_update_group_contacts(void *cls,
711 GtkListBox *listbox = closure->listbox; 688 GtkListBox *listbox = closure->listbox;
712 UI_ACCOUNT_ENTRY_Handle* entry = ui_account_entry_new(closure->app); 689 UI_ACCOUNT_ENTRY_Handle* entry = ui_account_entry_new(closure->app);
713 690
714 const char *name = GNUNET_CHAT_contact_get_name(contact); 691 ui_account_entry_set_contact(entry, contact);
715
716 gtk_label_set_text(entry->entry_label, name? name : "");
717 hdy_avatar_set_text(entry->entry_avatar, name? name : "");
718 692
719 gtk_list_box_prepend(listbox, entry->entry_box); 693 gtk_list_box_prepend(listbox, entry->entry_box);
720 694
@@ -722,7 +696,7 @@ iterate_ui_chat_update_group_contacts(void *cls,
722 gtk_widget_get_parent(entry->entry_box) 696 gtk_widget_get_parent(entry->entry_box)
723 ); 697 );
724 698
725 g_hash_table_insert(closure->bindings, row, contact); 699 bindings_put(closure->app->bindings, row, contact);
726 700
727 ui_account_entry_delete(entry); 701 ui_account_entry_delete(entry);
728 return GNUNET_YES; 702 return GNUNET_YES;
@@ -776,8 +750,7 @@ ui_chat_update(UI_CHAT_Handle *handle,
776 GtkWidget *widget = GTK_WIDGET(children->data); 750 GtkWidget *widget = GTK_WIDGET(children->data);
777 children = children->next; 751 children = children->next;
778 752
779 if (g_hash_table_contains(app->ui.bindings, widget)) 753 bindings_remove(app->bindings, widget, NULL, NULL);
780 g_hash_table_remove(app->ui.bindings, widget);
781 754
782 gtk_container_remove( 755 gtk_container_remove(
783 GTK_CONTAINER(handle->chat_contacts_listbox), 756 GTK_CONTAINER(handle->chat_contacts_listbox),
@@ -789,7 +762,6 @@ ui_chat_update(UI_CHAT_Handle *handle,
789 { 762 {
790 struct IterateChatGroupClosure closure; 763 struct IterateChatGroupClosure closure;
791 closure.app = app; 764 closure.app = app;
792 closure.bindings = app->ui.bindings;
793 closure.listbox = handle->chat_contacts_listbox; 765 closure.listbox = handle->chat_contacts_listbox;
794 766
795 GNUNET_CHAT_group_iterate_contacts( 767 GNUNET_CHAT_group_iterate_contacts(
@@ -845,29 +817,11 @@ ui_chat_delete(UI_CHAT_Handle *handle)
845 817
846 g_object_unref(handle->builder); 818 g_object_unref(handle->builder);
847 819
848 GList *list = handle->messages;
849
850 while (list) {
851 if (list->data)
852 ui_message_delete((UI_MESSAGE_Handle*) list->data);
853
854 list = list->next;
855 }
856
857 list = handle->loads;
858
859 while (list) {
860 if (list->data)
861 ui_file_load_entry_delete((UI_FILE_LOAD_ENTRY_Handle*) list->data);
862
863 list = list->next;
864 }
865
866 if (handle->messages) 820 if (handle->messages)
867 g_list_free(handle->messages); 821 g_list_free_full(handle->messages, (GDestroyNotify) ui_message_delete);
868 822
869 if (handle->loads) 823 if (handle->loads)
870 g_list_free(handle->loads); 824 g_list_free_full(handle->loads, (GDestroyNotify) ui_file_load_entry_delete);
871 825
872 g_free(handle); 826 g_free(handle);
873} 827}
@@ -886,7 +840,7 @@ ui_chat_add_message(UI_CHAT_Handle *handle,
886 840
887 GtkWidget *row = gtk_widget_get_parent(message->message_box); 841 GtkWidget *row = gtk_widget_get_parent(message->message_box);
888 842
889 g_hash_table_insert(app->ui.bindings, row, message); 843 bindings_put(app->bindings, row, message);
890 844
891 handle->messages = g_list_prepend(handle->messages, message); 845 handle->messages = g_list_prepend(handle->messages, message);
892 846
@@ -904,12 +858,14 @@ ui_chat_remove_message(UI_CHAT_Handle *handle,
904 858
905 GtkWidget *row = gtk_widget_get_parent(message->message_box); 859 GtkWidget *row = gtk_widget_get_parent(message->message_box);
906 860
907 g_hash_table_remove(app->ui.bindings, row); 861 bindings_remove(app->bindings, row, NULL, NULL);
908 862
909 gtk_container_remove( 863 gtk_container_remove(
910 GTK_CONTAINER(handle->messages_listbox), 864 GTK_CONTAINER(handle->messages_listbox),
911 gtk_widget_get_parent(GTK_WIDGET(message->message_box)) 865 gtk_widget_get_parent(GTK_WIDGET(message->message_box))
912 ); 866 );
867
868 handle->messages = g_list_append(handle->messages, message);
913} 869}
914 870
915void 871void
diff --git a/src/ui/chat_entry.c b/src/ui/chat_entry.c
index 3c9461e..99f03cc 100644
--- a/src/ui/chat_entry.c
+++ b/src/ui/chat_entry.c
@@ -34,6 +34,8 @@ ui_chat_entry_new(MESSENGER_Application *app)
34{ 34{
35 UI_CHAT_ENTRY_Handle* handle = g_malloc(sizeof(UI_CHAT_ENTRY_Handle)); 35 UI_CHAT_ENTRY_Handle* handle = g_malloc(sizeof(UI_CHAT_ENTRY_Handle));
36 36
37 handle->joining = bindings_create();
38
37 handle->chat = ui_chat_new(app); 39 handle->chat = ui_chat_new(app);
38 handle->builder = gtk_builder_new_from_resource( 40 handle->builder = gtk_builder_new_from_resource(
39 application_get_resource_path(app, "ui/chat_entry.ui") 41 application_get_resource_path(app, "ui/chat_entry.ui")
@@ -153,5 +155,7 @@ ui_chat_entry_delete(UI_CHAT_ENTRY_Handle *handle)
153 155
154 g_object_unref(handle->builder); 156 g_object_unref(handle->builder);
155 157
158 bindings_destroy(handle->joining);
159
156 g_free(handle); 160 g_free(handle);
157} 161}
diff --git a/src/ui/chat_entry.h b/src/ui/chat_entry.h
index cdf19d7..d6d70ea 100644
--- a/src/ui/chat_entry.h
+++ b/src/ui/chat_entry.h
@@ -26,9 +26,12 @@
26#define UI_CHAT_ENTRY_H_ 26#define UI_CHAT_ENTRY_H_
27 27
28#include "chat.h" 28#include "chat.h"
29#include "../bindings.h"
29 30
30typedef struct UI_CHAT_ENTRY_Handle 31typedef struct UI_CHAT_ENTRY_Handle
31{ 32{
33 MESSENGER_Bindings *joining;
34
32 UI_CHAT_Handle *chat; 35 UI_CHAT_Handle *chat;
33 GtkBuilder *builder; 36 GtkBuilder *builder;
34 37
diff --git a/src/ui/contact_entry.c b/src/ui/contact_entry.c
index 291c3b0..54fe80a 100644
--- a/src/ui/contact_entry.c
+++ b/src/ui/contact_entry.c
@@ -55,6 +55,31 @@ ui_contact_entry_new(MESSENGER_Application *app)
55} 55}
56 56
57void 57void
58ui_contact_entry_set_contact(UI_CONTACT_ENTRY_Handle* handle,
59 const struct GNUNET_CHAT_Contact *contact)
60{
61
62 const gchar *name;
63 const gchar *key;
64
65 name = GNUNET_CHAT_contact_get_name(contact);
66
67 if (!name)
68 goto skip_name;
69
70 hdy_avatar_set_text(handle->entry_avatar, name);
71 gtk_label_set_text(handle->title_label, name);
72
73skip_name:
74 key = GNUNET_CHAT_contact_get_key(contact);
75
76 if (!key)
77 return;
78
79 gtk_label_set_text(handle->subtitle_label, name);
80}
81
82void
58ui_contact_entry_delete(UI_CONTACT_ENTRY_Handle *handle) 83ui_contact_entry_delete(UI_CONTACT_ENTRY_Handle *handle)
59{ 84{
60 g_object_unref(handle->builder); 85 g_object_unref(handle->builder);
diff --git a/src/ui/contact_entry.h b/src/ui/contact_entry.h
index 1ec97fc..a9ff9dd 100644
--- a/src/ui/contact_entry.h
+++ b/src/ui/contact_entry.h
@@ -43,6 +43,10 @@ UI_CONTACT_ENTRY_Handle*
43ui_contact_entry_new(MESSENGER_Application *app); 43ui_contact_entry_new(MESSENGER_Application *app);
44 44
45void 45void
46ui_contact_entry_set_contact(UI_CONTACT_ENTRY_Handle* handle,
47 const struct GNUNET_CHAT_Contact *contact);
48
49void
46ui_contact_entry_delete(UI_CONTACT_ENTRY_Handle *handle); 50ui_contact_entry_delete(UI_CONTACT_ENTRY_Handle *handle);
47 51
48#endif /* UI_CONTACT_ENTRY_H_ */ 52#endif /* UI_CONTACT_ENTRY_H_ */
diff --git a/src/ui/contacts.c b/src/ui/contacts.c
index 2e3b0ec..21d2f2f 100644
--- a/src/ui/contacts.c
+++ b/src/ui/contacts.c
@@ -61,7 +61,7 @@ handle_contacts_listbox_row_activated(UNUSED GtkListBox* listbox,
61 } 61 }
62 62
63 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( 63 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) (
64 g_hash_table_lookup(app->ui.bindings, row) 64 bindings_get(app->bindings, row)
65 ); 65 );
66 66
67 if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) || 67 if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) ||
@@ -88,7 +88,7 @@ handle_contacts_listbox_filter_func(GtkListBoxRow *row,
88{ 88{
89 UI_CONTACTS_Handle *handle = (UI_CONTACTS_Handle*) user_data; 89 UI_CONTACTS_Handle *handle = (UI_CONTACTS_Handle*) user_data;
90 90
91 if (!gtk_list_box_row_get_selectable(row)) 91 if ((!row) || (!gtk_list_box_row_get_selectable(row)))
92 return TRUE; 92 return TRUE;
93 93
94 const gchar *filter = gtk_entry_get_text( 94 const gchar *filter = gtk_entry_get_text(
@@ -98,14 +98,14 @@ handle_contacts_listbox_filter_func(GtkListBoxRow *row,
98 if (!filter) 98 if (!filter)
99 return TRUE; 99 return TRUE;
100 100
101 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( 101 UI_CONTACT_ENTRY_Handle *entry = (UI_CONTACT_ENTRY_Handle*) (
102 g_hash_table_lookup(handle->bindings, row) 102 bindings_get(handle->bindings, row)
103 ); 103 );
104 104
105 if (!contact) 105 if (!entry)
106 return FALSE; 106 return FALSE;
107 107
108 const gchar *name = GNUNET_CHAT_contact_get_name(contact); 108 const gchar *name = gtk_label_get_text(entry->title_label);
109 109
110 if (!name) 110 if (!name)
111 return FALSE; 111 return FALSE;
@@ -139,36 +139,20 @@ _iterate_contacts(void *cls,
139 139
140 MESSENGER_Application *app = (MESSENGER_Application*) cls; 140 MESSENGER_Application *app = (MESSENGER_Application*) cls;
141 141
142 const char *title;
143 title = GNUNET_CHAT_contact_get_name(contact);
144
145 const char *key = GNUNET_CHAT_contact_get_key(contact);
146
147 UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app); 142 UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app);
143 ui_contact_entry_set_contact(entry, contact);
144
148 gtk_list_box_prepend( 145 gtk_list_box_prepend(
149 app->ui.contacts.contacts_listbox, 146 app->ui.contacts.contacts_listbox,
150 entry->entry_box 147 entry->entry_box
151 ); 148 );
152 149
153 if (title)
154 {
155 gtk_label_set_text(entry->title_label, title);
156 hdy_avatar_set_text(entry->entry_avatar, title);
157 }
158
159 if (key)
160 gtk_label_set_text(entry->subtitle_label, key);
161
162 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 150 GtkListBoxRow *row = GTK_LIST_BOX_ROW(
163 gtk_widget_get_parent(entry->entry_box) 151 gtk_widget_get_parent(entry->entry_box)
164 ); 152 );
165 153
166 g_hash_table_insert(app->ui.bindings, row, contact); 154 bindings_put(app->bindings, row, contact);
167 155 bindings_put(app->ui.contacts.bindings, row, entry);
168 app->ui.contacts.contact_entries = g_list_append(
169 app->ui.contacts.contact_entries,
170 entry
171 );
172 156
173 return GNUNET_YES; 157 return GNUNET_YES;
174} 158}
@@ -177,8 +161,7 @@ void
177ui_contacts_dialog_init(MESSENGER_Application *app, 161ui_contacts_dialog_init(MESSENGER_Application *app,
178 UI_CONTACTS_Handle *handle) 162 UI_CONTACTS_Handle *handle)
179{ 163{
180 handle->contact_entries = NULL; 164 handle->bindings = bindings_create();
181 handle->bindings = app->ui.bindings;
182 165
183 handle->builder = gtk_builder_new_from_resource( 166 handle->builder = gtk_builder_new_from_resource(
184 application_get_resource_path(app, "ui/contacts.ui") 167 application_get_resource_path(app, "ui/contacts.ui")
@@ -249,8 +232,9 @@ ui_contacts_dialog_init(MESSENGER_Application *app,
249 gtk_list_box_invalidate_filter(handle->contacts_listbox); 232 gtk_list_box_invalidate_filter(handle->contacts_listbox);
250} 233}
251 234
252void 235static void
253ui_contacts_dialog_cleanup(UI_CONTACTS_Handle *handle) 236_clear_contacts_listbox_rows(UI_CONTACTS_Handle *handle,
237 gboolean bindings_only)
254{ 238{
255 GList *list = gtk_container_get_children( 239 GList *list = gtk_container_get_children(
256 GTK_CONTAINER(handle->contacts_listbox) 240 GTK_CONTAINER(handle->contacts_listbox)
@@ -258,23 +242,38 @@ ui_contacts_dialog_cleanup(UI_CONTACTS_Handle *handle)
258 242
259 while (list) 243 while (list)
260 { 244 {
261 if (list->data) 245 GtkListBoxRow *row = GTK_LIST_BOX_ROW(list->data);
262 g_hash_table_remove(handle->bindings, list->data);
263 246
264 list = list->next; 247 if ((!row) || (!gtk_list_box_row_get_selectable(row)))
265 } 248 goto skip_row;
266 249
267 g_object_unref(handle->builder); 250 if (!bindings_only)
251 gtk_container_remove(
252 GTK_CONTAINER(handle->contacts_listbox),
253 GTK_WIDGET(row)
254 );
268 255
269 list = handle->contact_entries; 256 bindings_remove(
270 257 handle->bindings,
271 while (list) { 258 row,
272 if (list->data) 259 NULL,
273 ui_contact_entry_delete((UI_CONTACT_ENTRY_Handle*) list->data); 260 (GDestroyNotify) ui_contact_entry_delete
261 );
274 262
263 skip_row:
275 list = list->next; 264 list = list->next;
276 } 265 }
266}
267
268void
269ui_contacts_dialog_cleanup(UI_CONTACTS_Handle *handle)
270{
271 _clear_contacts_listbox_rows(handle, TRUE);
272
273 g_object_unref(handle->builder);
274
275 bindings_destroy(handle->bindings);
276 handle->bindings = NULL;
277 277
278 if (handle->contact_entries) 278 handle->contacts_listbox = NULL;
279 g_list_free(handle->contact_entries);
280} 279}
diff --git a/src/ui/contacts.h b/src/ui/contacts.h
index 499c3fe..89e7946 100644
--- a/src/ui/contacts.h
+++ b/src/ui/contacts.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2021 GNUnet e.V. 3 Copyright (C) 2021--2022 GNUnet e.V.
4 4
5 GNUnet is free software: you can redistribute it and/or modify it 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 6 under the terms of the GNU Affero General Public License as published
@@ -26,11 +26,11 @@
26#define UI_CONTACTS_H_ 26#define UI_CONTACTS_H_
27 27
28#include "messenger.h" 28#include "messenger.h"
29#include "../bindings.h"
29 30
30typedef struct UI_CONTACTS_Handle 31typedef struct UI_CONTACTS_Handle
31{ 32{
32 GList *contact_entries; 33 MESSENGER_Bindings *bindings;
33 GHashTable *bindings;
34 34
35 GtkBuilder *builder; 35 GtkBuilder *builder;
36 GtkDialog *dialog; 36 GtkDialog *dialog;
diff --git a/src/ui/delete_messages.c b/src/ui/delete_messages.c
index df75484..300c42e 100644
--- a/src/ui/delete_messages.c
+++ b/src/ui/delete_messages.c
@@ -57,7 +57,7 @@ handle_confirm_button_click(UNUSED GtkButton *button,
57 57
58 if (app->ui.delete_messages.callback) 58 if (app->ui.delete_messages.callback)
59 app->ui.delete_messages.callback( 59 app->ui.delete_messages.callback(
60 app->ui.bindings, 60 app,
61 app->ui.delete_messages.selected, 61 app->ui.delete_messages.selected,
62 delay 62 delay
63 ); 63 );
diff --git a/src/ui/delete_messages.h b/src/ui/delete_messages.h
index 9cf9949..b0c04e0 100644
--- a/src/ui/delete_messages.h
+++ b/src/ui/delete_messages.h
@@ -28,7 +28,7 @@
28#include "messenger.h" 28#include "messenger.h"
29 29
30typedef void 30typedef void
31(*UI_DELETE_MESSAGES_Callback) (GHashTable *bindings, 31(*UI_DELETE_MESSAGES_Callback) (MESSENGER_Application *app,
32 GList *selected, 32 GList *selected,
33 gulong delay); 33 gulong delay);
34 34
diff --git a/src/ui/invite_contact.c b/src/ui/invite_contact.c
index 3afeee0..4229067 100644
--- a/src/ui/invite_contact.c
+++ b/src/ui/invite_contact.c
@@ -44,11 +44,11 @@ handle_contacts_listbox_row_activated(GtkListBox* listbox,
44 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 44 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
45 45
46 GtkTextView *text_view = GTK_TEXT_VIEW( 46 GtkTextView *text_view = GTK_TEXT_VIEW(
47 g_hash_table_lookup(app->ui.bindings, listbox) 47 bindings_get(app->bindings, listbox)
48 ); 48 );
49 49
50 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( 50 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) (
51 g_hash_table_lookup(app->ui.bindings, row) 51 bindings_get(app->bindings, row)
52 ); 52 );
53 53
54 if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) || 54 if ((!contact) || (!GNUNET_CHAT_contact_get_key(contact)) ||
@@ -56,8 +56,8 @@ handle_contacts_listbox_row_activated(GtkListBox* listbox,
56 (!text_view)) 56 (!text_view))
57 goto close_dialog; 57 goto close_dialog;
58 58
59 struct GNUNET_CHAT_Context *context = g_hash_table_lookup( 59 struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) (
60 app->ui.bindings, text_view 60 bindings_get(app->bindings, text_view)
61 ); 61 );
62 62
63 if (!context) 63 if (!context)
@@ -78,9 +78,9 @@ static gboolean
78handle_contacts_listbox_filter_func(GtkListBoxRow *row, 78handle_contacts_listbox_filter_func(GtkListBoxRow *row,
79 gpointer user_data) 79 gpointer user_data)
80{ 80{
81 UI_CONTACTS_Handle *handle = (UI_CONTACTS_Handle*) user_data; 81 UI_INVITE_CONTACT_Handle *handle = (UI_INVITE_CONTACT_Handle*) user_data;
82 82
83 if (!gtk_list_box_row_get_selectable(row)) 83 if ((!row) || (!gtk_list_box_row_get_selectable(row)))
84 return TRUE; 84 return TRUE;
85 85
86 const gchar *filter = gtk_entry_get_text( 86 const gchar *filter = gtk_entry_get_text(
@@ -90,14 +90,14 @@ handle_contacts_listbox_filter_func(GtkListBoxRow *row,
90 if (!filter) 90 if (!filter)
91 return TRUE; 91 return TRUE;
92 92
93 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) ( 93 UI_CONTACT_ENTRY_Handle *entry = (UI_CONTACT_ENTRY_Handle*) (
94 g_hash_table_lookup(handle->bindings, row) 94 bindings_get(handle->bindings, row)
95 ); 95 );
96 96
97 if (!contact) 97 if (!entry)
98 return FALSE; 98 return FALSE;
99 99
100 const gchar *name = GNUNET_CHAT_contact_get_name(contact); 100 const gchar *name = gtk_label_get_text(entry->title_label);
101 101
102 if (!name) 102 if (!name)
103 return FALSE; 103 return FALSE;
@@ -131,36 +131,20 @@ _iterate_contacts(void *cls,
131 131
132 MESSENGER_Application *app = (MESSENGER_Application*) cls; 132 MESSENGER_Application *app = (MESSENGER_Application*) cls;
133 133
134 const char *title;
135 title = GNUNET_CHAT_contact_get_name(contact);
136
137 const char *key = GNUNET_CHAT_contact_get_key(contact);
138
139 UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app); 134 UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app);
135 ui_contact_entry_set_contact(entry, contact);
136
140 gtk_list_box_prepend( 137 gtk_list_box_prepend(
141 app->ui.invite_contact.contacts_listbox, 138 app->ui.invite_contact.contacts_listbox,
142 entry->entry_box 139 entry->entry_box
143 ); 140 );
144 141
145 if (title)
146 {
147 gtk_label_set_text(entry->title_label, title);
148 hdy_avatar_set_text(entry->entry_avatar, title);
149 }
150
151 if (key)
152 gtk_label_set_text(entry->subtitle_label, key);
153
154 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 142 GtkListBoxRow *row = GTK_LIST_BOX_ROW(
155 gtk_widget_get_parent(entry->entry_box) 143 gtk_widget_get_parent(entry->entry_box)
156 ); 144 );
157 145
158 g_hash_table_insert(app->ui.bindings, row, contact); 146 bindings_put(app->bindings, row, contact);
159 147 bindings_put(app->ui.invite_contact.bindings, row, entry);
160 app->ui.invite_contact.contact_entries = g_list_append(
161 app->ui.invite_contact.contact_entries,
162 entry
163 );
164 148
165 return GNUNET_YES; 149 return GNUNET_YES;
166} 150}
@@ -169,8 +153,7 @@ void
169ui_invite_contact_dialog_init(MESSENGER_Application *app, 153ui_invite_contact_dialog_init(MESSENGER_Application *app,
170 UI_INVITE_CONTACT_Handle *handle) 154 UI_INVITE_CONTACT_Handle *handle)
171{ 155{
172 handle->contact_entries = NULL; 156 handle->bindings = bindings_create();
173 handle->bindings = app->ui.bindings;
174 157
175 handle->builder = gtk_builder_new_from_resource( 158 handle->builder = gtk_builder_new_from_resource(
176 application_get_resource_path(app, "ui/invite_contact.ui") 159 application_get_resource_path(app, "ui/invite_contact.ui")
@@ -241,20 +224,48 @@ ui_invite_contact_dialog_init(MESSENGER_Application *app,
241 gtk_list_box_invalidate_filter(handle->contacts_listbox); 224 gtk_list_box_invalidate_filter(handle->contacts_listbox);
242} 225}
243 226
244void 227static void
245ui_invite_contact_dialog_cleanup(UI_INVITE_CONTACT_Handle *handle) 228_clear_contacts_listbox_rows(UI_INVITE_CONTACT_Handle *handle,
229 gboolean bindings_only)
246{ 230{
247 g_object_unref(handle->builder); 231 GList *list = gtk_container_get_children(
232 GTK_CONTAINER(handle->contacts_listbox)
233 );
234
235 while (list)
236 {
237 GtkListBoxRow *row = GTK_LIST_BOX_ROW(list->data);
248 238
249 GList *list = handle->contact_entries; 239 if ((!row) || (!gtk_list_box_row_get_selectable(row)))
240 goto skip_row;
250 241
251 while (list) { 242 if (!bindings_only)
252 if (list->data) 243 gtk_container_remove(
253 ui_contact_entry_delete((UI_CONTACT_ENTRY_Handle*) list->data); 244 GTK_CONTAINER(handle->contacts_listbox),
245 GTK_WIDGET(row)
246 );
254 247
248 bindings_remove(
249 handle->bindings,
250 row,
251 NULL,
252 (GDestroyNotify) ui_contact_entry_delete
253 );
254
255 skip_row:
255 list = list->next; 256 list = list->next;
256 } 257 }
258}
259
260void
261ui_invite_contact_dialog_cleanup(UI_INVITE_CONTACT_Handle *handle)
262{
263 _clear_contacts_listbox_rows(handle, TRUE);
264
265 g_object_unref(handle->builder);
266
267 bindings_destroy(handle->bindings);
268 handle->bindings = NULL;
257 269
258 if (handle->contact_entries) 270 handle->contacts_listbox = NULL;
259 g_list_free(handle->contact_entries);
260} 271}
diff --git a/src/ui/invite_contact.h b/src/ui/invite_contact.h
index 94a83e7..4cf1f79 100644
--- a/src/ui/invite_contact.h
+++ b/src/ui/invite_contact.h
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 Copyright (C) 2021 GNUnet e.V. 3 Copyright (C) 2021--2022 GNUnet e.V.
4 4
5 GNUnet is free software: you can redistribute it and/or modify it 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 6 under the terms of the GNU Affero General Public License as published
@@ -26,11 +26,11 @@
26#define UI_INVITE_CONTACT_H_ 26#define UI_INVITE_CONTACT_H_
27 27
28#include "messenger.h" 28#include "messenger.h"
29#include "../bindings.h"
29 30
30typedef struct UI_INVITE_CONTACT_Handle 31typedef struct UI_INVITE_CONTACT_Handle
31{ 32{
32 GList *contact_entries; 33 MESSENGER_Bindings *bindings;
33 GHashTable *bindings;
34 34
35 GtkBuilder *builder; 35 GtkBuilder *builder;
36 GtkDialog *dialog; 36 GtkDialog *dialog;
diff --git a/src/ui/message.c b/src/ui/message.c
index 4920d76..c6a395e 100644
--- a/src/ui/message.c
+++ b/src/ui/message.c
@@ -49,15 +49,15 @@ handle_file_button_click(GtkButton *button,
49{ 49{
50 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 50 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
51 51
52 UI_MESSAGE_Handle* handle = g_hash_table_lookup( 52 UI_MESSAGE_Handle* handle = (UI_MESSAGE_Handle*) (
53 app->ui.bindings, button 53 bindings_get(app->bindings, button)
54 ); 54 );
55 55
56 if (!handle) 56 if (!handle)
57 return; 57 return;
58 58
59 struct GNUNET_CHAT_File *file = g_hash_table_lookup( 59 struct GNUNET_CHAT_File *file = (struct GNUNET_CHAT_File*) (
60 app->ui.bindings, handle->file_progress_bar 60 bindings_get(app->bindings, handle->file_progress_bar)
61 ); 61 );
62 62
63 if (!file) 63 if (!file)
@@ -266,38 +266,38 @@ ui_message_new(MESSENGER_Application *app,
266 break; 266 break;
267 } 267 }
268 268
269 handle->builder = gtk_builder_new_from_resource( 269 handle->builder[0] = gtk_builder_new_from_resource(
270 application_get_resource_path(app, ui_builder_file) 270 application_get_resource_path(app, ui_builder_file)
271 ); 271 );
272 272
273 handle->message_box = GTK_WIDGET( 273 handle->message_box = GTK_WIDGET(
274 gtk_builder_get_object(handle->builder, "message_box") 274 gtk_builder_get_object(handle->builder[0], "message_box")
275 ); 275 );
276 276
277 handle->sender_avatar = HDY_AVATAR( 277 handle->sender_avatar = HDY_AVATAR(
278 gtk_builder_get_object(handle->builder, "sender_avatar") 278 gtk_builder_get_object(handle->builder[0], "sender_avatar")
279 ); 279 );
280 280
281 handle->sender_label = GTK_LABEL( 281 handle->sender_label = GTK_LABEL(
282 gtk_builder_get_object(handle->builder, "sender_label") 282 gtk_builder_get_object(handle->builder[0], "sender_label")
283 ); 283 );
284 284
285 if (UI_MESSAGE_STATUS == handle->type) 285 if (UI_MESSAGE_STATUS == handle->type)
286 { 286 {
287 handle->deny_revealer = GTK_REVEALER( 287 handle->deny_revealer = GTK_REVEALER(
288 gtk_builder_get_object(handle->builder, "deny_revealer") 288 gtk_builder_get_object(handle->builder[0], "deny_revealer")
289 ); 289 );
290 290
291 handle->accept_revealer = GTK_REVEALER( 291 handle->accept_revealer = GTK_REVEALER(
292 gtk_builder_get_object(handle->builder, "accept_revealer") 292 gtk_builder_get_object(handle->builder[0], "accept_revealer")
293 ); 293 );
294 294
295 handle->deny_button = GTK_BUTTON( 295 handle->deny_button = GTK_BUTTON(
296 gtk_builder_get_object(handle->builder, "deny_button") 296 gtk_builder_get_object(handle->builder[0], "deny_button")
297 ); 297 );
298 298
299 handle->accept_button = GTK_BUTTON( 299 handle->accept_button = GTK_BUTTON(
300 gtk_builder_get_object(handle->builder, "accept_button") 300 gtk_builder_get_object(handle->builder[0], "accept_button")
301 ); 301 );
302 } 302 }
303 else 303 else
@@ -310,43 +310,43 @@ ui_message_new(MESSENGER_Application *app,
310 } 310 }
311 311
312 GtkContainer *content_box = GTK_CONTAINER( 312 GtkContainer *content_box = GTK_CONTAINER(
313 gtk_builder_get_object(handle->builder, "content_box") 313 gtk_builder_get_object(handle->builder[0], "content_box")
314 ); 314 );
315 315
316 GtkBuilder *builder = gtk_builder_new_from_resource( 316 handle->builder[1] = gtk_builder_new_from_resource(
317 application_get_resource_path(app, "ui/message_content.ui") 317 application_get_resource_path(app, "ui/message_content.ui")
318 ); 318 );
319 319
320 handle->timestamp_label = GTK_LABEL( 320 handle->timestamp_label = GTK_LABEL(
321 gtk_builder_get_object(builder, "timestamp_label") 321 gtk_builder_get_object(handle->builder[1], "timestamp_label")
322 ); 322 );
323 323
324 handle->read_receipt_image = GTK_IMAGE( 324 handle->read_receipt_image = GTK_IMAGE(
325 gtk_builder_get_object(builder, "read_receipt_image") 325 gtk_builder_get_object(handle->builder[1], "read_receipt_image")
326 ); 326 );
327 327
328 handle->content_stack = GTK_STACK( 328 handle->content_stack = GTK_STACK(
329 gtk_builder_get_object(builder, "content_stack") 329 gtk_builder_get_object(handle->builder[1], "content_stack")
330 ); 330 );
331 331
332 handle->text_label = GTK_LABEL( 332 handle->text_label = GTK_LABEL(
333 gtk_builder_get_object(builder, "text_label") 333 gtk_builder_get_object(handle->builder[1], "text_label")
334 ); 334 );
335 335
336 handle->file_revealer = GTK_REVEALER( 336 handle->file_revealer = GTK_REVEALER(
337 gtk_builder_get_object(builder, "file_revealer") 337 gtk_builder_get_object(handle->builder[1], "file_revealer")
338 ); 338 );
339 339
340 handle->filename_label = GTK_LABEL( 340 handle->filename_label = GTK_LABEL(
341 gtk_builder_get_object(builder, "filename_label") 341 gtk_builder_get_object(handle->builder[1], "filename_label")
342 ); 342 );
343 343
344 handle->file_progress_bar = GTK_PROGRESS_BAR( 344 handle->file_progress_bar = GTK_PROGRESS_BAR(
345 gtk_builder_get_object(builder, "file_progress_bar") 345 gtk_builder_get_object(handle->builder[1], "file_progress_bar")
346 ); 346 );
347 347
348 handle->file_button = GTK_BUTTON( 348 handle->file_button = GTK_BUTTON(
349 gtk_builder_get_object(builder, "file_button") 349 gtk_builder_get_object(handle->builder[1], "file_button")
350 ); 350 );
351 351
352 g_signal_connect( 352 g_signal_connect(
@@ -357,16 +357,16 @@ ui_message_new(MESSENGER_Application *app,
357 ); 357 );
358 358
359 handle->file_status_image = GTK_IMAGE( 359 handle->file_status_image = GTK_IMAGE(
360 gtk_builder_get_object(builder, "file_status_image") 360 gtk_builder_get_object(handle->builder[1], "file_status_image")
361 ); 361 );
362 362
363 g_hash_table_insert(app->ui.bindings, handle->file_button, handle); 363 bindings_put(app->bindings, handle->file_button, handle);
364 364
365 handle->preview_drawing_area = GTK_DRAWING_AREA( 365 handle->preview_drawing_area = GTK_DRAWING_AREA(
366 gtk_builder_get_object(builder, "preview_drawing_area") 366 gtk_builder_get_object(handle->builder[1], "preview_drawing_area")
367 ); 367 );
368 368
369 handle->preview_draw_signal = g_signal_connect( 369 g_signal_connect(
370 handle->preview_drawing_area, 370 handle->preview_drawing_area,
371 "draw", 371 "draw",
372 G_CALLBACK(handle_preview_drawing_area_draw), 372 G_CALLBACK(handle_preview_drawing_area_draw),
@@ -383,11 +383,9 @@ ui_message_new(MESSENGER_Application *app,
383 } 383 }
384 384
385 gtk_container_add(content_box, GTK_WIDGET( 385 gtk_container_add(content_box, GTK_WIDGET(
386 gtk_builder_get_object(builder, "message_content_box") 386 gtk_builder_get_object(handle->builder[1], "message_content_box")
387 )); 387 ));
388 388
389 g_object_unref(builder);
390
391 handle->preview_image = NULL; 389 handle->preview_image = NULL;
392 handle->preview_animation = NULL; 390 handle->preview_animation = NULL;
393 handle->preview_animation_iter = NULL; 391 handle->preview_animation_iter = NULL;
@@ -445,15 +443,14 @@ ui_message_update(UI_MESSAGE_Handle *handle,
445 handle->timestamp = GNUNET_CHAT_message_get_timestamp(msg); 443 handle->timestamp = GNUNET_CHAT_message_get_timestamp(msg);
446 } 444 }
447 else 445 else
448 file = g_hash_table_lookup(app->ui.bindings, handle->message_box); 446 file = (struct GNUNET_CHAT_File*) (
447 bindings_get(app->bindings, handle->message_box)
448 );
449 449
450 if (!file) 450 if (!file)
451 return; 451 return;
452 452
453 if (g_hash_table_contains(app->ui.bindings, handle->message_box)) 453 bindings_put(app->bindings, handle->message_box, file);
454 g_hash_table_replace(app->ui.bindings, handle->message_box, file);
455 else
456 g_hash_table_insert(app->ui.bindings, handle->message_box, file);
457 454
458 uint64_t size = GNUNET_CHAT_file_get_size(file); 455 uint64_t size = GNUNET_CHAT_file_get_size(file);
459 uint64_t local_size = GNUNET_CHAT_file_get_local_size(file); 456 uint64_t local_size = GNUNET_CHAT_file_get_local_size(file);
@@ -522,10 +519,7 @@ file_content:
522 519
523 gtk_revealer_set_reveal_child(handle->file_revealer, TRUE); 520 gtk_revealer_set_reveal_child(handle->file_revealer, TRUE);
524 521
525 if (g_hash_table_contains(app->ui.bindings, handle->file_progress_bar)) 522 bindings_put(app->bindings, handle->file_progress_bar, file);
526 g_hash_table_replace(app->ui.bindings, handle->file_progress_bar, file);
527 else
528 g_hash_table_insert(app->ui.bindings, handle->file_progress_bar, file);
529} 523}
530 524
531void 525void
@@ -533,12 +527,8 @@ ui_message_delete(UI_MESSAGE_Handle *handle)
533{ 527{
534 _clear_message_preview_data(handle); 528 _clear_message_preview_data(handle);
535 529
536 g_signal_handler_disconnect( 530 g_object_unref(handle->builder[1]);
537 handle->preview_drawing_area, 531 g_object_unref(handle->builder[0]);
538 handle->preview_draw_signal
539 );
540
541 g_object_unref(handle->builder);
542 532
543 g_free(handle); 533 g_free(handle);
544} 534}
diff --git a/src/ui/message.h b/src/ui/message.h
index ec4e772..befe536 100644
--- a/src/ui/message.h
+++ b/src/ui/message.h
@@ -48,7 +48,7 @@ typedef struct UI_MESSAGE_Handle
48 struct GNUNET_TIME_Absolute timestamp; 48 struct GNUNET_TIME_Absolute timestamp;
49 const struct GNUNET_CHAT_Message *msg; 49 const struct GNUNET_CHAT_Message *msg;
50 50
51 GtkBuilder *builder; 51 GtkBuilder *builder [2];
52 GtkWidget *message_box; 52 GtkWidget *message_box;
53 53
54 HdyAvatar *sender_avatar; 54 HdyAvatar *sender_avatar;
@@ -75,8 +75,6 @@ typedef struct UI_MESSAGE_Handle
75 75
76 GtkDrawingArea *preview_drawing_area; 76 GtkDrawingArea *preview_drawing_area;
77 77
78 gulong preview_draw_signal;
79
80 GdkPixbuf *preview_image; 78 GdkPixbuf *preview_image;
81 GdkPixbufAnimation *preview_animation; 79 GdkPixbufAnimation *preview_animation;
82 GdkPixbufAnimationIter *preview_animation_iter; 80 GdkPixbufAnimationIter *preview_animation_iter;
diff --git a/src/ui/messenger.c b/src/ui/messenger.c
index 612f568..aff450e 100644
--- a/src/ui/messenger.c
+++ b/src/ui/messenger.c
@@ -26,6 +26,7 @@
26 26
27#include <gtk-3.0/gdk/gdkkeys.h> 27#include <gtk-3.0/gdk/gdkkeys.h>
28 28
29#include "account_entry.h"
29#include "chat_entry.h" 30#include "chat_entry.h"
30#include "contacts.h" 31#include "contacts.h"
31#include "message.h" 32#include "message.h"
@@ -105,7 +106,7 @@ handle_accounts_listbox_row_activated(UNUSED GtkListBox* listbox,
105 } 106 }
106 107
107 struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) ( 108 struct GNUNET_CHAT_Account *account = (struct GNUNET_CHAT_Account*) (
108 g_hash_table_lookup(app->ui.bindings, row) 109 bindings_get(app->bindings, row)
109 ); 110 );
110 111
111 if (!account) 112 if (!account)
@@ -192,8 +193,8 @@ handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox,
192 if (!gtk_list_box_row_get_selectable(row)) 193 if (!gtk_list_box_row_get_selectable(row))
193 return; 194 return;
194 195
195 UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) g_hash_table_lookup( 196 UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) (
196 handle->bindings, row 197 bindings_get(handle->app->bindings, row)
197 ); 198 );
198 199
199 if ((!entry) || (!(entry->chat)) || (!(entry->chat->chat_box))) 200 if ((!entry) || (!(entry->chat)) || (!(entry->chat->chat_box)))
@@ -217,7 +218,7 @@ handle_chats_listbox_filter_func(GtkListBoxRow *row,
217{ 218{
218 UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data; 219 UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data;
219 220
220 if ((!gtk_list_box_row_get_selectable(row)) || 221 if ((!row) || (!gtk_list_box_row_get_selectable(row)) ||
221 (gtk_list_box_row_is_selected(row))) 222 (gtk_list_box_row_is_selected(row)))
222 return TRUE; 223 return TRUE;
223 224
@@ -228,8 +229,8 @@ handle_chats_listbox_filter_func(GtkListBoxRow *row,
228 if (!filter) 229 if (!filter)
229 return TRUE; 230 return TRUE;
230 231
231 UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) g_hash_table_lookup( 232 UI_CHAT_ENTRY_Handle *entry = (UI_CHAT_ENTRY_Handle*) (
232 handle->bindings, row 233 bindings_get(handle->app->bindings, row)
233 ); 234 );
234 235
235 if ((!entry) || (!(entry->title_label))) 236 if ((!entry) || (!(entry->title_label)))
@@ -267,8 +268,8 @@ void
267ui_messenger_init(MESSENGER_Application *app, 268ui_messenger_init(MESSENGER_Application *app,
268 UI_MESSENGER_Handle *handle) 269 UI_MESSENGER_Handle *handle)
269{ 270{
271 handle->app = app;
270 handle->chat_entries = NULL; 272 handle->chat_entries = NULL;
271 handle->bindings = app->ui.bindings;
272 273
273 handle->builder = gtk_builder_new_from_resource( 274 handle->builder = gtk_builder_new_from_resource(
274 application_get_resource_path(app, "ui/messenger.ui") 275 application_get_resource_path(app, "ui/messenger.ui")
@@ -490,6 +491,79 @@ ui_messenger_init(MESSENGER_Application *app,
490 ); 491 );
491} 492}
492 493
494static void
495_messenger_clear_accounts_listbox_rows(UI_MESSENGER_Handle *handle)
496{
497 GList *list = gtk_container_get_children(
498 GTK_CONTAINER(handle->accounts_listbox)
499 );
500
501 while (list)
502 {
503 GtkListBoxRow *row = GTK_LIST_BOX_ROW(list->data);
504
505 if ((!row) || (!gtk_list_box_row_get_selectable(row)))
506 goto skip_row;
507
508 bindings_remove(handle->app->bindings, row, NULL, NULL);
509
510 gtk_container_remove(
511 GTK_CONTAINER(handle->accounts_listbox),
512 GTK_WIDGET(row)
513 );
514
515 skip_row:
516 list = list->next;
517 }
518}
519
520static int
521_messenger_iterate_accounts(void *cls,
522 const struct GNUNET_CHAT_Handle *handle,
523 struct GNUNET_CHAT_Account *account)
524{
525 MESSENGER_Application *app = (MESSENGER_Application*) cls;
526 UI_MESSENGER_Handle *ui = &(app->ui.messenger);
527
528 const gchar *name = GNUNET_CHAT_account_get_name(account);
529
530 UI_ACCOUNT_ENTRY_Handle *entry = ui_account_entry_new(app);
531
532 hdy_avatar_set_text(entry->entry_avatar, name);
533 gtk_label_set_text(entry->entry_label, name);
534
535 gtk_list_box_prepend(ui->accounts_listbox, entry->entry_box);
536
537 GtkListBoxRow *row = GTK_LIST_BOX_ROW(
538 gtk_widget_get_parent(entry->entry_box)
539 );
540
541 bindings_put(app->bindings, row, account);
542
543 if ((account == GNUNET_CHAT_get_connected(handle)) ||
544 ((app->chat.identity) && (0 == g_strcmp0(app->chat.identity, name))))
545 gtk_widget_activate(GTK_WIDGET(row));
546
547 ui_account_entry_delete(entry);
548 return GNUNET_YES;
549}
550
551void
552ui_messenger_refresh(MESSENGER_Application *app,
553 UI_MESSENGER_Handle *handle)
554{
555 if (!(handle->accounts_listbox))
556 return;
557
558 _messenger_clear_accounts_listbox_rows(handle);
559
560 GNUNET_CHAT_iterate_accounts(
561 app->chat.messenger.handle,
562 _messenger_iterate_accounts,
563 app
564 );
565}
566
493gboolean 567gboolean
494ui_messenger_is_context_active(UI_MESSENGER_Handle *handle, 568ui_messenger_is_context_active(UI_MESSENGER_Handle *handle,
495 struct GNUNET_CHAT_Context *context) 569 struct GNUNET_CHAT_Context *context)
@@ -514,11 +588,8 @@ ui_messenger_cleanup(UI_MESSENGER_Handle *handle)
514{ 588{
515 g_object_unref(handle->builder); 589 g_object_unref(handle->builder);
516 590
517 for (GList *list = handle->chat_entries; list; list = list->next)
518 ui_chat_entry_delete((UI_CHAT_ENTRY_Handle*) list->data);
519
520 if (handle->chat_entries) 591 if (handle->chat_entries)
521 g_list_free(handle->chat_entries); 592 g_list_free_full(handle->chat_entries, (GDestroyNotify) ui_chat_entry_delete);
522 593
523 memset(handle, 0, sizeof(*handle)); 594 memset(handle, 0, sizeof(*handle));
524} 595}
diff --git a/src/ui/messenger.h b/src/ui/messenger.h
index c44f74b..c23a27d 100644
--- a/src/ui/messenger.h
+++ b/src/ui/messenger.h
@@ -35,8 +35,9 @@ typedef struct MESSENGER_Application MESSENGER_Application;
35 35
36typedef struct UI_MESSENGER_Handle 36typedef struct UI_MESSENGER_Handle
37{ 37{
38 MESSENGER_Application *app;
39
38 GList *chat_entries; 40 GList *chat_entries;
39 GHashTable *bindings;
40 41
41 GtkBuilder *builder; 42 GtkBuilder *builder;
42 GtkApplicationWindow *main_window; 43 GtkApplicationWindow *main_window;
@@ -77,6 +78,10 @@ void
77ui_messenger_init(MESSENGER_Application *app, 78ui_messenger_init(MESSENGER_Application *app,
78 UI_MESSENGER_Handle *handle); 79 UI_MESSENGER_Handle *handle);
79 80
81void
82ui_messenger_refresh(MESSENGER_Application *app,
83 UI_MESSENGER_Handle *handle);
84
80gboolean 85gboolean
81ui_messenger_is_context_active(UI_MESSENGER_Handle *handle, 86ui_messenger_is_context_active(UI_MESSENGER_Handle *handle,
82 struct GNUNET_CHAT_Context *context); 87 struct GNUNET_CHAT_Context *context);
diff --git a/src/ui/new_group.c b/src/ui/new_group.c
index 59199dc..ed7f0a7 100644
--- a/src/ui/new_group.c
+++ b/src/ui/new_group.c
@@ -50,8 +50,8 @@ _open_new_group(GtkEntry *entry,
50 { 50 {
51 GtkListBoxRow *row = GTK_LIST_BOX_ROW(selected->data); 51 GtkListBoxRow *row = GTK_LIST_BOX_ROW(selected->data);
52 52
53 struct GNUNET_CHAT_Contact* contact = g_hash_table_lookup( 53 struct GNUNET_CHAT_Contact *contact = (struct GNUNET_CHAT_Contact*) (
54 app->ui.bindings, row 54 bindings_get(app->bindings, row)
55 ); 55 );
56 56
57 GNUNET_CHAT_group_invite_contact(group, contact); 57 GNUNET_CHAT_group_invite_contact(group, contact);
@@ -158,31 +158,19 @@ _iterate_contacts(void *cls,
158 158
159 MESSENGER_Application *app = (MESSENGER_Application*) cls; 159 MESSENGER_Application *app = (MESSENGER_Application*) cls;
160 160
161 const char *title;
162 title = GNUNET_CHAT_contact_get_name(contact);
163
164 const char *key = GNUNET_CHAT_contact_get_key(contact);
165
166 UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app); 161 UI_CONTACT_ENTRY_Handle *entry = ui_contact_entry_new(app);
162 ui_contact_entry_set_contact(entry, contact);
163
167 gtk_list_box_prepend( 164 gtk_list_box_prepend(
168 app->ui.new_group.contacts_listbox, 165 app->ui.new_group.contacts_listbox,
169 entry->entry_box 166 entry->entry_box
170 ); 167 );
171 168
172 if (title)
173 {
174 gtk_label_set_text(entry->title_label, title);
175 hdy_avatar_set_text(entry->entry_avatar, title);
176 }
177
178 if (key)
179 gtk_label_set_text(entry->subtitle_label, key);
180
181 GtkListBoxRow *row = GTK_LIST_BOX_ROW( 169 GtkListBoxRow *row = GTK_LIST_BOX_ROW(
182 gtk_widget_get_parent(entry->entry_box) 170 gtk_widget_get_parent(entry->entry_box)
183 ); 171 );
184 172
185 g_hash_table_insert(app->ui.bindings, row, contact); 173 bindings_put(app->bindings, row, contact);
186 174
187 app->ui.new_group.contact_entries = g_list_append( 175 app->ui.new_group.contact_entries = g_list_append(
188 app->ui.new_group.contact_entries, 176 app->ui.new_group.contact_entries,
diff --git a/src/ui/send_file.c b/src/ui/send_file.c
index 42c5584..5555e73 100644
--- a/src/ui/send_file.c
+++ b/src/ui/send_file.c
@@ -65,7 +65,7 @@ handle_send_button_click(GtkButton *button,
65 MESSENGER_Application *app = (MESSENGER_Application*) user_data; 65 MESSENGER_Application *app = (MESSENGER_Application*) user_data;
66 66
67 GtkTextView *text_view = GTK_TEXT_VIEW( 67 GtkTextView *text_view = GTK_TEXT_VIEW(
68 g_hash_table_lookup(app->ui.bindings, button) 68 bindings_get(app->bindings, button)
69 ); 69 );
70 70
71 if (!text_view) 71 if (!text_view)
@@ -78,8 +78,8 @@ handle_send_button_click(GtkButton *button,
78 if (!filename) 78 if (!filename)
79 return; 79 return;
80 80
81 struct GNUNET_CHAT_Context *context = g_hash_table_lookup( 81 struct GNUNET_CHAT_Context *context = (struct GNUNET_CHAT_Context*) (
82 app->ui.bindings, text_view 82 bindings_get(app->bindings, text_view)
83 ); 83 );
84 84
85 UI_CHAT_ENTRY_Handle *entry = GNUNET_CHAT_context_get_user_pointer(context); 85 UI_CHAT_ENTRY_Handle *entry = GNUNET_CHAT_context_get_user_pointer(context);