From a54cbb5aeaba6f6ecf6c04de38acda79733583ed Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 16 Oct 2019 21:51:01 +0100 Subject: [PATCH] commit a neatness on the gtk download window code --- frontends/gtk/download.c | 810 +++++++++++++++++++++++---------------- frontends/gtk/download.h | 25 +- 2 files changed, 509 insertions(+), 326 deletions(-) diff --git a/frontends/gtk/download.c b/frontends/gtk/download.c index b981dce4b..6fb908195 100644 --- a/frontends/gtk/download.c +++ b/frontends/gtk/download.c @@ -65,12 +65,23 @@ typedef enum { } nsgtk_download_status; typedef enum { - NSGTK_DOWNLOAD_PAUSE = 1 << 0, + NSGTK_DOWNLOAD_PAUSE = 1 << 0, NSGTK_DOWNLOAD_RESUME = 1 << 1, - NSGTK_DOWNLOAD_CANCEL = 1 << 2, - NSGTK_DOWNLOAD_CLEAR = 1 << 3 + NSGTK_DOWNLOAD_CANCEL = 1 << 2, + NSGTK_DOWNLOAD_CLEAR = 1 << 3 } nsgtk_download_actions; +static const gchar* status_messages[] = { + NULL, + "gtkWorking", + "gtkError", + "gtkComplete", + "gtkCanceled" +}; + +/** + * context for each download. + */ struct gui_download_window { struct download_context *ctx; nsgtk_download_actions sensitivity; @@ -90,28 +101,37 @@ struct gui_download_window { GError *error; }; -typedef void (*nsgtk_download_selection_action)( - struct gui_download_window *dl, - void *user_data); +typedef void (*nsgtk_download_selection_action)(struct gui_download_window *dl, + void *user_data); -static GtkWindow *nsgtk_download_window, *nsgtk_download_parent; -static GtkProgressBar *nsgtk_download_progress_bar; +/** + * context for a nsgtk download window. + */ +struct download_window_ctx { + GtkWindow *window; + GtkWindow *parent; -static GtkTreeView *nsgtk_download_tree; -static GtkListStore *nsgtk_download_store; -static GtkTreeSelection *nsgtk_download_selection; -static GtkTreeIter nsgtk_download_iter; + GtkProgressBar *progress; -static GTimer *nsgtk_downloads_timer; -static GList *nsgtk_downloads_list; -static GtkButton *nsgtk_download_button_pause; -static GtkButton *nsgtk_download_button_clear; -static GtkButton *nsgtk_download_button_cancel; -static GtkButton *nsgtk_download_button_resume; -static gint nsgtk_downloads_num_active; -static const gchar* status_messages[] = { NULL, "gtkWorking", "gtkError", - "gtkComplete", "gtkCanceled" }; + GtkTreeView *tree; + GtkListStore *store; + GtkTreeSelection *selection; + GtkTreeIter iter; + GTimer *timer; + GList *list; + GtkButton *pause; + GtkButton *clear; + GtkButton *cancel; + GtkButton *resume; + + gint num_active; +}; + +/** + * global instance of the download window + */ +static struct download_window_ctx dl_ctx; static GtkTreeView* nsgtk_download_tree_view_new(GtkBuilder *gladeFile) @@ -119,40 +139,66 @@ static GtkTreeView* nsgtk_download_tree_view_new(GtkBuilder *gladeFile) GtkTreeView *treeview; GtkCellRenderer *renderer; - treeview = GTK_TREE_VIEW(gtk_builder_get_object(gladeFile, "treeDownloads")); + treeview = GTK_TREE_VIEW(gtk_builder_get_object(gladeFile, + "treeDownloads")); /* Progress column */ renderer = gtk_cell_renderer_progress_new(); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkProgress"), renderer, "value", - NSGTK_DOWNLOAD_PROGRESS, "pulse", NSGTK_DOWNLOAD_PULSE, - "text", NSGTK_DOWNLOAD_STATUS, NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkProgress"), + renderer, + "value", + NSGTK_DOWNLOAD_PROGRESS, + "pulse", + NSGTK_DOWNLOAD_PULSE, + "text", + NSGTK_DOWNLOAD_STATUS, + NULL); /* Information column */ renderer = gtk_cell_renderer_text_new(); - g_object_set(G_OBJECT(renderer), "wrap-mode", PANGO_WRAP_WORD_CHAR, - "wrap-width", 300, NULL); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkDetails"), renderer, "text", - NSGTK_DOWNLOAD_INFO, NULL); - gtk_tree_view_column_set_expand(gtk_tree_view_get_column(treeview, - NSGTK_DOWNLOAD_INFO), TRUE); + g_object_set(G_OBJECT(renderer), + "wrap-mode", + PANGO_WRAP_WORD_CHAR, + "wrap-width", + 300, + NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkDetails"), + renderer, + "text", + NSGTK_DOWNLOAD_INFO, + NULL); + gtk_tree_view_column_set_expand( + gtk_tree_view_get_column(treeview, + NSGTK_DOWNLOAD_INFO), TRUE); /* Time remaining column */ renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkRemaining"), renderer, "text", - NSGTK_DOWNLOAD_REMAINING, NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkRemaining"), + renderer, + "text", + NSGTK_DOWNLOAD_REMAINING, + NULL); /* Speed column */ renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_insert_column_with_attributes (treeview, -1, - messages_get("gtkSpeed"), renderer, "text", - NSGTK_DOWNLOAD_SPEED, NULL); + gtk_tree_view_insert_column_with_attributes(treeview, + -1, + messages_get("gtkSpeed"), + renderer, + "text", + NSGTK_DOWNLOAD_SPEED, + NULL); return treeview; } + static gint nsgtk_download_sort(GtkTreeModel *model, GtkTreeIter *a, @@ -167,43 +213,52 @@ nsgtk_download_sort(GtkTreeModel *model, return dl1->status - dl2->status; } + static void nsgtk_download_sensitivity_update_buttons(nsgtk_download_actions sensitivity) { /* Glade seems to pack the buttons in an arbitrary order */ enum { PAUSE_BUTTON, CLEAR_BUTTON, CANCEL_BUTTON, RESUME_BUTTON }; - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_pause), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.pause), sensitivity & NSGTK_DOWNLOAD_PAUSE); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_clear), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.clear), sensitivity & NSGTK_DOWNLOAD_CLEAR); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_cancel), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.cancel), sensitivity & NSGTK_DOWNLOAD_CANCEL); - gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_download_button_resume), + gtk_widget_set_sensitive(GTK_WIDGET(dl_ctx.resume), sensitivity & NSGTK_DOWNLOAD_RESUME); } + static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection) { GtkTreeIter iter; GList *rows; - gboolean selected = gtk_tree_selection_count_selected_rows(selection); - GtkTreeModel *model = GTK_TREE_MODEL(nsgtk_download_store); + gboolean selected; + GtkTreeModel *model; nsgtk_download_actions sensitivity = 0; struct gui_download_window *dl; + model = GTK_TREE_MODEL(dl_ctx.store); + + selected = gtk_tree_selection_count_selected_rows(selection); if (selected) { rows = gtk_tree_selection_get_selected_rows(selection, &model); while (rows != NULL) { - gtk_tree_model_get_iter(model, &iter, + gtk_tree_model_get_iter(model, + &iter, (GtkTreePath*)rows->data); - gtk_tree_model_get(model, &iter, NSGTK_DOWNLOAD, - &dl, -1); + gtk_tree_model_get(model, + &iter, + NSGTK_DOWNLOAD, + &dl, + -1); sensitivity |= dl->sensitivity; rows = rows->next; } } else { - rows = nsgtk_downloads_list; + rows = dl_ctx.list; while (rows != NULL) { dl = rows->data; sensitivity |= (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR); @@ -211,103 +266,121 @@ static void nsgtk_download_sensitivity_evaluate(GtkTreeSelection *selection) } } - nsgtk_download_sensitivity_update_buttons(sensitivity); } + /** * Wrapper to GFunc-ify gtk_tree_path_free for g_list_foreach. */ -static void nsgtk_download_gfunc__gtk_tree_path_free( - gpointer data, - gpointer user_data) +static void +nsgtk_download_gfunc__gtk_tree_path_free(gpointer data, gpointer user_data) { gtk_tree_path_free(data); } + /** * Wrapper to GFunc-ify g_free for g_list_foreach. */ -static void nsgtk_download_gfunc__g_free( - gpointer data, - gpointer user_data) +static void +nsgtk_download_gfunc__g_free(gpointer data, gpointer user_data) { g_free(data); } + static void nsgtk_download_do(nsgtk_download_selection_action action) { GList *rows, *dls = NULL; - GtkTreeModel *model = GTK_TREE_MODEL(nsgtk_download_store); - gboolean selection_exists = gtk_tree_selection_count_selected_rows( - nsgtk_download_selection); + GtkTreeModel *model; - if (selection_exists) { - rows = gtk_tree_selection_get_selected_rows( - nsgtk_download_selection, &model); + if (gtk_tree_selection_count_selected_rows(dl_ctx.selection)) { + model = GTK_TREE_MODEL(dl_ctx.store); + + rows = gtk_tree_selection_get_selected_rows(dl_ctx.selection, + &model); while (rows != NULL) { struct gui_download_window *dl; - gtk_tree_model_get_iter(GTK_TREE_MODEL( - nsgtk_download_store), - &nsgtk_download_iter, + + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, (GtkTreePath*)rows->data); - gtk_tree_model_get(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, NSGTK_DOWNLOAD, - &dl, -1); + + gtk_tree_model_get(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, + NSGTK_DOWNLOAD, + &dl, + -1); + dls = g_list_prepend(dls, dl); rows = rows->next; } - g_list_foreach(rows, nsgtk_download_gfunc__gtk_tree_path_free, NULL); - g_list_foreach(rows, nsgtk_download_gfunc__g_free, NULL); + g_list_foreach(rows, + nsgtk_download_gfunc__gtk_tree_path_free, + NULL); + g_list_foreach(rows, + nsgtk_download_gfunc__g_free, + NULL); g_list_free(rows); - } else - dls = g_list_copy(nsgtk_downloads_list); + } else { + dls = g_list_copy(dl_ctx.list); + } g_list_foreach(dls, (GFunc)action, NULL); g_list_free(dls); } + static gchar* nsgtk_download_info_to_string(struct gui_download_window *dl) { - gchar *size_info = g_strdup_printf(messages_get("gtkSizeInfo"), - human_friendly_bytesize(dl->size_downloaded), - dl->size_total == 0 ? messages_get("gtkUnknownSize") : - human_friendly_bytesize(dl->size_total)); - + gchar *size_info; gchar *r; - if (dl->status != NSGTK_DOWNLOAD_ERROR) + size_info = g_strdup_printf(messages_get("gtkSizeInfo"), + human_friendly_bytesize(dl->size_downloaded), + dl->size_total == 0 ? + messages_get("gtkUnknownSize") : + human_friendly_bytesize(dl->size_total)); + + if (dl->status != NSGTK_DOWNLOAD_ERROR) { r = g_strdup_printf("%s\n%s", dl->name->str, size_info); - else - r = g_strdup_printf("%s\n%s", dl->name->str, - dl->error->message); + } else { + r = g_strdup_printf("%s\n%s", dl->name->str, dl->error->message); + } g_free(size_info); return r; } + static gchar* nsgtk_download_time_to_string(gint seconds) { gint hours, minutes; - if (seconds < 0) + if (seconds < 0) { return g_strdup("-"); + } hours = seconds / 3600; seconds -= hours * 3600; minutes = seconds / 60; seconds -= minutes * 60; - if (hours > 0) - return g_strdup_printf("%u:%02u:%02u", hours, minutes, + if (hours > 0) { + return g_strdup_printf("%u:%02u:%02u", + hours, + minutes, seconds); - else + } else { return g_strdup_printf("%u:%02u", minutes, seconds); + } } -static void nsgtk_download_store_update_item (struct gui_download_window *dl) + +static void nsgtk_download_store_update_item(struct gui_download_window *dl) { gchar *info = nsgtk_download_info_to_string(dl); char *human = human_friendly_bytesize(dl->speed); @@ -317,11 +390,11 @@ static void nsgtk_download_store_update_item (struct gui_download_window *dl) gboolean pulse = dl->status == NSGTK_DOWNLOAD_WORKING; /* Updates iter (which is needed to set and get data) with the dl row */ - gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, gtk_tree_row_reference_get_path(dl->row)); - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, + gtk_list_store_set(dl_ctx.store, &dl_ctx.iter, NSGTK_DOWNLOAD_PULSE, pulse ? dl->progress : -1, NSGTK_DOWNLOAD_PROGRESS, pulse ? 0 : dl->progress, NSGTK_DOWNLOAD_INFO, info, @@ -334,20 +407,23 @@ static void nsgtk_download_store_update_item (struct gui_download_window *dl) g_free(time); } + static gboolean nsgtk_download_update(gboolean force_update) { /* Be sure we need to update */ - if (!nsgtk_widget_get_visible(GTK_WIDGET(nsgtk_download_window))) + if (!nsgtk_widget_get_visible(GTK_WIDGET(dl_ctx.window))) { return TRUE; + } GList *list; gchar *text; gboolean update, pulse_mode = FALSE; gint downloaded = 0, total = 0, dls = 0; - gfloat percent, elapsed = g_timer_elapsed(nsgtk_downloads_timer, NULL); - nsgtk_downloads_num_active = 0; + gfloat percent, elapsed = g_timer_elapsed(dl_ctx.timer, NULL); - for (list = nsgtk_downloads_list; list != NULL; list = list->next) { + dl_ctx.num_active = 0; + + for (list = dl_ctx.list; list != NULL; list = list->next) { struct gui_download_window *dl = list->data; update = force_update; @@ -366,10 +442,11 @@ static gboolean nsgtk_download_update(gboolean force_update) dl->progress = (gfloat) dl->size_downloaded / dl->size_total * 100; - } else + } else { dl->progress++; + } - nsgtk_downloads_num_active++; + dl_ctx.num_active++; update = TRUE; /* Fall through */ @@ -382,60 +459,66 @@ static gboolean nsgtk_download_update(gboolean force_update) ;//Do nothing } - if (update) + if (update) { nsgtk_download_store_update_item(dl); + } } if (pulse_mode) { text = g_strdup_printf( - messages_get(nsgtk_downloads_num_active > 1 ? + messages_get(dl_ctx.num_active > 1 ? "gtkProgressBarPulse" : "gtkProgressBarPulseSingle"), - nsgtk_downloads_num_active); - gtk_progress_bar_pulse(nsgtk_download_progress_bar); - gtk_progress_bar_set_text(nsgtk_download_progress_bar, text); + dl_ctx.num_active); + gtk_progress_bar_pulse(dl_ctx.progress); + gtk_progress_bar_set_text(dl_ctx.progress, text); } else { percent = total != 0 ? (gfloat)downloaded / total : 0; text = g_strdup_printf(messages_get("gtkProgressBar"), floor(percent*100), dls); - gtk_progress_bar_set_fraction(nsgtk_download_progress_bar, + gtk_progress_bar_set_fraction(dl_ctx.progress, percent); - gtk_progress_bar_set_text(nsgtk_download_progress_bar, text); + gtk_progress_bar_set_text(dl_ctx.progress, text); } g_free(text); - if (nsgtk_downloads_num_active == 0) + if (dl_ctx.num_active == 0) { return FALSE; /* Returning FALSE here cancels the g_timeout */ - else + } else { return TRUE; + } } -static void nsgtk_download_store_clear_item( - struct gui_download_window *dl, - void *user_data) + +static void +nsgtk_download_store_clear_item(struct gui_download_window *dl, void *user_data) { if (dl->sensitivity & NSGTK_DOWNLOAD_CLEAR) { - nsgtk_downloads_list = g_list_remove(nsgtk_downloads_list, dl); + dl_ctx.list = g_list_remove(dl_ctx.list, dl); - gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, gtk_tree_row_reference_get_path(dl->row)); - gtk_list_store_remove(nsgtk_download_store, - &nsgtk_download_iter); + gtk_list_store_remove(dl_ctx.store, + &dl_ctx.iter); download_context_destroy(dl->ctx); g_string_free(dl->name, TRUE); g_string_free(dl->time_left, TRUE); g_free(dl); - nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); + nsgtk_download_sensitivity_evaluate(dl_ctx.selection); nsgtk_download_update(FALSE); } } -static void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, - GtkTreePath *path, GtkTreeViewColumn *column, gpointer data) + +static void +nsgtk_download_tree_view_row_activated(GtkTreeView *tree, + GtkTreePath *path, + GtkTreeViewColumn *column, + gpointer data) { GtkTreeModel *model; GtkTreeIter iter; @@ -448,31 +531,36 @@ static void nsgtk_download_tree_view_row_activated(GtkTreeView *tree, } } -static void nsgtk_download_change_sensitivity(struct gui_download_window *dl, - nsgtk_download_actions sensitivity) + +static void +nsgtk_download_change_sensitivity(struct gui_download_window *dl, + nsgtk_download_actions sensitivity) { dl->sensitivity = sensitivity; - nsgtk_download_sensitivity_evaluate(nsgtk_download_selection); + nsgtk_download_sensitivity_evaluate(dl_ctx.selection); } -static void nsgtk_download_change_status ( - struct gui_download_window *dl, nsgtk_download_status status) + +static void +nsgtk_download_change_status(struct gui_download_window *dl, + nsgtk_download_status status) { dl->status = status; if (status != NSGTK_DOWNLOAD_NONE) { - gtk_tree_model_get_iter(GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter, + gtk_tree_model_get_iter(GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter, gtk_tree_row_reference_get_path(dl->row)); - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, + gtk_list_store_set(dl_ctx.store, &dl_ctx.iter, NSGTK_DOWNLOAD_STATUS, messages_get(status_messages[status]), -1); } } -static void nsgtk_download_store_cancel_item ( - struct gui_download_window *dl, - void *user_data) + +static void +nsgtk_download_store_cancel_item(struct gui_download_window *dl, + void *user_data) { if (dl->sensitivity & NSGTK_DOWNLOAD_CANCEL) { dl->speed = 0; @@ -490,148 +578,49 @@ static void nsgtk_download_store_cancel_item ( } } + static gboolean nsgtk_download_hide(GtkWidget *window) { gtk_widget_hide(window); return TRUE; } -/* exported interface documented in gtk/download.h */ -nserror nsgtk_download_init(void) -{ - GtkBuilder* builder; - nserror res; - res = nsgtk_builder_new_from_resname("downloads", &builder); - if (res != NSERROR_OK) { - NSLOG(netsurf, INFO, "Download UI builder init failed"); - return res; - } - - gtk_builder_connect_signals(builder, NULL); - - nsgtk_download_button_pause = GTK_BUTTON(gtk_builder_get_object(builder, "buttonPause")); - nsgtk_download_button_clear = GTK_BUTTON(gtk_builder_get_object(builder, "buttonClear")); - nsgtk_download_button_cancel = GTK_BUTTON(gtk_builder_get_object(builder, "buttonCancel")); - nsgtk_download_button_resume = GTK_BUTTON(gtk_builder_get_object(builder, "buttonPlay")); - - nsgtk_download_progress_bar = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, "progressBar")); - nsgtk_download_window = GTK_WINDOW(gtk_builder_get_object(builder, "wndDownloads")); - nsgtk_download_parent = NULL; - - gtk_window_set_transient_for(GTK_WINDOW(nsgtk_download_window), - nsgtk_download_parent); - gtk_window_set_destroy_with_parent(GTK_WINDOW(nsgtk_download_window), - FALSE); - - nsgtk_downloads_timer = g_timer_new(); - - nsgtk_download_tree = nsgtk_download_tree_view_new(builder); - - nsgtk_download_store = gtk_list_store_new(NSGTK_DOWNLOAD_N_COLUMNS, - G_TYPE_INT, /* % complete */ - G_TYPE_STRING, /* Description */ - G_TYPE_STRING, /* Time remaining */ - G_TYPE_STRING, /* Speed */ - G_TYPE_INT, /* Pulse */ - G_TYPE_STRING, /* Status */ - G_TYPE_POINTER /* Download structure */ - ); - - - gtk_tree_view_set_model(nsgtk_download_tree, - GTK_TREE_MODEL(nsgtk_download_store)); - - gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(nsgtk_download_store), - NSGTK_DOWNLOAD_STATUS, - (GtkTreeIterCompareFunc) nsgtk_download_sort, NULL, NULL); - gtk_tree_sortable_set_sort_column_id( - GTK_TREE_SORTABLE(nsgtk_download_store), - NSGTK_DOWNLOAD_STATUS, GTK_SORT_ASCENDING); - - g_object_unref(nsgtk_download_store); - - nsgtk_download_selection = - gtk_tree_view_get_selection(nsgtk_download_tree); - gtk_tree_selection_set_mode(nsgtk_download_selection, - GTK_SELECTION_MULTIPLE); - - g_signal_connect(G_OBJECT(nsgtk_download_selection), "changed", - G_CALLBACK(nsgtk_download_sensitivity_evaluate), NULL); - g_signal_connect(nsgtk_download_tree, "row-activated", - G_CALLBACK(nsgtk_download_tree_view_row_activated), - NULL); - g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonClear"), - "clicked", - G_CALLBACK(nsgtk_download_do), - nsgtk_download_store_clear_item); - g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonCancel"), - "clicked", - G_CALLBACK(nsgtk_download_do), - nsgtk_download_store_cancel_item); - g_signal_connect(G_OBJECT(nsgtk_download_window), "delete-event", - G_CALLBACK(nsgtk_download_hide), NULL); - - return NSERROR_OK; -} - -void nsgtk_download_destroy () -{ - nsgtk_download_do(nsgtk_download_store_cancel_item); -} - -bool nsgtk_check_for_downloads (GtkWindow *parent) -{ - if (nsgtk_downloads_num_active != 0) { - GtkWidget *dialog; - dialog = gtk_message_dialog_new_with_markup(parent, - GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, - GTK_BUTTONS_NONE, - "%s\n\n" - "%s", messages_get("gtkQuit"), - messages_get("gtkDownloadsRunning")); - gtk_dialog_add_buttons(GTK_DIALOG(dialog), "gtk-cancel", - GTK_RESPONSE_CANCEL, "gtk-quit", - GTK_RESPONSE_CLOSE, NULL); - - gint response = gtk_dialog_run(GTK_DIALOG(dialog)); - gtk_widget_destroy(dialog); - - if (response == GTK_RESPONSE_CANCEL) - return true; - } - - return false; -} - -void nsgtk_download_show(GtkWindow *parent) -{ - gtk_window_set_transient_for(nsgtk_download_window, - nsgtk_download_parent); - gtk_window_present(nsgtk_download_window); -} - -static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *domain, - const gchar *size) +/** + * Prompt user for downloaded file name + * + * \param filename The original name of the file + * \param domain the domain the file is being downloaded from + * \param size The size of the file being downloaded + */ +static gchar* +nsgtk_download_dialog_show(const gchar *filename, + const gchar *domain, + const gchar *size) { enum { GTK_RESPONSE_DOWNLOAD, GTK_RESPONSE_SAVE_AS }; GtkWidget *dialog; char *destination = NULL; - gchar *message = g_strdup(messages_get("gtkStartDownload")); - gchar *info = g_strdup_printf(messages_get("gtkInfo"), filename, - domain, size); + gchar *message; + gchar *info; - dialog = gtk_message_dialog_new_with_markup(nsgtk_download_parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, - "%s" - "\n\n%s", - message, info); + message = g_strdup(messages_get("gtkStartDownload")); + info = g_strdup_printf(messages_get("gtkInfo"), filename, domain, size); - gtk_dialog_add_buttons(GTK_DIALOG(dialog), NSGTK_STOCK_SAVE, - GTK_RESPONSE_DOWNLOAD, NSGTK_STOCK_CANCEL, - GTK_RESPONSE_CANCEL, NSGTK_STOCK_SAVE_AS, - GTK_RESPONSE_SAVE_AS, NULL); + dialog = gtk_message_dialog_new_with_markup( + dl_ctx.parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, + "%s" + "\n\n%s", + message, + info); + + gtk_dialog_add_buttons(GTK_DIALOG(dialog), + NSGTK_STOCK_SAVE, GTK_RESPONSE_DOWNLOAD, + NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NSGTK_STOCK_SAVE_AS, GTK_RESPONSE_SAVE_AS, + NULL); gint result = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); @@ -640,13 +629,13 @@ static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *do switch (result) { case GTK_RESPONSE_SAVE_AS: { - dialog = gtk_file_chooser_dialog_new - (messages_get("gtkSave"), - nsgtk_download_parent, - GTK_FILE_CHOOSER_ACTION_SAVE, - NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); + dialog = gtk_file_chooser_dialog_new( + messages_get("gtkSave"), + dl_ctx.parent, + GTK_FILE_CHOOSER_ACTION_SAVE, + NSGTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + NSGTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER(dialog), filename); gtk_file_chooser_set_current_folder @@ -676,30 +665,32 @@ static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *do * confirmation if needed */ if (g_file_test(destination, G_FILE_TEST_EXISTS) && nsoption_bool(request_overwrite)) { - message = g_strdup_printf(messages_get( - "gtkOverwrite"), filename); - info = g_strdup_printf(messages_get( - "gtkOverwriteInfo"), + GtkWidget *button; + + message = g_strdup_printf(messages_get("gtkOverwrite"), + filename); + info = g_strdup_printf(messages_get("gtkOverwriteInfo"), nsoption_charp(downloads_directory)); dialog = gtk_message_dialog_new_with_markup( - nsgtk_download_parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_QUESTION, - GTK_BUTTONS_CANCEL, - "%s",message); + dl_ctx.parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_QUESTION, + GTK_BUTTONS_CANCEL, + "%s", + message); gtk_message_dialog_format_secondary_markup( - GTK_MESSAGE_DIALOG(dialog), - "%s", info); + GTK_MESSAGE_DIALOG(dialog), + "%s", + info); - GtkWidget *button = gtk_dialog_add_button( - GTK_DIALOG(dialog), - "_Replace", - GTK_RESPONSE_DOWNLOAD); + button = gtk_dialog_add_button(GTK_DIALOG(dialog), + "_Replace", + GTK_RESPONSE_DOWNLOAD); gtk_button_set_image(GTK_BUTTON(button), nsgtk_image_new_from_stock( - NSGTK_STOCK_SAVE, - GTK_ICON_SIZE_BUTTON)); + NSGTK_STOCK_SAVE, + GTK_ICON_SIZE_BUTTON)); gint result = gtk_dialog_run(GTK_DIALOG(dialog)); if (result == GTK_RESPONSE_CANCEL) @@ -716,20 +707,24 @@ static gchar* nsgtk_download_dialog_show (const gchar *filename, const gchar *do } -static gboolean nsgtk_download_handle_error (GError *error) +static gboolean nsgtk_download_handle_error(GError *error) { - if (error != NULL) { - GtkWidget*dialog; - gchar *message = g_strdup_printf(messages_get("gtkFileError"), - error->message); + GtkWidget*dialog; + gchar *message; - dialog = gtk_message_dialog_new_with_markup - (nsgtk_download_parent, - GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, - GTK_BUTTONS_OK, - "%s\n\n" - "%s", messages_get("gtkFailed"), - message); + if (error != NULL) { + message = g_strdup_printf(messages_get("gtkFileError"), + error->message); + + dialog = gtk_message_dialog_new_with_markup( + dl_ctx.parent, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s\n\n" + "%s", + messages_get("gtkFailed"), + message); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); @@ -738,14 +733,19 @@ static gboolean nsgtk_download_handle_error (GError *error) return FALSE; } -static void nsgtk_download_store_create_item (struct gui_download_window *dl) + +static void nsgtk_download_store_create_item(struct gui_download_window *dl) { nsgtk_download_store_update_item(dl); /* The iter has already been updated to this row */ - gtk_list_store_set(nsgtk_download_store, &nsgtk_download_iter, - NSGTK_DOWNLOAD, dl, -1); + gtk_list_store_set(dl_ctx.store, + &dl_ctx.iter, + NSGTK_DOWNLOAD, + dl, + -1); } + /** * Wrapper to GSourceFunc-ify nsgtk_download_update. */ @@ -755,22 +755,31 @@ nsgtk_download_gsourcefunc__nsgtk_download_update(gpointer user_data) return nsgtk_download_update(FALSE); } + +/** + * core callback on creating a new download + */ static struct gui_download_window * gui_download_window_create(download_context *ctx, struct gui_window *gui) { - nsurl *url = download_context_get_url(ctx); - unsigned long total_size = download_context_get_total_length(ctx); + nsurl *url; + unsigned long total_size; gchar *domain; gchar *destination; - gboolean unknown_size = total_size == 0; - const char *size = (total_size == 0 ? - messages_get("gtkUnknownSize") : - human_friendly_bytesize(total_size)); + gboolean unknown_size; + struct gui_download_window *download; + const char *size; - nsgtk_download_parent = - nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); + url = download_context_get_url(ctx); + total_size = download_context_get_total_length(ctx); + unknown_size = total_size == 0; + size = (total_size == 0 ? + messages_get("gtkUnknownSize") : + human_friendly_bytesize(total_size)); - struct gui_download_window *download = malloc(sizeof *download); + dl_ctx.parent = nsgtk_scaffolding_window(nsgtk_get_scaffold(gui)); + + download = malloc(sizeof *download); if (download == NULL) { return NULL; } @@ -797,12 +806,12 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui) /* Add the new row and store the reference to it (which keeps track of * the tree changes) */ - gtk_list_store_prepend(nsgtk_download_store, &nsgtk_download_iter); + gtk_list_store_prepend(dl_ctx.store, &dl_ctx.iter); download->row = gtk_tree_row_reference_new( - GTK_TREE_MODEL(nsgtk_download_store), - gtk_tree_model_get_path( - GTK_TREE_MODEL(nsgtk_download_store), - &nsgtk_download_iter)); + GTK_TREE_MODEL(dl_ctx.store), + gtk_tree_model_get_path( + GTK_TREE_MODEL(dl_ctx.store), + &dl_ctx.iter)); download->ctx = ctx; download->name = g_string_new(download_context_get_filename(ctx)); @@ -810,13 +819,14 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui) download->size_total = total_size; download->size_downloaded = 0; download->speed = 0; - download->start_time = g_timer_elapsed(nsgtk_downloads_timer, NULL); + download->start_time = g_timer_elapsed(dl_ctx.timer, NULL); download->time_remaining = -1; download->status = NSGTK_DOWNLOAD_NONE; download->progress = 0; download->error = NULL; - download->write = - g_io_channel_new_file(destination, "w", &download->error); + download->write = g_io_channel_new_file(destination, + "w", + &download->error); if (nsgtk_download_handle_error(download->error)) { g_string_free(download->name, TRUE); @@ -829,26 +839,32 @@ gui_download_window_create(download_context *ctx, struct gui_window *gui) nsgtk_download_change_sensitivity(download, NSGTK_DOWNLOAD_CANCEL); nsgtk_download_store_create_item(download); - nsgtk_download_show(nsgtk_download_parent); + nsgtk_download_show(dl_ctx.parent); - if (unknown_size) + if (unknown_size) { nsgtk_download_change_status(download, NSGTK_DOWNLOAD_WORKING); + } - if (nsgtk_downloads_num_active == 0) { + if (dl_ctx.num_active == 0) { g_timeout_add( UPDATE_RATE, nsgtk_download_gsourcefunc__nsgtk_download_update, NULL); } - nsgtk_downloads_list = g_list_prepend(nsgtk_downloads_list, download); + dl_ctx.list = g_list_prepend(dl_ctx.list, download); return download; } -static nserror gui_download_window_data(struct gui_download_window *dw, - const char *data, unsigned int size) +/** + * core callback on receipt of data + */ +static nserror +gui_download_window_data(struct gui_download_window *dw, + const char *data, + unsigned int size) { g_io_channel_write_chars(dw->write, data, size, NULL, &dw->error); if (dw->error != NULL) { @@ -860,7 +876,7 @@ static nserror gui_download_window_data(struct gui_download_window *dw, nsgtk_download_update(TRUE); - gtk_window_present(nsgtk_download_window); + gtk_window_present(dl_ctx.window); return NSERROR_SAVE_FAILED; } @@ -870,12 +886,18 @@ static nserror gui_download_window_data(struct gui_download_window *dw, } -static void gui_download_window_error(struct gui_download_window *dw, - const char *error_msg) +/** + * core callback on error + */ +static void +gui_download_window_error(struct gui_download_window *dw, const char *error_msg) { } +/** + * core callback when core download is complete + */ static void gui_download_window_done(struct gui_download_window *dw) { g_io_channel_shutdown(dw->write, TRUE, &dw->error); @@ -888,10 +910,11 @@ static void gui_download_window_done(struct gui_download_window *dw) nsgtk_download_change_sensitivity(dw, NSGTK_DOWNLOAD_CLEAR); nsgtk_download_change_status(dw, NSGTK_DOWNLOAD_COMPLETE); - if (nsoption_bool(downloads_clear)) + if (nsoption_bool(downloads_clear)) { nsgtk_download_store_clear_item(dw, NULL); - else + } else { nsgtk_download_update(TRUE); + } } @@ -903,3 +926,146 @@ static struct gui_download_table download_table = { }; struct gui_download_table *nsgtk_download_table = &download_table; + + +/* exported interface documented in gtk/download.h */ +nserror nsgtk_download_init(void) +{ + GtkBuilder* builder; + nserror res; + + res = nsgtk_builder_new_from_resname("downloads", &builder); + if (res != NSERROR_OK) { + NSLOG(netsurf, INFO, "Download UI builder init failed"); + return res; + } + + gtk_builder_connect_signals(builder, NULL); + + dl_ctx.pause = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonPause")); + dl_ctx.clear = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonClear")); + dl_ctx.cancel = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonCancel")); + dl_ctx.resume = GTK_BUTTON(gtk_builder_get_object(builder, + "buttonPlay")); + + dl_ctx.progress = GTK_PROGRESS_BAR(gtk_builder_get_object(builder, + "progressBar")); + dl_ctx.window = GTK_WINDOW(gtk_builder_get_object(builder, + "wndDownloads")); + dl_ctx.parent = NULL; + + gtk_window_set_transient_for(GTK_WINDOW(dl_ctx.window), + dl_ctx.parent); + gtk_window_set_destroy_with_parent(GTK_WINDOW(dl_ctx.window), + FALSE); + + dl_ctx.timer = g_timer_new(); + + dl_ctx.tree = nsgtk_download_tree_view_new(builder); + + dl_ctx.store = gtk_list_store_new(NSGTK_DOWNLOAD_N_COLUMNS, + G_TYPE_INT, /* % complete */ + G_TYPE_STRING, /* Description */ + G_TYPE_STRING, /* Time remaining */ + G_TYPE_STRING, /* Speed */ + G_TYPE_INT, /* Pulse */ + G_TYPE_STRING, /* Status */ + G_TYPE_POINTER /* Download structure */ + ); + + + gtk_tree_view_set_model(dl_ctx.tree, GTK_TREE_MODEL(dl_ctx.store)); + + gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(dl_ctx.store), + NSGTK_DOWNLOAD_STATUS, + (GtkTreeIterCompareFunc)nsgtk_download_sort, NULL, NULL); + gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(dl_ctx.store), + NSGTK_DOWNLOAD_STATUS, + GTK_SORT_ASCENDING); + + g_object_unref(dl_ctx.store); + + dl_ctx.selection = gtk_tree_view_get_selection(dl_ctx.tree); + gtk_tree_selection_set_mode(dl_ctx.selection, GTK_SELECTION_MULTIPLE); + + g_signal_connect(G_OBJECT(dl_ctx.selection), + "changed", + G_CALLBACK(nsgtk_download_sensitivity_evaluate), + NULL); + + g_signal_connect(dl_ctx.tree, + "row-activated", + G_CALLBACK(nsgtk_download_tree_view_row_activated), + NULL); + + g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonClear"), + "clicked", + G_CALLBACK(nsgtk_download_do), + nsgtk_download_store_clear_item); + + g_signal_connect_swapped(gtk_builder_get_object(builder, "buttonCancel"), + "clicked", + G_CALLBACK(nsgtk_download_do), + nsgtk_download_store_cancel_item); + + g_signal_connect(G_OBJECT(dl_ctx.window), + "delete-event", + G_CALLBACK(nsgtk_download_hide), + NULL); + + return NSERROR_OK; +} + + +/* exported interface documented in gtk/download.h */ +void nsgtk_download_destroy () +{ + nsgtk_download_do(nsgtk_download_store_cancel_item); +} + + +/* exported interface documented in gtk/download.h */ +bool nsgtk_check_for_downloads(GtkWindow *parent) +{ + GtkWidget *dialog; + gint response; + + if (dl_ctx.num_active == 0) { + return false; + } + + dialog = gtk_message_dialog_new_with_markup( + parent, + GTK_DIALOG_MODAL, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_NONE, + "%s\n\n" + "%s", + messages_get("gtkQuit"), + messages_get("gtkDownloadsRunning")); + + gtk_dialog_add_buttons(GTK_DIALOG(dialog), + "gtk-cancel", GTK_RESPONSE_CANCEL, + "gtk-quit", GTK_RESPONSE_CLOSE, + NULL); + + response = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (response == GTK_RESPONSE_CANCEL) { + return true; + } + + return false; +} + + +/* exported interface documented in gtk/download.h */ +void nsgtk_download_show(GtkWindow *parent) +{ + gtk_window_set_transient_for(dl_ctx.window, dl_ctx.parent); + gtk_window_present(dl_ctx.window); +} diff --git a/frontends/gtk/download.h b/frontends/gtk/download.h index b720650ca..c6dc187e7 100644 --- a/frontends/gtk/download.h +++ b/frontends/gtk/download.h @@ -19,13 +19,12 @@ #ifndef GTK_DOWNLOAD_H #define GTK_DOWNLOAD_H -#include - /** * download operation table for gtk */ extern struct gui_download_table *nsgtk_download_table; + /** * Initialise download window ready for use. * @@ -33,9 +32,27 @@ extern struct gui_download_table *nsgtk_download_table; */ nserror nsgtk_download_init(void); -void nsgtk_download_destroy (void); + +/** + * Destroy download window + */ +void nsgtk_download_destroy(void); + + +/** + * Check with user if download is in progress they want to complete + * + * \param parent The parent window for the prompt dialog. + * \return true if the user wants to continue else false. + */ bool nsgtk_check_for_downloads(GtkWindow *parent); + + +/** + * Show the download window + * + * \param parent The parent window to use for the shown window + */ void nsgtk_download_show(GtkWindow *parent); -void nsgtk_download_add(gchar *url, gchar *destination); #endif