downloads.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // BadWolf: Minimalist and privacy-oriented WebKitGTK+ browser
  2. // SPDX-FileCopyrightText: 2019-2022 Badwolf Authors <https://hacktivis.me/projects/badwolf>
  3. // SPDX-License-Identifier: BSD-3-Clause
  4. #include "downloads.h"
  5. #include "badwolf.h"
  6. #include "config.h"
  7. #include <assert.h>
  8. #include <glib/gi18n.h> /* _() and other internationalization/localization helpers */
  9. static void
  10. download_stop_iconCb_clicked(GtkButton *UNUSED(stop_icon), gpointer user_data)
  11. {
  12. WebKitDownload *webkit_download = (WebKitDownload *)user_data;
  13. webkit_download_cancel(webkit_download);
  14. }
  15. void
  16. download_format_elapsed(char *restrict formatted,
  17. size_t formatted_size,
  18. char *restrict format,
  19. int total)
  20. {
  21. /* flawfinder: ignore, format string only passed by ourselves */
  22. snprintf(formatted,
  23. formatted_size,
  24. format,
  25. total / 3600, /* hours */
  26. (total % 3600) / 60, /* minutes */
  27. total % 60); /* seconds */
  28. }
  29. void
  30. download_new_entry(WebKitDownload *webkit_download, struct Download *download)
  31. {
  32. download->error = 0;
  33. download->container = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, BADWOLF_DOWNLOAD_PADDING);
  34. download->progress = gtk_progress_bar_new();
  35. download->file_path = gtk_label_new(NULL);
  36. download->status = gtk_label_new(_("Download starting…"));
  37. download->icon = gtk_image_new_from_icon_name("network-idle-symbolic");
  38. download->stop_icon = gtk_button_new_from_icon_name("process-stop");
  39. gtk_progress_bar_set_show_text(GTK_PROGRESS_BAR(download->progress), TRUE);
  40. gtk_label_set_ellipsize(GTK_LABEL(download->file_path), BADWOLF_DOWNLOAD_FILE_PATH_ELLIPSIZE);
  41. g_signal_connect(
  42. download->stop_icon, "clicked", G_CALLBACK(download_stop_iconCb_clicked), webkit_download);
  43. gtk_box_append(GTK_BOX(download->container), download->icon);
  44. gtk_box_append(GTK_BOX(download->container), download->progress);
  45. gtk_box_append(GTK_BOX(download->container), download->stop_icon);
  46. gtk_box_append(GTK_BOX(download->container), download->status);
  47. gtk_box_append(GTK_BOX(download->container), download->file_path);
  48. gtk_list_box_insert(GTK_LIST_BOX(window->downloads_tab), download->container, -1);
  49. }
  50. void
  51. downloadCb_created_destination(WebKitDownload *UNUSED(webkit_download),
  52. gchar *destination,
  53. gpointer user_data)
  54. {
  55. char *markup;
  56. struct Download *download = (struct Download *)user_data;
  57. markup = g_markup_printf_escaped(
  58. "<a href=\"%s\">%s</a>", destination, webkit_uri_for_display(destination));
  59. gtk_label_set_markup(GTK_LABEL(download->file_path), markup);
  60. g_free(markup);
  61. }
  62. static void
  63. file_chooserCb_response(GtkNativeDialog *file_chooser, int response, gpointer user_data)
  64. {
  65. WebKitDownload *webkit_download = (WebKitDownload *)user_data;
  66. if(response != GTK_RESPONSE_ACCEPT) webkit_download_cancel(webkit_download);
  67. // FIXME: Check if it works with both existing files and not-existing files
  68. GFile *destination = gtk_file_chooser_get_file(file_chooser);
  69. webkit_download_set_destination(webkit_download, g_file_get_path(destination));
  70. }
  71. gboolean
  72. downloadCb_decide_destination(WebKitDownload *webkit_download,
  73. gchar *suggested_filename,
  74. gpointer UNUSED(user_data))
  75. {
  76. GtkWindow *parent_window = GTK_WINDOW(window->main_window);
  77. GtkFileChooserNative *file_dialog =
  78. gtk_file_chooser_native_new(NULL, parent_window, GTK_FILE_CHOOSER_ACTION_SAVE, NULL, NULL);
  79. GtkFileChooser *file_chooser = GTK_FILE_CHOOSER(file_dialog);
  80. gtk_file_chooser_set_current_name(file_chooser, suggested_filename);
  81. webkit_download_set_allow_overwrite(webkit_download, TRUE);
  82. g_signal_connect(file_chooser, "response", G_CALLBACK(file_chooserCb_response), webkit_download);
  83. gtk_native_dialog_show(GTK_NATIVE_DIALOG(file_dialog));
  84. return TRUE; /* async */
  85. }
  86. void
  87. downloadCb_failed(WebKitDownload *webkit_download, GError *error, gpointer user_data)
  88. {
  89. struct Download *download = (struct Download *)user_data;
  90. /* flawfinder: ignore. proper buffer limits are used */
  91. char formatted[BUFSIZ];
  92. int total = (int)webkit_download_get_elapsed_time(webkit_download);
  93. char *format;
  94. download->error = error;
  95. if(g_error_matches(error, WEBKIT_DOWNLOAD_ERROR, WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER))
  96. format = _("%02i:%02i:%02i Download cancelled");
  97. else
  98. format = _("%02i:%02i:%02i Download error");
  99. download_format_elapsed(formatted, sizeof(formatted), format, total);
  100. gtk_label_set_text(GTK_LABEL(download->status), formatted);
  101. gtk_image_set_from_icon_name(GTK_IMAGE(download->icon), "network-error-symbolic");
  102. }
  103. void
  104. downloadCb_finished(WebKitDownload *webkit_download, gpointer user_data)
  105. {
  106. struct Download *download = (struct Download *)user_data;
  107. /* flawfinder: ignore. proper buffer limits are used */
  108. char formatted[BUFSIZ];
  109. int total = (int)webkit_download_get_elapsed_time(webkit_download);
  110. gchar *format_size = g_format_size(webkit_download_get_received_data_length(webkit_download));
  111. download_format_elapsed(
  112. formatted, sizeof(formatted), _("%02i:%02i:%02i Download finished"), total);
  113. gtk_widget_destroy(download->stop_icon);
  114. if(download->error == 0)
  115. {
  116. gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(download->progress), 1);
  117. gtk_progress_bar_set_text(GTK_PROGRESS_BAR(download->progress), format_size);
  118. gtk_label_set_text(GTK_LABEL(download->status), formatted);
  119. gtk_image_set_from_icon_name(GTK_IMAGE(download->icon), "network-idle-symbolic");
  120. }
  121. // TODO: Send notification
  122. }
  123. void
  124. downloadCb_received_data(WebKitDownload *webkit_download,
  125. guint64 UNUSED(data_lenght),
  126. gpointer user_data)
  127. {
  128. struct Download *download = (struct Download *)user_data;
  129. /* flawfinder: ignore. proper buffer limits are used */
  130. char formatted[BUFSIZ];
  131. int total = (int)webkit_download_get_elapsed_time(webkit_download);
  132. gchar *format_size = g_format_size(webkit_download_get_received_data_length(webkit_download));
  133. download_format_elapsed(formatted, sizeof(formatted), _("%02i:%02i:%02i Downloading…"), total);
  134. gtk_image_set_from_icon_name(GTK_IMAGE(download->icon), "network-receive-symbolic");
  135. gtk_label_set_text(GTK_LABEL(download->status), formatted);
  136. gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(download->progress),
  137. webkit_download_get_estimated_progress(webkit_download));
  138. gtk_progress_bar_set_text(GTK_PROGRESS_BAR(download->progress), format_size);
  139. g_free(format_size);
  140. }
  141. GtkWidget *
  142. badwolf_downloads_tab_new()
  143. {
  144. return gtk_list_box_new();
  145. }
  146. void
  147. badwolf_downloads_tab_attach()
  148. {
  149. assert(window != NULL);
  150. GtkWidget *scrolled_window = gtk_scrolled_window_new();
  151. gtk_widget_set_name(scrolled_window, "browser__scrollwin_downloads");
  152. gtk_scrolled_window_set_child(scrolled_window, window->downloads_tab);
  153. gtk_notebook_insert_page(GTK_NOTEBOOK(window->notebook), scrolled_window, NULL, 0);
  154. gtk_notebook_set_tab_reorderable(GTK_NOTEBOOK(window->notebook), scrolled_window, TRUE);
  155. GtkWidget *tab_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
  156. gtk_widget_set_name(tab_box, "browser__tabbox");
  157. GtkWidget *icon = gtk_image_new_from_icon_name("emblem-downloads");
  158. gtk_widget_set_name(icon, "browser__tabbox__icon");
  159. GtkWidget *label = gtk_label_new(_("Badwolf Downloads"));
  160. gtk_widget_set_name(label, "browser__tabbox__label");
  161. #ifdef BADWOLF_TAB_BOX_WIDTH
  162. gtk_widget_set_size_request(label, BADWOLF_TAB_BOX_WIDTH, -1);
  163. #endif
  164. #ifdef BADWOLF_TAB_LABEL_CHARWIDTH
  165. gtk_label_set_width_chars(GTK_LABEL(label), BADWOLF_TAB_LABEL_CHARWIDTH);
  166. #endif
  167. gtk_widget_set_hexpand(tab_box, BADWOLF_TAB_HEXPAND);
  168. gtk_label_set_ellipsize(GTK_LABEL(label), BADWOLF_TAB_LABEL_ELLIPSIZE);
  169. gtk_label_set_single_line_mode(GTK_LABEL(label), TRUE);
  170. gtk_box_append(GTK_BOX(tab_box), icon);
  171. gtk_box_append(GTK_BOX(tab_box), label);
  172. gtk_widget_set_tooltip_text(tab_box, _("Badwolf Downloads"));
  173. gtk_notebook_set_tab_label(GTK_NOTEBOOK(window->notebook), scrolled_window, tab_box);
  174. gtk_notebook_set_menu_label_text(
  175. GTK_NOTEBOOK(window->notebook), scrolled_window, _("Badwolf Downloads"));
  176. }