File: | frontends/gtk/download.c |
Warning: | line 829, column 18 Potential leak of memory pointed to by 'destination' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
45 | struct download_context; | |||
46 | ||||
47 | enum { | |||
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 | ||||
59 | typedef 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 | ||||
67 | typedef 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 | ||||
74 | static 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 | */ | |||
85 | struct 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 | ||||
104 | typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl, | |||
105 | void *user_data); | |||
106 | ||||
107 | /** | |||
108 | * context for a nsgtk download window. | |||
109 | */ | |||
110 | struct 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 | */ | |||
134 | static struct download_window_ctx dl_ctx; | |||
135 | ||||
136 | ||||
137 | static 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 | ||||
202 | static gint | |||
203 | nsgtk_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 | ||||
217 | static void | |||
218 | nsgtk_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 | ||||
234 | static 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 | */ | |||
276 | static void | |||
277 | nsgtk_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 | */ | |||
286 | static void | |||
287 | nsgtk_download_gfunc__g_free(gpointer data, gpointer user_data) | |||
288 | { | |||
289 | g_free(data); | |||
290 | } | |||
291 | ||||
292 | ||||
293 | static 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 | ||||
336 | static 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 | ||||
359 | static 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 | ||||
383 | static 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 | ||||
411 | static 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 | ||||
496 | static void | |||
497 | nsgtk_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 | ||||
519 | static void | |||
520 | nsgtk_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 | ||||
537 | static void | |||
538 | nsgtk_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 | ||||
546 | static void | |||
547 | nsgtk_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 | ||||
563 | static void | |||
564 | nsgtk_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 | ||||
584 | static 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 | */ | |||
598 | static gchar* | |||
599 | nsgtk_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) { | |||
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)) | |||
659 | + strlen(filename) + SLEN("/")(sizeof(("/")) - 1) + 1); | |||
660 | if (destination == NULL((void*)0)) { | |||
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) && | |||
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 | destination = NULL((void*)0); | |||
700 | ||||
701 | gtk_widget_destroy(dialog); | |||
702 | g_free(message); | |||
703 | g_free(info); | |||
704 | } | |||
705 | break; | |||
706 | } | |||
707 | } | |||
708 | return destination; | |||
709 | } | |||
710 | ||||
711 | ||||
712 | static gboolean nsgtk_download_handle_error(GError *error) | |||
713 | { | |||
714 | GtkWidget*dialog; | |||
715 | gchar *message; | |||
716 | ||||
717 | if (error != NULL((void*)0)) { | |||
718 | message = g_strdup_printf(messages_get("gtkFileError"), | |||
719 | error->message); | |||
720 | ||||
721 | dialog = gtk_message_dialog_new_with_markup( | |||
722 | dl_ctx.parent, | |||
723 | GTK_DIALOG_MODAL, | |||
724 | GTK_MESSAGE_ERROR, | |||
725 | GTK_BUTTONS_OK, | |||
726 | "<big><b>%s</b></big>\n\n" | |||
727 | "<small>%s</small>", | |||
728 | messages_get("gtkFailed"), | |||
729 | message); | |||
730 | ||||
731 | gtk_dialog_run(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((gtk_dialog_get_type ()))))))); | |||
732 | gtk_widget_destroy(dialog); | |||
733 | return TRUE(!(0)); | |||
734 | } | |||
735 | return FALSE(0); | |||
736 | } | |||
737 | ||||
738 | ||||
739 | static void nsgtk_download_store_create_item(struct gui_download_window *dl) | |||
740 | { | |||
741 | nsgtk_download_store_update_item(dl); | |||
742 | /* The iter has already been updated to this row */ | |||
743 | gtk_list_store_set(dl_ctx.store, | |||
744 | &dl_ctx.iter, | |||
745 | NSGTK_DOWNLOAD, | |||
746 | dl, | |||
747 | -1); | |||
748 | } | |||
749 | ||||
750 | ||||
751 | /** | |||
752 | * Wrapper to GSourceFunc-ify nsgtk_download_update. | |||
753 | */ | |||
754 | static gboolean | |||
755 | nsgtk_download_gsourcefunc__nsgtk_download_update(gpointer user_data) | |||
756 | { | |||
757 | return nsgtk_download_update(FALSE(0)); | |||
758 | } | |||
759 | ||||
760 | ||||
761 | /** | |||
762 | * core callback on creating a new download | |||
763 | */ | |||
764 | static struct gui_download_window * | |||
765 | gui_download_window_create(download_context *ctx, struct gui_window *gui) | |||
766 | { | |||
767 | nsurl *url; | |||
768 | unsigned long long int total_size; | |||
769 | gchar *domain; | |||
770 | gchar *destination; | |||
771 | gboolean unknown_size; | |||
772 | struct gui_download_window *download; | |||
773 | const char *size; | |||
774 | ||||
775 | url = download_context_get_url(ctx); | |||
776 | total_size = download_context_get_total_length(ctx); | |||
777 | unknown_size = total_size == 0; | |||
| ||||
778 | size = (total_size
| |||
779 | messages_get("gtkUnknownSize") : | |||
780 | human_friendly_bytesize(total_size)); | |||
781 | ||||
782 | dl_ctx.parent = nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); | |||
783 | ||||
784 | download = malloc(sizeof *download); | |||
785 | if (download == NULL((void*)0)) { | |||
786 | return NULL((void*)0); | |||
787 | } | |||
788 | ||||
789 | /* set the domain to the host component of the url if it exists */ | |||
790 | if (nsurl_has_component(url, NSURL_HOST)) { | |||
791 | 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", 791, __extension__ __PRETTY_FUNCTION__ )); (const char *)((nsurl_get_component(url, NSURL_HOST))+1); })); | |||
792 | } else { | |||
793 | domain = g_strdup(messages_get("gtkUnknownHost")); | |||
794 | } | |||
795 | if (domain == NULL((void*)0)) { | |||
796 | free(download); | |||
797 | return NULL((void*)0); | |||
798 | } | |||
799 | ||||
800 | /* show the dialog */ | |||
801 | destination = nsgtk_download_dialog_show( | |||
802 | download_context_get_filename(ctx), domain, size); | |||
803 | if (destination
| |||
804 | g_free(domain); | |||
805 | free(download); | |||
806 | return NULL((void*)0); | |||
807 | } | |||
808 | ||||
809 | /* Add the new row and store the reference to it (which keeps track of | |||
810 | * the tree changes) */ | |||
811 | gtk_list_store_prepend(dl_ctx.store, &dl_ctx.iter); | |||
812 | download->row = gtk_tree_row_reference_new( | |||
813 | GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dl_ctx.store)), ((gtk_tree_model_get_type ())))))), | |||
814 | gtk_tree_model_get_path( | |||
815 | GTK_TREE_MODEL(dl_ctx.store)((((GtkTreeModel*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dl_ctx.store)), ((gtk_tree_model_get_type ())))))), | |||
816 | &dl_ctx.iter)); | |||
817 | ||||
818 | download->ctx = ctx; | |||
819 | download->name = g_string_new(download_context_get_filename(ctx)); | |||
820 | download->time_left = g_string_new(""); | |||
821 | download->size_total = total_size; | |||
822 | download->size_downloaded = 0; | |||
823 | download->speed = 0; | |||
824 | download->start_time = g_timer_elapsed(dl_ctx.timer, NULL((void*)0)); | |||
825 | download->time_remaining = -1; | |||
826 | download->status = NSGTK_DOWNLOAD_NONE; | |||
827 | download->progress = 0; | |||
828 | download->error = NULL((void*)0); | |||
829 | download->write = g_io_channel_new_file(destination, | |||
| ||||
830 | "w", | |||
831 | &download->error); | |||
832 | ||||
833 | if (nsgtk_download_handle_error(download->error)) { | |||
834 | g_string_free(download->name, TRUE(!(0))); | |||
835 | g_string_free(download->time_left, TRUE(!(0))); | |||
836 | free(download); | |||
837 | return NULL((void*)0); | |||
838 | } | |||
839 | g_io_channel_set_encoding(download->write, NULL((void*)0), &download->error); | |||
840 | ||||
841 | nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL); | |||
842 | ||||
843 | nsgtk_download_store_create_item(download); | |||
844 | nsgtk_download_show(dl_ctx.parent); | |||
845 | ||||
846 | if (unknown_size) { | |||
847 | nsgtk_download_change_status(download, NSGTK_DOWNLOAD_WORKING); | |||
848 | } | |||
849 | ||||
850 | if (dl_ctx.num_active == 0) { | |||
851 | g_timeout_add( | |||
852 | UPDATE_RATE500, | |||
853 | nsgtk_download_gsourcefunc__nsgtk_download_update, | |||
854 | NULL((void*)0)); | |||
855 | } | |||
856 | ||||
857 | dl_ctx.list = g_list_prepend(dl_ctx.list, download); | |||
858 | ||||
859 | return download; | |||
860 | } | |||
861 | ||||
862 | ||||
863 | /** | |||
864 | * core callback on receipt of data | |||
865 | */ | |||
866 | static nserror | |||
867 | gui_download_window_data(struct gui_download_window *dw, | |||
868 | const char *data, | |||
869 | unsigned int size) | |||
870 | { | |||
871 | g_io_channel_write_chars(dw->write, data, size, NULL((void*)0), &dw->error); | |||
872 | if (dw->error != NULL((void*)0)) { | |||
873 | dw->speed = 0; | |||
874 | dw->time_remaining = -1; | |||
875 | ||||
876 | nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); | |||
877 | nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_ERROR); | |||
878 | ||||
879 | nsgtk_download_update(TRUE(!(0))); | |||
880 | ||||
881 | gtk_window_present(dl_ctx.window); | |||
882 | ||||
883 | return NSERROR_SAVE_FAILED; | |||
884 | } | |||
885 | dw->size_downloaded += size; | |||
886 | ||||
887 | return NSERROR_OK; | |||
888 | } | |||
889 | ||||
890 | ||||
891 | /** | |||
892 | * core callback on error | |||
893 | */ | |||
894 | static void | |||
895 | gui_download_window_error(struct gui_download_window *dw, const char *error_msg) | |||
896 | { | |||
897 | } | |||
898 | ||||
899 | ||||
900 | /** | |||
901 | * core callback when core download is complete | |||
902 | */ | |||
903 | static void gui_download_window_done(struct gui_download_window *dw) | |||
904 | { | |||
905 | g_io_channel_shutdown(dw->write, TRUE(!(0)), &dw->error); | |||
906 | g_io_channel_unref(dw->write); | |||
907 | ||||
908 | dw->speed = 0; | |||
909 | dw->time_remaining = -1; | |||
910 | dw->progress = 100; | |||
911 | dw->size_total = dw->size_downloaded; | |||
912 | nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); | |||
913 | nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_COMPLETE); | |||
914 | ||||
915 | if (nsoption_bool(downloads_clear)(nsoptions[NSOPTION_downloads_clear].value.b)) { | |||
916 | nsgtk_download_store_clear_item(dw, NULL((void*)0)); | |||
917 | } else { | |||
918 | nsgtk_download_update(TRUE(!(0))); | |||
919 | } | |||
920 | } | |||
921 | ||||
922 | ||||
923 | static struct gui_download_table download_table = { | |||
924 | .create = gui_download_window_create, | |||
925 | .data = gui_download_window_data, | |||
926 | .error = gui_download_window_error, | |||
927 | .done = gui_download_window_done, | |||
928 | }; | |||
929 | ||||
930 | struct gui_download_table *nsgtk_download_table = &download_table; | |||
931 | ||||
932 | ||||
933 | /* exported interface documented in gtk/download.h */ | |||
934 | nserror nsgtk_download_init(void) | |||
935 | { | |||
936 | GtkBuilder* builder; | |||
937 | nserror res; | |||
938 | ||||
939 | res = nsgtk_builder_new_from_resname("downloads", &builder); | |||
940 | if (res != NSERROR_OK) { | |||
941 | 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, 941 , }; nslog__log(&_nslog_ctx, "Download UI builder init failed" ); } } while(0); | |||
942 | return res; | |||
943 | } | |||
944 | ||||
945 | gtk_builder_connect_signals(builder, NULL((void*)0)); | |||
946 | ||||
947 | 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 ())))))) | |||
948 | "buttonPause"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((gtk_builder_get_object(builder, "buttonPause"))), ((gtk_button_get_type ())))))); | |||
949 | 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 ())))))) | |||
950 | "buttonClear"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((gtk_builder_get_object(builder, "buttonClear"))), ((gtk_button_get_type ())))))); | |||
951 | 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 ())))))) | |||
952 | "buttonCancel"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((gtk_builder_get_object(builder, "buttonCancel"))), ((gtk_button_get_type ())))))); | |||
953 | 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 ())))))) | |||
954 | "buttonPlay"))((((GtkButton*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((gtk_builder_get_object(builder, "buttonPlay"))), ((gtk_button_get_type ())))))); | |||
955 | ||||
956 | 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 ())))))) | |||
957 | "progressBar"))((((GtkProgressBar*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((gtk_builder_get_object(builder, "progressBar"))), ((gtk_progress_bar_get_type ())))))); | |||
958 | 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 ())))))) | |||
959 | "wndDownloads"))((((GtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((gtk_builder_get_object(builder, "wndDownloads"))), ((gtk_window_get_type ())))))); | |||
960 | dl_ctx.parent = NULL((void*)0); | |||
961 | ||||
962 | 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 ())))))), | |||
963 | dl_ctx.parent); | |||
964 | 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 ())))))), | |||
965 | FALSE(0)); | |||
966 | ||||
967 | dl_ctx.timer = g_timer_new(); | |||
968 | ||||
969 | dl_ctx.tree = nsgtk_download_tree_view_new(builder); | |||
970 | ||||
971 | dl_ctx.store = gtk_list_store_new(NSGTK_DOWNLOAD_N_COLUMNS, | |||
972 | G_TYPE_INT((GType) ((6) << (2))), /* % complete */ | |||
973 | G_TYPE_STRING((GType) ((16) << (2))), /* Description */ | |||
974 | G_TYPE_STRING((GType) ((16) << (2))), /* Time remaining */ | |||
975 | G_TYPE_STRING((GType) ((16) << (2))), /* Speed */ | |||
976 | G_TYPE_INT((GType) ((6) << (2))), /* Pulse */ | |||
977 | G_TYPE_STRING((GType) ((16) << (2))), /* Status */ | |||
978 | G_TYPE_POINTER((GType) ((17) << (2))) /* Download structure */ | |||
979 | ); | |||
980 | ||||
981 | ||||
982 | 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 ()))))))); | |||
983 | ||||
984 | 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 ())))))), | |||
985 | NSGTK_DOWNLOAD_STATUS, | |||
986 | (GtkTreeIterCompareFunc)nsgtk_download_sort, NULL((void*)0), NULL((void*)0)); | |||
987 | 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 ())))))), | |||
988 | NSGTK_DOWNLOAD_STATUS, | |||
989 | GTK_SORT_ASCENDING); | |||
990 | ||||
991 | g_object_unref(dl_ctx.store); | |||
992 | ||||
993 | dl_ctx.selection = gtk_tree_view_get_selection(dl_ctx.tree); | |||
994 | gtk_tree_selection_set_mode(dl_ctx.selection, GTK_SELECTION_MULTIPLE); | |||
995 | ||||
996 | 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) | |||
997 | "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) | |||
998 | 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) | |||
999 | 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); | |||
1000 | ||||
1001 | 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) | |||
1002 | "row-activated",g_signal_connect_data ((dl_ctx.tree), ("row-activated"), (((GCallback ) (nsgtk_download_tree_view_row_activated))), (((void*)0)), ( (void*)0), (GConnectFlags) 0) | |||
1003 | 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) | |||
1004 | NULL)g_signal_connect_data ((dl_ctx.tree), ("row-activated"), (((GCallback ) (nsgtk_download_tree_view_row_activated))), (((void*)0)), ( (void*)0), (GConnectFlags) 0); | |||
1005 | ||||
1006 | 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) | |||
1007 | "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) | |||
1008 | 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) | |||
1009 | 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); | |||
1010 | ||||
1011 | 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) | |||
1012 | "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) | |||
1013 | 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) | |||
1014 | 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); | |||
1015 | ||||
1016 | 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) | |||
1017 | "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) | |||
1018 | 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) | |||
1019 | 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); | |||
1020 | ||||
1021 | return NSERROR_OK; | |||
1022 | } | |||
1023 | ||||
1024 | ||||
1025 | /* exported interface documented in gtk/download.h */ | |||
1026 | void nsgtk_download_destroy(void) | |||
1027 | { | |||
1028 | nsgtk_download_do(nsgtk_download_store_cancel_item); | |||
1029 | } | |||
1030 | ||||
1031 | ||||
1032 | /* exported interface documented in gtk/download.h */ | |||
1033 | bool_Bool nsgtk_check_for_downloads(GtkWindow *parent) | |||
1034 | { | |||
1035 | GtkWidget *dialog; | |||
1036 | gint response; | |||
1037 | ||||
1038 | if (dl_ctx.num_active == 0) { | |||
1039 | return false0; | |||
1040 | } | |||
1041 | ||||
1042 | dialog = gtk_message_dialog_new_with_markup( | |||
1043 | parent, | |||
1044 | GTK_DIALOG_MODAL, | |||
1045 | GTK_MESSAGE_WARNING, | |||
1046 | GTK_BUTTONS_NONE, | |||
1047 | "<big><b>%s</b></big>\n\n" | |||
1048 | "<small>%s</small>", | |||
1049 | messages_get("gtkQuit"), | |||
1050 | messages_get("gtkDownloadsRunning")); | |||
1051 | ||||
1052 | gtk_dialog_add_buttons(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((gtk_dialog_get_type ())))))), | |||
1053 | "gtk-cancel", GTK_RESPONSE_CANCEL, | |||
1054 | "gtk-quit", GTK_RESPONSE_CLOSE, | |||
1055 | NULL((void*)0)); | |||
1056 | ||||
1057 | response = gtk_dialog_run(GTK_DIALOG(dialog)((((GtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((dialog)), ((gtk_dialog_get_type ()))))))); | |||
1058 | gtk_widget_destroy(dialog); | |||
1059 | ||||
1060 | if (response == GTK_RESPONSE_CANCEL) { | |||
1061 | return true1; | |||
1062 | } | |||
1063 | ||||
1064 | return false0; | |||
1065 | } | |||
1066 | ||||
1067 | ||||
1068 | /* exported interface documented in gtk/download.h */ | |||
1069 | void nsgtk_download_show(GtkWindow *parent) | |||
1070 | { | |||
1071 | gtk_window_set_transient_for(dl_ctx.window, dl_ctx.parent); | |||
1072 | gtk_window_present(dl_ctx.window); | |||
1073 | } |