Bug Summary

File:frontends/gtk/download.c
Warning:line 831, column 18
Potential leak of memory pointed to by 'destination'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name download.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-14/lib/clang/14.0.6 -I . -I include -I build/Linux-gtk2 -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NS_SVG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSSPRITE -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -I /usr/include/librsvg-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/libpng16 -I /usr/include/x86_64-linux-gnu -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/freetype2 -D WITH_RSVG -I /usr/include/gtk-2.0 -I /usr/lib/x86_64-linux-gnu/gtk-2.0/include -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/atk-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -D gtk -D nsgtk -D G_DISABLE_SINGLE_INCLUDES -D G_DISABLE_DEPRECATED -D GTK_DISABLE_SINGLE_INCLUDES -D GTK_MULTIHEAD_SAFE -D PANGO_DISABLE_DEPRECATED -D GTK_DISABLE_DEPRECATED -D _XOPEN_SOURCE=700 -D _POSIX_C_SOURCE=200809L -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D GTK_RESPATH="/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf/:./frontends/gtk/res/" -D WITH_GRESOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-14/lib/clang/14.0.6/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/12/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -ferror-limit 19 -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2025-03-06-104537-2872456-1 -x c frontends/gtk/download.c
1/*
2 * Copyright 2008 Michael Lester <element3260@gmail.com>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <math.h>
22
23#include <gtk1/gtk1.h>
24#include <glib/gstdio.h>
25
26#include "utils/log.h"
27#include "utils/utils.h"
28#include "utils/nsurl.h"
29#include "utils/messages.h"
30#include "utils/nsoption.h"
31#include "utils/string.h"
32#include "desktop/download.h"
33#include "netsurf/download.h"
34
35#include "gtk/warn.h"
36#include "gtk/scaffolding.h"
37#include "gtk/toolbar_items.h"
38#include "gtk/window.h"
39#include "gtk/compat.h"
40#include "gtk/resources.h"
41#include "gtk/download.h"
42
43#define UPDATE_RATE500 500 /* In milliseconds */
44
45struct download_context;
46
47enum {
48 NSGTK_DOWNLOAD_PROGRESS,
49 NSGTK_DOWNLOAD_INFO,
50 NSGTK_DOWNLOAD_REMAINING,
51 NSGTK_DOWNLOAD_SPEED,
52 NSGTK_DOWNLOAD_PULSE,
53 NSGTK_DOWNLOAD_STATUS,
54 NSGTK_DOWNLOAD,
55
56 NSGTK_DOWNLOAD_N_COLUMNS
57};
58
59typedef enum {
60 NSGTK_DOWNLOAD_NONE,
61 NSGTK_DOWNLOAD_WORKING,
62 NSGTK_DOWNLOAD_ERROR,
63 NSGTK_DOWNLOAD_COMPLETE,
64 NSGTK_DOWNLOAD_CANCELED
65} nsgtk_download_status;
66
67typedef enum {
68 NSGTK_DOWNLOAD_PAUSE = 1 << 0,
69 NSGTK_DOWNLOAD_RESUME = 1 << 1,
70 NSGTK_DOWNLOAD_CANCEL = 1 << 2,
71 NSGTK_DOWNLOAD_CLEAR = 1 << 3
72} nsgtk_download_actions;
73
74static const gchar* status_messages[] = {
75 NULL((void*)0),
76 "gtkWorking",
77 "gtkError",
78 "gtkComplete",
79 "gtkCanceled"
80};
81
82/**
83 * context for each download.
84 */
85struct gui_download_window {
86 struct download_context *ctx;
87 nsgtk_download_actions sensitivity;
88 nsgtk_download_status status;
89
90 GString *name;
91 GString *time_left;
92 unsigned long long int size_total;
93 unsigned long long int size_downloaded;
94 gint progress;
95 gfloat time_remaining;
96 gfloat start_time;
97 gfloat speed;
98
99 GtkTreeRowReference *row;
100 GIOChannel *write;
101 GError *error;
102};
103
104typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl,
105 void *user_data);
106
107/**
108 * context for a nsgtk download window.
109 */
110struct download_window_ctx {
111 GtkWindow *window;
112 GtkWindow *parent;
113
114 GtkProgressBar *progress;
115
116 GtkTreeView *tree;
117 GtkListStore *store;
118 GtkTreeSelection *selection;
119 GtkTreeIter iter;
120
121 GTimer *timer;
122 GList *list;
123 GtkButton *pause;
124 GtkButton *clear;
125 GtkButton *cancel;
126 GtkButton *resume;
127
128 gint num_active;
129};
130
131/**
132 * global instance of the download window
133 */
134static struct download_window_ctx dl_ctx;
135
136
137static GtkTreeView* nsgtk_download_tree_view_new(GtkBuilder *gladeFile)
138{
139 GtkTreeView *treeview;
140 GtkCellRenderer *renderer;
141
142 treeview = GTK_TREE_VIEW(gtk_builder_get_object(gladeFile,((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(gladeFile, "treeDownloads"))), ((
gtk_tree_view_get_type ()))))))
143 "treeDownloads"))((((GtkTreeView*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(gladeFile, "treeDownloads"))), ((
gtk_tree_view_get_type ()))))))
;
144
145 /* Progress column */
146 renderer = gtk_cell_renderer_progress_new();
147 gtk_tree_view_insert_column_with_attributes(treeview,
148 -1,
149 messages_get("gtkProgress"),
150 renderer,
151 "value",
152 NSGTK_DOWNLOAD_PROGRESS,
153 "pulse",
154 NSGTK_DOWNLOAD_PULSE,
155 "text",
156 NSGTK_DOWNLOAD_STATUS,
157 NULL((void*)0));
158
159 /* Information column */
160 renderer = gtk_cell_renderer_text_new();
161 g_object_set(G_OBJECT(renderer)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((renderer)), (((GType) ((20) << (2))))))))
,
162 "wrap-mode",
163 PANGO_WRAP_WORD_CHAR,
164 "wrap-width",
165 300,
166 NULL((void*)0));
167 gtk_tree_view_insert_column_with_attributes(treeview,
168 -1,
169 messages_get("gtkDetails"),
170 renderer,
171 "text",
172 NSGTK_DOWNLOAD_INFO,
173 NULL((void*)0));
174 gtk_tree_view_column_set_expand(
175 gtk_tree_view_get_column(treeview,
176 NSGTK_DOWNLOAD_INFO), TRUE(!(0)));
177
178 /* Time remaining column */
179 renderer = gtk_cell_renderer_text_new();
180 gtk_tree_view_insert_column_with_attributes(treeview,
181 -1,
182 messages_get("gtkRemaining"),
183 renderer,
184 "text",
185 NSGTK_DOWNLOAD_REMAINING,
186 NULL((void*)0));
187
188 /* Speed column */
189 renderer = gtk_cell_renderer_text_new();
190 gtk_tree_view_insert_column_with_attributes(treeview,
191 -1,
192 messages_get("gtkSpeed"),
193 renderer,
194 "text",
195 NSGTK_DOWNLOAD_SPEED,
196 NULL((void*)0));
197
198 return treeview;
199}
200
201
202static gint
203nsgtk_download_sort(GtkTreeModel *model,
204 GtkTreeIter *a,
205 GtkTreeIter *b,
206 gpointer userdata)
207{
208 struct gui_download_window *dl1, *dl2;
209
210 gtk_tree_model_get(model, a, NSGTK_DOWNLOAD, &dl1, -1);
211 gtk_tree_model_get(model, b, NSGTK_DOWNLOAD, &dl2, -1);
212
213 return dl1->status - dl2->status;
214}
215
216
217static void
218nsgtk_download_sensitivity_update_buttons(nsgtk_download_actions sensitivity)
219{
220 /* Glade seems to pack the buttons in an arbitrary order */
221 enum { PAUSE_BUTTON, CLEAR_BUTTON, CANCEL_BUTTON, RESUME_BUTTON };
222
223 gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.pause)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.pause)), ((gtk_widget_get_type ()))))))
,
224 sensitivity & NSGTK_DOWNLOAD_PAUSE);
225 gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.clear)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.clear)), ((gtk_widget_get_type ()))))))
,
226 sensitivity & NSGTK_DOWNLOAD_CLEAR);
227 gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.cancel)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.cancel)), ((gtk_widget_get_type ()))))))
,
228 sensitivity & NSGTK_DOWNLOAD_CANCEL);
229 gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.resume)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.resume)), ((gtk_widget_get_type ()))))))
,
230 sensitivity & NSGTK_DOWNLOAD_RESUME);
231}
232
233
234static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection)
235{
236 GtkTreeIter iter;
237 GList *rows;
238 gboolean selected;
239 GtkTreeModel *model;
240 nsgtk_download_actions sensitivity = 0;
241 struct gui_download_window *dl;
242
243 model = GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
;
244
245 selected = gtk_tree_selection_count_selected_rows(selection);
246 if (selected) {
247 rows = gtk_tree_selection_get_selected_rows(selection, &model);
248 while (rows != NULL((void*)0)) {
249 gtk_tree_model_get_iter(model,
250 &iter,
251 (GtkTreePath*)rows->data);
252 gtk_tree_model_get(model,
253 &iter,
254 NSGTK_DOWNLOAD,
255 &dl,
256 -1);
257 sensitivity |= dl->sensitivity;
258 rows = rows->next;
259 }
260 } else {
261 rows = dl_ctx.list;
262 while (rows != NULL((void*)0)) {
263 dl = rows->data;
264 sensitivity |= (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR);
265 rows = rows->next;
266 }
267 }
268
269 nsgtk_download_sensitivity_update_buttons(sensitivity);
270}
271
272
273/**
274 * Wrapper to GFunc-ify gtk_tree_path_free for g_list_foreach.
275 */
276static void
277nsgtk_download_gfunc__gtk_tree_path_free(gpointer data, gpointer user_data)
278{
279 gtk_tree_path_free(data);
280}
281
282
283/**
284 * Wrapper to GFunc-ify g_free for g_list_foreach.
285 */
286static void
287nsgtk_download_gfunc__g_free(gpointer data, gpointer user_data)
288{
289 g_free(data);
290}
291
292
293static void nsgtk_download_do(nsgtk_download_selection_action action)
294{
295 GList *rows, *dls = NULL((void*)0);
296 GtkTreeModel *model;
297
298 if (gtk_tree_selection_count_selected_rows(dl_ctx.selection)) {
299 model = GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
;
300
301 rows = gtk_tree_selection_get_selected_rows(dl_ctx.selection,
302 &model);
303 while (rows != NULL((void*)0)) {
304 struct gui_download_window *dl;
305
306 gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
,
307 &dl_ctx.iter,
308 (GtkTreePath*)rows->data);
309
310 gtk_tree_model_get(GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
,
311 &dl_ctx.iter,
312 NSGTK_DOWNLOAD,
313 &dl,
314 -1);
315
316 dls = g_list_prepend(dls, dl);
317
318 rows = rows->next;
319 }
320 g_list_foreach(rows,
321 nsgtk_download_gfunc__gtk_tree_path_free,
322 NULL((void*)0));
323 g_list_foreach(rows,
324 nsgtk_download_gfunc__g_free,
325 NULL((void*)0));
326 g_list_free(rows);
327 } else {
328 dls = g_list_copy(dl_ctx.list);
329 }
330
331 g_list_foreach(dls, (GFunc)action, NULL((void*)0));
332 g_list_free(dls);
333}
334
335
336static gchar* nsgtk_download_info_to_string(struct gui_download_window *dl)
337{
338 gchar *size_info;
339 gchar *r;
340
341 size_info = g_strdup_printf(messages_get("gtkSizeInfo"),
342 human_friendly_bytesize(dl->size_downloaded),
343 dl->size_total == 0 ?
344 messages_get("gtkUnknownSize") :
345 human_friendly_bytesize(dl->size_total));
346
347 if (dl->status != NSGTK_DOWNLOAD_ERROR) {
348 r = g_strdup_printf("%s\n%s", dl->name->str, size_info);
349 } else {
350 r = g_strdup_printf("%s\n%s", dl->name->str, dl->error->message);
351 }
352
353 g_free(size_info);
354
355 return r;
356}
357
358
359static gchar* nsgtk_download_time_to_string(gint seconds)
360{
361 gint hours, minutes;
362
363 if (seconds < 0) {
364 return g_strdup("-");
365 }
366
367 hours = seconds / 3600;
368 seconds -= hours * 3600;
369 minutes = seconds / 60;
370 seconds -= minutes * 60;
371
372 if (hours > 0) {
373 return g_strdup_printf("%u:%02u:%02u",
374 hours,
375 minutes,
376 seconds);
377 } else {
378 return g_strdup_printf("%u:%02u", minutes, seconds);
379 }
380}
381
382
383static void nsgtk_download_store_update_item(struct gui_download_window *dl)
384{
385 gchar *info = nsgtk_download_info_to_string(dl);
386 char *human = human_friendly_bytesize(dl->speed);
387 char speed[strlen(human) + SLEN("/s")(sizeof(("/s")) - 1) + 1];
388 sprintf(speed, "%s/s", human);
389 gchar *time = nsgtk_download_time_to_string(dl->time_remaining);
390 gboolean pulse = dl->status == NSGTK_DOWNLOAD_WORKING;
391
392 /* Updates iter (which is needed to set and get data) with the dl row */
393 gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
,
394 &dl_ctx.iter,
395 gtk_tree_row_reference_get_path(dl->row));
396
397 gtk_list_store_set(dl_ctx.store, &dl_ctx.iter,
398 NSGTK_DOWNLOAD_PULSE, pulse ? dl->progress : -1,
399 NSGTK_DOWNLOAD_PROGRESS, pulse ? 0 : dl->progress,
400 NSGTK_DOWNLOAD_INFO, info,
401 NSGTK_DOWNLOAD_SPEED, dl->speed == 0 ? "-" : speed,
402 NSGTK_DOWNLOAD_REMAINING, time,
403 NSGTK_DOWNLOAD, dl,
404 -1);
405
406 g_free(info);
407 g_free(time);
408}
409
410
411static gboolean nsgtk_download_update(gboolean force_update)
412{
413 /* Be sure we need to update */
414 if (!nsgtk_widget_get_visible(GTK_WIDGET(dl_ctx.window)((((GtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.window)), ((gtk_widget_get_type ()))))))
)) {
415 return TRUE(!(0));
416 }
417
418 GList *list;
419 gchar *text;
420 gboolean update, pulse_mode = FALSE(0);
421 unsigned long long int downloaded = 0;
422 unsigned long long int total = 0;
423 gint dls = 0;
424 gfloat percent, elapsed = g_timer_elapsed(dl_ctx.timer, NULL((void*)0));
425
426 dl_ctx.num_active = 0;
427
428 for (list = dl_ctx.list; list != NULL((void*)0); list = list->next) {
429 struct gui_download_window *dl = list->data;
430 update = force_update;
431
432 switch (dl->status) {
433 case NSGTK_DOWNLOAD_WORKING:
434 pulse_mode = TRUE(!(0));
435 fallthrough__attribute__((__fallthrough__));
436
437 case NSGTK_DOWNLOAD_NONE:
438 dl->speed = dl->size_downloaded /
439 (elapsed - dl->start_time);
440 if (dl->status == NSGTK_DOWNLOAD_NONE) {
441 dl->time_remaining = (dl->size_total -
442 dl->size_downloaded)/
443 dl->speed;
444 dl->progress = (double)dl->size_downloaded /
445 (double)dl->size_total * 100;
446 } else {
447 dl->progress++;
448 }
449
450 dl_ctx.num_active++;
451 update = TRUE(!(0));
452 fallthrough__attribute__((__fallthrough__));
453
454 case NSGTK_DOWNLOAD_COMPLETE:
455 downloaded += dl->size_downloaded;
456 total += dl->size_total;
457 dls++;
458 fallthrough__attribute__((__fallthrough__));
459
460 default:
461 ;//Do nothing
462
463 }
464 if (update) {
465 nsgtk_download_store_update_item(dl);
466 }
467 }
468
469 if (pulse_mode) {
470 text = g_strdup_printf(
471 messages_get(dl_ctx.num_active > 1 ?
472 "gtkProgressBarPulse" :
473 "gtkProgressBarPulseSingle"),
474 dl_ctx.num_active);
475 gtk_progress_bar_pulse(dl_ctx.progress);
476 gtk_progress_bar_set_text(dl_ctx.progress, text);
477 } else {
478 percent = total != 0 ? (double)downloaded / (double)total : 0;
479 text = g_strdup_printf(messages_get("gtkProgressBar"),
480 floor(percent * 100), dls);
481 gtk_progress_bar_set_fraction(dl_ctx.progress,
482 percent);
483 gtk_progress_bar_set_text(dl_ctx.progress, text);
484 }
485
486 g_free(text);
487
488 if (dl_ctx.num_active == 0) {
489 return FALSE(0); /* Returning FALSE here cancels the g_timeout */
490 } else {
491 return TRUE(!(0));
492 }
493}
494
495
496static void
497nsgtk_download_store_clear_item(struct gui_download_window *dl, void *user_data)
498{
499 if (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR) {
500 dl_ctx.list = g_list_remove(dl_ctx.list, dl);
501
502 gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
,
503 &dl_ctx.iter,
504 gtk_tree_row_reference_get_path(dl->row));
505 gtk_list_store_remove(dl_ctx.store,
506 &dl_ctx.iter);
507
508 download_context_destroy(dl->ctx);
509 g_string_free(dl->name, TRUE(!(0)));
510 g_string_free(dl->time_left, TRUE(!(0)));
511 g_free(dl);
512
513 nsgtk_download_sensitivity_evaluate(dl_ctx.selection);
514 nsgtk_download_update(FALSE(0));
515 }
516}
517
518
519static void
520nsgtk_download_tree_view_row_activated(GtkTreeView *tree,
521 GtkTreePath *path,
522 GtkTreeViewColumn *column,
523 gpointer data)
524{
525 GtkTreeModel *model;
526 GtkTreeIter iter;
527
528 model = gtk_tree_view_get_model(tree);
529
530 if (gtk_tree_model_get_iter(model, &iter, path)) {
531 /* TODO: This will be a context action (pause, start, clear) */
532 nsgtk_download_do(nsgtk_download_store_clear_item);
533 }
534}
535
536
537static void
538nsgtk_download_change_sensitivity(struct gui_download_window *dl,
539 nsgtk_download_actions sensitivity)
540{
541 dl->sensitivity = sensitivity;
542 nsgtk_download_sensitivity_evaluate(dl_ctx.selection);
543}
544
545
546static void
547nsgtk_download_change_status(struct gui_download_window *dl,
548 nsgtk_download_status status)
549{
550 dl->status = status;
551 if (status != NSGTK_DOWNLOAD_NONE) {
552 gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
,
553 &dl_ctx.iter,
554 gtk_tree_row_reference_get_path(dl->row));
555
556 gtk_list_store_set(dl_ctx.store, &dl_ctx.iter,
557 NSGTK_DOWNLOAD_STATUS,
558 messages_get(status_messages[status]), -1);
559 }
560}
561
562
563static void
564nsgtk_download_store_cancel_item(struct gui_download_window *dl,
565 void *user_data)
566{
567 if (dl->sensitivity & NSGTK_DOWNLOAD_CANCEL) {
568 dl->speed = 0;
569 dl->size_downloaded = 0;
570 dl->progress = 0;
571 dl->time_remaining = -1;
572 nsgtk_download_change_sensitivity(dl, NSGTK_DOWNLOAD_CLEAR);
573 nsgtk_download_change_status(dl, NSGTK_DOWNLOAD_CANCELED);
574
575 download_context_abort(dl->ctx);
576
577 g_unlink(download_context_get_filename(dl->ctx));
578
579 nsgtk_download_update(TRUE(!(0)));
580 }
581}
582
583
584static gboolean nsgtk_download_hide(GtkWidget *window)
585{
586 gtk_widget_hide(window);
587 return TRUE(!(0));
588}
589
590
591/**
592 * Prompt user for downloaded file name
593 *
594 * \param filename The original name of the file
595 * \param domain the domain the file is being downloaded from
596 * \param size The size of the file being downloaded
597 */
598static gchar*
599nsgtk_download_dialog_show(const gchar *filename,
600 const gchar *domain,
601 const gchar *size)
602{
603 enum { GTK_RESPONSE_DOWNLOAD, GTK_RESPONSE_SAVE_AS };
604 GtkWidget *dialog;
605 char *destination = NULL((void*)0);
606 gchar *message;
607 gchar *info;
608
609 message = g_strdup(messages_get("gtkStartDownload"));
610 info = g_strdup_printf(messages_get("gtkInfo"), filename, domain, size);
611
612 dialog = gtk_message_dialog_new_with_markup(
613 dl_ctx.parent,
614 GTK_DIALOG_DESTROY_WITH_PARENT,
615 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
616 "<span size=\"x-large\" weight=\"ultrabold\">%s</span>"
617 "\n\n<small>%s</small>",
618 message,
619 info);
620
621 gtk_dialog_add_buttons(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
,
622 NSGTK_STOCK_SAVE"gtk-save", GTK_RESPONSE_DOWNLOAD,
623 NSGTK_STOCK_CANCEL"gtk-cancel", GTK_RESPONSE_CANCEL,
624 NSGTK_STOCK_SAVE_AS"gtk-save-as", GTK_RESPONSE_SAVE_AS,
625 NULL((void*)0));
626
627 gint result = gtk_dialog_run(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
628 gtk_widget_destroy(dialog);
629 g_free(message);
630 g_free(info);
631
632 switch (result) {
10
Control jumps to 'case GTK_RESPONSE_DOWNLOAD:' at line 657
633 case GTK_RESPONSE_SAVE_AS: {
634 dialog = gtk_file_chooser_dialog_new(
635 messages_get("gtkSave"),
636 dl_ctx.parent,
637 GTK_FILE_CHOOSER_ACTION_SAVE,
638 NSGTK_STOCK_CANCEL"gtk-cancel", GTK_RESPONSE_CANCEL,
639 NSGTK_STOCK_SAVE"gtk-save", GTK_RESPONSE_ACCEPT,
640 NULL((void*)0));
641 gtk_file_chooser_set_current_name
642 (GTK_FILE_CHOOSER(dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
, filename);
643 gtk_file_chooser_set_current_folder
644 (GTK_FILE_CHOOSER(dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
,
645 nsoption_charp(downloads_directory)(nsoptions[NSOPTION_downloads_directory].value.s));
646 gtk_file_chooser_set_do_overwrite_confirmation
647 (GTK_FILE_CHOOSER(dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
,
648 nsoption_bool(request_overwrite)(nsoptions[NSOPTION_request_overwrite].value.b));
649
650 gint result = gtk_dialog_run(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
651 if (result == GTK_RESPONSE_ACCEPT)
652 destination = gtk_file_chooser_get_filename
653 (GTK_FILE_CHOOSER(dialog)((((GtkFileChooser*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_file_chooser_get_type ()))))))
);
654 gtk_widget_destroy(dialog);
655 break;
656 }
657 case GTK_RESPONSE_DOWNLOAD: {
658 destination = malloc(strlen(nsoption_charp(downloads_directory)(nsoptions[NSOPTION_downloads_directory].value.s))
11
Memory is allocated
659 + strlen(filename) + SLEN("/")(sizeof(("/")) - 1) + 1);
660 if (destination == NULL((void*)0)) {
12
Assuming 'destination' is not equal to NULL
13
Taking false branch
661 nsgtk_warning(messages_get("NoMemory"), 0);
662 break;
663 }
664 sprintf(destination, "%s/%s",
665 nsoption_charp(downloads_directory)(nsoptions[NSOPTION_downloads_directory].value.s), filename);
666 /* Test if file already exists and display overwrite
667 * confirmation if needed */
668 if (g_file_test(destination, G_FILE_TEST_EXISTS) &&
14
Assuming the condition is false
669 nsoption_bool(request_overwrite)(nsoptions[NSOPTION_request_overwrite].value.b)) {
670 GtkWidget *button;
671
672 message = g_strdup_printf(messages_get("gtkOverwrite"),
673 filename);
674 info = g_strdup_printf(messages_get("gtkOverwriteInfo"),
675 nsoption_charp(downloads_directory)(nsoptions[NSOPTION_downloads_directory].value.s));
676
677 dialog = gtk_message_dialog_new_with_markup(
678 dl_ctx.parent,
679 GTK_DIALOG_DESTROY_WITH_PARENT,
680 GTK_MESSAGE_QUESTION,
681 GTK_BUTTONS_CANCEL,
682 "<b>%s</b>",
683 message);
684 gtk_message_dialog_format_secondary_markup(
685 GTK_MESSAGE_DIALOG(dialog)((((GtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((dialog)), ((gtk_message_dialog_get_type ())
)))))
,
686 "%s",
687 info);
688
689 button = gtk_dialog_add_button(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
,
690 "_Replace",
691 GTK_RESPONSE_DOWNLOAD);
692 gtk_button_set_image(GTK_BUTTON(button)((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((button)), ((gtk_button_get_type ()))))))
,
693 nsgtk_image_new_from_stock(
694 NSGTK_STOCK_SAVE"gtk-save",
695 GTK_ICON_SIZE_BUTTON));
696
697 gint result = gtk_dialog_run(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
698 if (result == GTK_RESPONSE_CANCEL) {
699 free(destination);
700 destination = NULL((void*)0);
701 }
702
703 gtk_widget_destroy(dialog);
704 g_free(message);
705 g_free(info);
706 }
707 break;
15
Execution continues on line 710
708 }
709 }
710 return destination;
711}
712
713
714static gboolean nsgtk_download_handle_error(GError *error)
715{
716 GtkWidget*dialog;
717 gchar *message;
718
719 if (error != NULL((void*)0)) {
720 message = g_strdup_printf(messages_get("gtkFileError"),
721 error->message);
722
723 dialog = gtk_message_dialog_new_with_markup(
724 dl_ctx.parent,
725 GTK_DIALOG_MODAL,
726 GTK_MESSAGE_ERROR,
727 GTK_BUTTONS_OK,
728 "<big><b>%s</b></big>\n\n"
729 "<small>%s</small>",
730 messages_get("gtkFailed"),
731 message);
732
733 gtk_dialog_run(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
734 gtk_widget_destroy(dialog);
735 return TRUE(!(0));
736 }
737 return FALSE(0);
738}
739
740
741static void nsgtk_download_store_create_item(struct gui_download_window *dl)
742{
743 nsgtk_download_store_update_item(dl);
744 /* The iter has already been updated to this row */
745 gtk_list_store_set(dl_ctx.store,
746 &dl_ctx.iter,
747 NSGTK_DOWNLOAD,
748 dl,
749 -1);
750}
751
752
753/**
754 * Wrapper to GSourceFunc-ify nsgtk_download_update.
755 */
756static gboolean
757nsgtk_download_gsourcefunc__nsgtk_download_update(gpointer user_data)
758{
759 return nsgtk_download_update(FALSE(0));
760}
761
762
763/**
764 * core callback on creating a new download
765 */
766static struct gui_download_window *
767gui_download_window_create(download_context *ctx, struct gui_window *gui)
768{
769 nsurl *url;
770 unsigned long long int total_size;
771 gchar *domain;
772 gchar *destination;
773 gboolean unknown_size;
774 struct gui_download_window *download;
775 const char *size;
776
777 url = download_context_get_url(ctx);
778 total_size = download_context_get_total_length(ctx);
779 unknown_size = total_size == 0;
1
Assuming 'total_size' is equal to 0
780 size = (total_size
1.1
'total_size' is equal to 0
== 0 ?
2
'?' condition is true
781 messages_get("gtkUnknownSize") :
782 human_friendly_bytesize(total_size));
783
784 dl_ctx.parent = nsgtk_scaffolding_window(nsgtk_get_scaffold(gui));
785
786 download = malloc(sizeof *download);
787 if (download == NULL((void*)0)) {
3
Assuming 'download' is not equal to NULL
4
Taking false branch
788 return NULL((void*)0);
789 }
790
791 /* set the domain to the host component of the url if it exists */
792 if (nsurl_has_component(url, NSURL_HOST)) {
5
Assuming the condition is false
6
Taking false branch
793 domain = g_strdup(lwc_string_data(nsurl_get_component(url, NSURL_HOST))({((nsurl_get_component(url, NSURL_HOST) != ((void*)0)) ? (void
) (0) : __assert_fail ("nsurl_get_component(url, NSURL_HOST) != NULL"
, "frontends/gtk/download.c", 793, __extension__ __PRETTY_FUNCTION__
)); (const char *)((nsurl_get_component(url, NSURL_HOST))+1);
})
);
794 } else {
795 domain = g_strdup(messages_get("gtkUnknownHost"));
796 }
797 if (domain == NULL((void*)0)) {
7
Assuming 'domain' is not equal to NULL
8
Taking false branch
798 free(download);
799 return NULL((void*)0);
800 }
801
802 /* show the dialog */
803 destination = nsgtk_download_dialog_show(
9
Calling 'nsgtk_download_dialog_show'
16
Returned allocated memory
804 download_context_get_filename(ctx), domain, size);
805 if (destination
16.1
'destination' is not equal to NULL
== NULL((void*)0)) {
17
Taking false branch
806 g_free(domain);
807 free(download);
808 return NULL((void*)0);
809 }
810
811 /* Add the new row and store the reference to it (which keeps track of
812 * the tree changes) */
813 gtk_list_store_prepend(dl_ctx.store, &dl_ctx.iter);
814 download->row = gtk_tree_row_reference_new(
815 GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
,
816 gtk_tree_model_get_path(
817 GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
,
818 &dl_ctx.iter));
819
820 download->ctx = ctx;
821 download->name = g_string_new(download_context_get_filename(ctx));
822 download->time_left = g_string_new("");
823 download->size_total = total_size;
824 download->size_downloaded = 0;
825 download->speed = 0;
826 download->start_time = g_timer_elapsed(dl_ctx.timer, NULL((void*)0));
827 download->time_remaining = -1;
828 download->status = NSGTK_DOWNLOAD_NONE;
829 download->progress = 0;
830 download->error = NULL((void*)0);
831 download->write = g_io_channel_new_file(destination,
18
Potential leak of memory pointed to by 'destination'
832 "w",
833 &download->error);
834
835 if (nsgtk_download_handle_error(download->error)) {
836 g_string_free(download->name, TRUE(!(0)));
837 g_string_free(download->time_left, TRUE(!(0)));
838 free(download);
839 return NULL((void*)0);
840 }
841 g_io_channel_set_encoding(download->write, NULL((void*)0), &download->error);
842
843 nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL);
844
845 nsgtk_download_store_create_item(download);
846 nsgtk_download_show(dl_ctx.parent);
847
848 if (unknown_size) {
849 nsgtk_download_change_status(download, NSGTK_DOWNLOAD_WORKING);
850 }
851
852 if (dl_ctx.num_active == 0) {
853 g_timeout_add(
854 UPDATE_RATE500,
855 nsgtk_download_gsourcefunc__nsgtk_download_update,
856 NULL((void*)0));
857 }
858
859 dl_ctx.list = g_list_prepend(dl_ctx.list, download);
860
861 return download;
862}
863
864
865/**
866 * core callback on receipt of data
867 */
868static nserror
869gui_download_window_data(struct gui_download_window *dw,
870 const char *data,
871 unsigned int size)
872{
873 GIOStatus status;
874 status = g_io_channel_write_chars(dw->write, data, size, NULL((void*)0), &dw->error);
875 if (status != G_IO_STATUS_NORMAL || dw->error != NULL((void*)0)) {
876 dw->speed = 0;
877 dw->time_remaining = -1;
878
879 nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR);
880 nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_ERROR);
881
882 nsgtk_download_update(TRUE(!(0)));
883
884 gtk_window_present(dl_ctx.window);
885
886 return NSERROR_SAVE_FAILED;
887 }
888 dw->size_downloaded += size;
889
890 return NSERROR_OK;
891}
892
893
894/**
895 * core callback on error
896 */
897static void
898gui_download_window_error(struct gui_download_window *dw, const char *error_msg)
899{
900}
901
902
903/**
904 * core callback when core download is complete
905 */
906static void gui_download_window_done(struct gui_download_window *dw)
907{
908 g_io_channel_shutdown(dw->write, TRUE(!(0)), &dw->error);
909 g_io_channel_unref(dw->write);
910
911 dw->speed = 0;
912 dw->time_remaining = -1;
913 dw->progress = 100;
914 dw->size_total = dw->size_downloaded;
915 nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR);
916 nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_COMPLETE);
917
918 if (nsoption_bool(downloads_clear)(nsoptions[NSOPTION_downloads_clear].value.b)) {
919 nsgtk_download_store_clear_item(dw, NULL((void*)0));
920 } else {
921 nsgtk_download_update(TRUE(!(0)));
922 }
923}
924
925
926static struct gui_download_table download_table = {
927 .create = gui_download_window_create,
928 .data = gui_download_window_data,
929 .error = gui_download_window_error,
930 .done = gui_download_window_done,
931};
932
933struct gui_download_table *nsgtk_download_table = &download_table;
934
935
936/* exported interface documented in gtk/download.h */
937nserror nsgtk_download_init(void)
938{
939 GtkBuilder* builder;
940 nserror res;
941
942 res = nsgtk_builder_new_from_resname("downloads", &builder);
943 if (res != NSERROR_OK) {
944 NSLOG(netsurf, INFO, "Download UI builder init failed")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "frontends/gtk/download.c", sizeof("frontends/gtk/download.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 944
, }; nslog__log(&_nslog_ctx, "Download UI builder init failed"
); } } while(0)
;
945 return res;
946 }
947
948 gtk_builder_connect_signals(builder, NULL((void*)0));
949
950 dl_ctx.pause = GTK_BUTTON(gtk_builder_get_object(builder,((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonPause"))), ((gtk_button_get_type
()))))))
951 "buttonPause"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonPause"))), ((gtk_button_get_type
()))))))
;
952 dl_ctx.clear = GTK_BUTTON(gtk_builder_get_object(builder,((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonClear"))), ((gtk_button_get_type
()))))))
953 "buttonClear"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonClear"))), ((gtk_button_get_type
()))))))
;
954 dl_ctx.cancel = GTK_BUTTON(gtk_builder_get_object(builder,((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonCancel"))), ((gtk_button_get_type
()))))))
955 "buttonCancel"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonCancel"))), ((gtk_button_get_type
()))))))
;
956 dl_ctx.resume = GTK_BUTTON(gtk_builder_get_object(builder,((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonPlay"))), ((gtk_button_get_type
()))))))
957 "buttonPlay"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "buttonPlay"))), ((gtk_button_get_type
()))))))
;
958
959 dl_ctx.progress = GTK_PROGRESS_BAR(gtk_builder_get_object(builder,((((GtkProgressBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "progressBar"))), ((gtk_progress_bar_get_type
()))))))
960 "progressBar"))((((GtkProgressBar*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "progressBar"))), ((gtk_progress_bar_get_type
()))))))
;
961 dl_ctx.window = GTK_WINDOW(gtk_builder_get_object(builder,((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "wndDownloads"))), ((gtk_window_get_type
()))))))
962 "wndDownloads"))((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((gtk_builder_get_object(builder, "wndDownloads"))), ((gtk_window_get_type
()))))))
;
963 dl_ctx.parent = NULL((void*)0);
964
965 gtk_window_set_transient_for(GTK_WINDOW(dl_ctx.window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.window)), ((gtk_window_get_type ()))))))
,
966 dl_ctx.parent);
967 gtk_window_set_destroy_with_parent(GTK_WINDOW(dl_ctx.window)((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.window)), ((gtk_window_get_type ()))))))
,
968 FALSE(0));
969
970 dl_ctx.timer = g_timer_new();
971
972 dl_ctx.tree = nsgtk_download_tree_view_new(builder);
973
974 dl_ctx.store = gtk_list_store_new(NSGTK_DOWNLOAD_N_COLUMNS,
975 G_TYPE_INT((GType) ((6) << (2))), /* % complete */
976 G_TYPE_STRING((GType) ((16) << (2))), /* Description */
977 G_TYPE_STRING((GType) ((16) << (2))), /* Time remaining */
978 G_TYPE_STRING((GType) ((16) << (2))), /* Speed */
979 G_TYPE_INT((GType) ((6) << (2))), /* Pulse */
980 G_TYPE_STRING((GType) ((16) << (2))), /* Status */
981 G_TYPE_POINTER((GType) ((17) << (2))) /* Download structure */
982 );
983
984
985 gtk_tree_view_set_model(dl_ctx.tree, GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_model_get_type ()))))))
);
986
987 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(dl_ctx.store)((((GtkTreeSortable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_sortable_get_type ()))))))
,
988 NSGTK_DOWNLOAD_STATUS,
989 (GtkTreeIterCompareFunc)nsgtk_download_sort, NULL((void*)0), NULL((void*)0));
990 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dl_ctx.store)((((GtkTreeSortable*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dl_ctx.store)), ((gtk_tree_sortable_get_type ()))))))
,
991 NSGTK_DOWNLOAD_STATUS,
992 GTK_SORT_ASCENDING);
993
994 g_object_unref(dl_ctx.store);
995
996 dl_ctx.selection = gtk_tree_view_get_selection(dl_ctx.tree);
997 gtk_tree_selection_set_mode(dl_ctx.selection, GTK_SELECTION_MULTIPLE);
998
999 g_signal_connect(G_OBJECT(dl_ctx.selection),g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.selection)), (((GType) ((20) <<
(2))))))))), ("changed"), (((GCallback) (nsgtk_download_sensitivity_evaluate
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
1000 "changed",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.selection)), (((GType) ((20) <<
(2))))))))), ("changed"), (((GCallback) (nsgtk_download_sensitivity_evaluate
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
1001 G_CALLBACK(nsgtk_download_sensitivity_evaluate),g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.selection)), (((GType) ((20) <<
(2))))))))), ("changed"), (((GCallback) (nsgtk_download_sensitivity_evaluate
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
1002 NULL)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.selection)), (((GType) ((20) <<
(2))))))))), ("changed"), (((GCallback) (nsgtk_download_sensitivity_evaluate
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
1003
1004 g_signal_connect(dl_ctx.tree,g_signal_connect_data ((dl_ctx.tree), ("row-activated"), (((GCallback
) (nsgtk_download_tree_view_row_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1005 "row-activated",g_signal_connect_data ((dl_ctx.tree), ("row-activated"), (((GCallback
) (nsgtk_download_tree_view_row_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1006 G_CALLBACK(nsgtk_download_tree_view_row_activated),g_signal_connect_data ((dl_ctx.tree), ("row-activated"), (((GCallback
) (nsgtk_download_tree_view_row_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
1007 NULL)g_signal_connect_data ((dl_ctx.tree), ("row-activated"), (((GCallback
) (nsgtk_download_tree_view_row_activated))), (((void*)0)), (
(void*)0), (GConnectFlags) 0)
;
1008
1009 g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonClear"),g_signal_connect_data ((gtk_builder_get_object(builder, "buttonClear"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_clear_item
), ((void*)0), G_CONNECT_SWAPPED)
1010 "clicked",g_signal_connect_data ((gtk_builder_get_object(builder, "buttonClear"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_clear_item
), ((void*)0), G_CONNECT_SWAPPED)
1011 G_CALLBACK(nsgtk_download_do),g_signal_connect_data ((gtk_builder_get_object(builder, "buttonClear"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_clear_item
), ((void*)0), G_CONNECT_SWAPPED)
1012 nsgtk_download_store_clear_item)g_signal_connect_data ((gtk_builder_get_object(builder, "buttonClear"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_clear_item
), ((void*)0), G_CONNECT_SWAPPED)
;
1013
1014 g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonCancel"),g_signal_connect_data ((gtk_builder_get_object(builder, "buttonCancel"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_cancel_item
), ((void*)0), G_CONNECT_SWAPPED)
1015 "clicked",g_signal_connect_data ((gtk_builder_get_object(builder, "buttonCancel"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_cancel_item
), ((void*)0), G_CONNECT_SWAPPED)
1016 G_CALLBACK(nsgtk_download_do),g_signal_connect_data ((gtk_builder_get_object(builder, "buttonCancel"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_cancel_item
), ((void*)0), G_CONNECT_SWAPPED)
1017 nsgtk_download_store_cancel_item)g_signal_connect_data ((gtk_builder_get_object(builder, "buttonCancel"
)), ("clicked"), (((GCallback) (nsgtk_download_do))), (nsgtk_download_store_cancel_item
), ((void*)0), G_CONNECT_SWAPPED)
;
1018
1019 g_signal_connect(G_OBJECT(dl_ctx.window),g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.window)), (((GType) ((20) <<
(2))))))))), ("delete-event"), (((GCallback) (nsgtk_download_hide
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
1020 "delete-event",g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.window)), (((GType) ((20) <<
(2))))))))), ("delete-event"), (((GCallback) (nsgtk_download_hide
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
1021 G_CALLBACK(nsgtk_download_hide),g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.window)), (((GType) ((20) <<
(2))))))))), ("delete-event"), (((GCallback) (nsgtk_download_hide
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
1022 NULL)g_signal_connect_data ((((((GObject*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dl_ctx.window)), (((GType) ((20) <<
(2))))))))), ("delete-event"), (((GCallback) (nsgtk_download_hide
))), (((void*)0)), ((void*)0), (GConnectFlags) 0)
;
1023
1024 return NSERROR_OK;
1025}
1026
1027
1028/* exported interface documented in gtk/download.h */
1029void nsgtk_download_destroy(void)
1030{
1031 nsgtk_download_do(nsgtk_download_store_cancel_item);
1032}
1033
1034
1035/* exported interface documented in gtk/download.h */
1036bool_Bool nsgtk_check_for_downloads(GtkWindow *parent)
1037{
1038 GtkWidget *dialog;
1039 gint response;
1040
1041 if (dl_ctx.num_active == 0) {
1042 return false0;
1043 }
1044
1045 dialog = gtk_message_dialog_new_with_markup(
1046 parent,
1047 GTK_DIALOG_MODAL,
1048 GTK_MESSAGE_WARNING,
1049 GTK_BUTTONS_NONE,
1050 "<big><b>%s</b></big>\n\n"
1051 "<small>%s</small>",
1052 messages_get("gtkQuit"),
1053 messages_get("gtkDownloadsRunning"));
1054
1055 gtk_dialog_add_buttons(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
,
1056 "gtk-cancel", GTK_RESPONSE_CANCEL,
1057 "gtk-quit", GTK_RESPONSE_CLOSE,
1058 NULL((void*)0));
1059
1060 response = gtk_dialog_run(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((gtk_dialog_get_type ()))))))
);
1061 gtk_widget_destroy(dialog);
1062
1063 if (response == GTK_RESPONSE_CANCEL) {
1064 return true1;
1065 }
1066
1067 return false0;
1068}
1069
1070
1071/* exported interface documented in gtk/download.h */
1072void nsgtk_download_show(GtkWindow *parent)
1073{
1074 gtk_window_set_transient_for(dl_ctx.window, dl_ctx.parent);
1075 gtk_window_present(dl_ctx.window);
1076}