messenger-gtk

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

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 }