file.c (7329B)
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 file.c 23 */ 24 25 #include "file.h" 26 #include <gnunet/gnunet_chat_lib.h> 27 28 void 29 file_create_info(struct GNUNET_CHAT_File *file) 30 { 31 if ((!file) || (GNUNET_CHAT_file_get_user_pointer(file))) 32 return; 33 34 MESSENGER_FileInfo* info = g_malloc(sizeof(MESSENGER_FileInfo)); 35 36 info->app = NULL; 37 38 info->update_task = 0; 39 info->file_messages = NULL; 40 41 info->preview_image = NULL; 42 info->preview_animation = NULL; 43 info->preview_animation_iter = NULL; 44 45 info->redraw_animation_task = 0; 46 info->preview_widgets = NULL; 47 48 GNUNET_CHAT_file_set_user_pointer(file, info); 49 } 50 51 void 52 file_destroy_info(struct GNUNET_CHAT_File *file) 53 { 54 g_assert(file); 55 56 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 57 58 if (!info) 59 return; 60 61 if (info->preview_widgets) 62 g_list_free(info->preview_widgets); 63 64 file_unload_preview_image(file); 65 66 if (info->update_task) 67 util_source_remove(info->update_task); 68 69 if (info->file_messages) 70 g_list_free(info->file_messages); 71 72 g_free(info); 73 74 GNUNET_CHAT_file_set_user_pointer(file, NULL); 75 } 76 77 void 78 file_add_ui_message_to_info(const struct GNUNET_CHAT_File *file, 79 UI_MESSAGE_Handle *message) 80 { 81 g_assert(message); 82 83 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 84 85 if (!info) 86 return; 87 88 info->file_messages = g_list_append(info->file_messages, message); 89 } 90 91 void 92 file_add_widget_to_preview(const struct GNUNET_CHAT_File *file, 93 GtkWidget *widget) 94 { 95 g_assert(widget); 96 97 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 98 99 if (!info) 100 return; 101 102 info->preview_widgets = g_list_append(info->preview_widgets, widget); 103 104 if ((info->preview_image) || 105 (info->preview_animation) || 106 (info->preview_animation_iter)) 107 gtk_widget_queue_draw(widget); 108 } 109 110 void 111 file_remove_widget_from_preview(const struct GNUNET_CHAT_File *file, 112 GtkWidget *widget) 113 { 114 g_assert(widget); 115 116 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 117 118 if (!info) 119 return; 120 121 if (info->preview_widgets) 122 info->preview_widgets = g_list_remove(info->preview_widgets, widget); 123 124 if (!(info->preview_widgets)) 125 file_unload_preview_image(file); 126 } 127 128 void 129 file_update_upload_info(const struct GNUNET_CHAT_File *file, 130 uint64_t completed, 131 uint64_t size) 132 { 133 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 134 135 if (!info) 136 return; 137 138 GList *list = info->file_messages; 139 140 while (list) 141 { 142 UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) list->data; 143 144 gtk_progress_bar_set_fraction( 145 message->file_progress_bar, 146 1.0 * completed / size 147 ); 148 149 list = list->next; 150 } 151 } 152 153 static gboolean 154 file_update_messages(gpointer user_data) 155 { 156 g_assert(user_data); 157 158 MESSENGER_FileInfo* info = (MESSENGER_FileInfo*) user_data; 159 160 info->update_task = 0; 161 162 GList *list = info->file_messages; 163 164 while (list) 165 { 166 UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) list->data; 167 168 ui_message_update(message, info->app, message->msg); 169 170 list = list->next; 171 } 172 173 return FALSE; 174 } 175 176 void 177 file_update_download_info(const struct GNUNET_CHAT_File *file, 178 MESSENGER_Application *app, 179 uint64_t completed, 180 uint64_t size) 181 { 182 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 183 184 if (!info) 185 return; 186 187 GList *list = info->file_messages; 188 189 while (list) 190 { 191 UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) list->data; 192 193 gtk_progress_bar_set_fraction( 194 message->file_progress_bar, 195 1.0 * completed / size 196 ); 197 198 list = list->next; 199 } 200 201 if ((completed < size) || (info->update_task)) 202 return; 203 204 info->app = app; 205 info->update_task = util_idle_add(file_update_messages, info); 206 } 207 208 static void 209 file_draw_preview(MESSENGER_FileInfo* info) 210 { 211 g_assert(info); 212 213 GList *list = info->preview_widgets; 214 215 while (list) 216 { 217 if (!GTK_IS_WIDGET(list->data)) 218 goto skip_data; 219 220 GtkWidget *widget = GTK_WIDGET(list->data); 221 gtk_widget_queue_draw(widget); 222 223 skip_data: 224 list = list->next; 225 } 226 } 227 228 void 229 file_load_preview_image(struct GNUNET_CHAT_File *file) 230 { 231 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 232 233 if (!info) 234 return; 235 236 const char *preview = GNUNET_CHAT_file_open_preview(file); 237 238 if (!preview) 239 return; 240 241 file_unload_preview_image(file); 242 243 info->preview_animation = gdk_pixbuf_animation_new_from_file( 244 preview, NULL 245 ); 246 247 if (!(info->preview_animation)) 248 info->preview_image = gdk_pixbuf_new_from_file(preview, NULL); 249 250 GNUNET_CHAT_file_close_preview(file); 251 252 if (info->preview_widgets) 253 file_draw_preview(info); 254 } 255 256 void 257 file_unload_preview_image(const struct GNUNET_CHAT_File *file) 258 { 259 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 260 261 if (!info) 262 return; 263 264 if (info->preview_image) 265 { 266 g_object_unref(info->preview_image); 267 info->preview_image = NULL; 268 } 269 270 if (info->redraw_animation_task) 271 { 272 util_source_remove(info->redraw_animation_task); 273 info->redraw_animation_task = 0; 274 } 275 276 if (info->preview_animation_iter) 277 { 278 g_object_unref(info->preview_animation_iter); 279 info->preview_animation_iter = NULL; 280 } 281 282 if (info->preview_animation) 283 { 284 g_object_unref(info->preview_animation); 285 info->preview_animation = NULL; 286 } 287 } 288 289 static gboolean 290 file_redraw_animation(gpointer user_data) 291 { 292 g_assert(user_data); 293 294 MESSENGER_FileInfo* info = (MESSENGER_FileInfo*) user_data; 295 296 info->redraw_animation_task = 0; 297 298 file_draw_preview(info); 299 300 return FALSE; 301 } 302 303 GdkPixbuf* 304 file_get_current_preview_image(const struct GNUNET_CHAT_File *file) 305 { 306 MESSENGER_FileInfo* info = GNUNET_CHAT_file_get_user_pointer(file); 307 308 if (!info) 309 return NULL; 310 311 GdkPixbuf *image = info->preview_image; 312 313 if (!(info->preview_animation)) 314 return image; 315 316 if (info->preview_animation_iter) 317 gdk_pixbuf_animation_iter_advance(info->preview_animation_iter, NULL); 318 else 319 info->preview_animation_iter = gdk_pixbuf_animation_get_iter( 320 info->preview_animation, NULL 321 ); 322 323 image = gdk_pixbuf_animation_iter_get_pixbuf(info->preview_animation_iter); 324 325 if (!(info->redraw_animation_task)) 326 { 327 const int delay = gdk_pixbuf_animation_iter_get_delay_time( 328 info->preview_animation_iter 329 ); 330 331 info->redraw_animation_task = util_timeout_add( 332 delay, file_redraw_animation, info 333 ); 334 } 335 336 return image; 337 }