]> git.armaanb.net Git - chorizo.git/blob - src/downloads.c
c09bda86e8a3d01b259b166593fddabda2ff9061
[chorizo.git] / src / downloads.c
1 #include <webkit2/webkit2.h>
2
3 #include "downloads.h"
4
5 gboolean download_handle(WebKitDownload *, gchar *, gpointer);
6 void download_click(GtkToolButton *, gpointer);
7 void download_cancel(GtkMenuItem *, gpointer);
8 gboolean downloadmanager_delete(GtkWidget *, gpointer);
9
10 struct DownloadManager
11 {
12         GtkWidget *scroll;
13         GtkWidget *toolbar;
14         GtkWidget *win;
15 } dm;
16
17 gint downloads = 0;
18
19 struct DownloadItem
20 {
21         GtkToolButton *tb;
22         WebKitDownload *download;
23 };
24
25 gboolean
26 key_downloadmanager(GtkWidget *widget, GdkEvent *event, gpointer data)
27 {
28         if (event->type == GDK_KEY_PRESS) {
29                 if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK) {
30                         int key = ((GdkEventKey *)event)->keyval;
31                         if ((def_key("close_tab", GDK_KEY_q) == key) ||
32                                         (def_key("download_manager", GDK_KEY_y) == key)) {
33                                 downloadmanager_delete(dm.win, NULL);
34                                 return TRUE;
35                         }
36                 }
37         }
38
39         return FALSE;
40 }
41
42 void
43 changed_download_progress(GObject *obj, GParamSpec *pspec, gpointer data)
44 {
45         WebKitDownload *download = WEBKIT_DOWNLOAD(obj);
46         WebKitURIResponse *resp;
47         GtkToolItem *tb = GTK_TOOL_ITEM(data);
48         gdouble p, size_mb;
49         const gchar *uri;
50         gchar *t, *filename, *base;
51
52         p = webkit_download_get_estimated_progress(download);
53         p = p > 1 ? 1 : p;
54         p = p < 0 ? 0 : p;
55         p *= 100;
56         resp = webkit_download_get_response(download);
57         size_mb = webkit_uri_response_get_content_length(resp) / 1e6;
58
59         uri = webkit_download_get_destination(download);
60         filename = g_filename_from_uri(uri, NULL, NULL);
61         if (filename == NULL) {
62                 /* This really should not happen because WebKit uses that URI to
63                  * write to a file... */
64                 fprintf(stderr, __NAME__": Could not construct file name from URI!\n");
65                 t = g_strdup_printf("%s (%.0f%% of %.1f MB)",
66                                                                                                 webkit_uri_response_get_uri(resp), p, size_mb);
67         } else {
68                 base = g_path_get_basename(filename);
69                 t = g_strdup_printf("%s (%.0f%% of %.1f MB)", base, p, size_mb);
70                 g_free(filename);
71                 g_free(base);
72         }
73         gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), t);
74         g_free(t);
75 }
76 void
77 download_finished(WebKitDownload *download, gpointer data)
78 {
79         if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(data)),
80                                                  "dialog-error") != 0)
81                 gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(data), "emblem-downloads");
82         downloads--;
83 }
84
85 void
86 download_start(WebKitWebView *web_view, WebKitDownload *download,
87                                                          gpointer data)
88 {
89         g_signal_connect(G_OBJECT(download), "decide-destination",
90                                                                          G_CALLBACK(download_handle), data);
91 }
92
93 gboolean
94 download_handle(WebKitDownload *download, gchar *suggested_filename,
95                                                                 gpointer data)
96 {
97         gchar *sug_clean, *path, *path2 = NULL, *uri;
98         GtkToolItem *tb;
99         int suffix = 1;
100         size_t i;
101
102         sug_clean = g_strdup(suggested_filename);
103         for (i = 0; i < strlen(sug_clean); i++)
104                 if (sug_clean[i] == G_DIR_SEPARATOR)
105                         sug_clean[i] = '_';
106
107         path = g_build_filename((char *)data, sug_clean, NULL);
108         path2 = g_strdup(path);
109         while (g_file_test(path2, G_FILE_TEST_EXISTS) && suffix < 1000) {
110                 g_free(path2);
111
112                 path2 = g_strdup_printf("%s.%d", path, suffix);
113                 suffix++;
114         }
115
116         if (suffix == 1000) {
117                 fprintf(stderr, __NAME__": Suffix reached limit for download.\n");
118                 webkit_download_cancel(download);
119         } else {
120                 uri = g_filename_to_uri(path2, NULL, NULL);
121                 webkit_download_set_destination(download, uri);
122                 g_free(uri);
123
124                 tb = gtk_tool_button_new(NULL, NULL);
125                 gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(tb), "network-receive");
126                 gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), sug_clean);
127                 gtk_toolbar_insert(GTK_TOOLBAR(dm.toolbar), tb, 0);
128                 gtk_widget_show_all(dm.win);
129
130                 g_signal_connect(G_OBJECT(download), "notify::estimated-progress",
131                                                                                  G_CALLBACK(changed_download_progress), tb);
132
133                 downloads++;
134                 g_signal_connect(G_OBJECT(download), "finished",
135                                                                                  G_CALLBACK(download_finished), tb);
136
137                 g_object_ref(download);
138
139                 struct DownloadItem *payload = malloc(sizeof(*payload));
140                                                                                                                 payload->tb = (GtkToolButton *)tb;
141                                                                                                                 payload->download = download;
142                                                                                                                 g_signal_connect(G_OBJECT(tb), "clicked", G_CALLBACK(download_click),
143                                                                                                                                                                                 payload);
144                 g_signal_connect(G_OBJECT(tb), "failed", G_CALLBACK(download_cancel),
145                                                                                  payload);
146                 g_signal_connect(G_OBJECT(tb), "destroy_event", G_CALLBACK(g_free),
147                                                                                  payload);
148         }
149
150         g_free(sug_clean);
151         g_free(path);
152         g_free(path2);
153
154         /* Propagate -- to whom it may concern. */
155         return FALSE;
156 }
157
158 void
159 download_cancel(GtkMenuItem *tb, gpointer data)
160 {
161         struct DownloadItem *payload = data;
162         gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(payload->tb), "dialog-error");
163         webkit_download_cancel(payload->download);
164 }
165
166 void
167 download_remove(GtkMenuItem *tb, gpointer data)
168 {
169         struct DownloadItem *payload = data;
170         g_object_unref(payload->download);
171         gtk_widget_destroy(GTK_WIDGET(payload->tb));
172 }
173
174 void
175 download_copy_url(GtkMenuItem *tb, gpointer data)
176 {
177         struct DownloadItem *payload = data;
178         WebKitURIRequest *req = webkit_download_get_request(payload->download);
179         const gchar *uri = webkit_uri_request_get_uri(req);
180         gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), uri,
181                                                                                                  strlen(uri));
182 }
183
184 void
185 download_copy_path(GtkMenuItem *tb, gpointer data)
186 {
187         struct DownloadItem *payload = data;
188         const gchar *path = webkit_download_get_destination(payload->download);
189         gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), path + 7,
190                                                                                                  strlen(path) - 7); // Offset by 7 to remove "file://"
191 }
192
193 void
194 download_click(GtkToolButton *tb, gpointer data)
195 {
196   GtkWidget *pmenu = gtk_menu_new();
197         GtkWidget *option;
198
199         if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(tb)),
200                                                  "network-receive") == 0) {
201                 option = gtk_menu_item_new_with_label("Cancel download");
202                 g_signal_connect(G_OBJECT(option), "activate",
203                                                                                  G_CALLBACK(download_cancel), data);
204         } else {
205                 option = gtk_menu_item_new_with_label("Remove download");
206                 g_signal_connect(G_OBJECT(option), "activate",
207                                                                                  G_CALLBACK(download_remove), data);
208         }
209         gtk_widget_show(option);
210         gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
211
212         option = gtk_menu_item_new_with_label("Copy download URL");
213         gtk_widget_show(option);
214         gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
215         g_signal_connect(G_OBJECT(option), "activate",
216                                                                          G_CALLBACK(download_copy_url), data);
217
218         option = gtk_menu_item_new_with_label("Copy local path");
219         gtk_widget_show(option);
220         gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
221         g_signal_connect(G_OBJECT(option), "activate",
222                                                                          G_CALLBACK(download_copy_path), data);
223
224         gtk_menu_popup_at_pointer(GTK_MENU(pmenu), NULL);
225 }
226
227 gboolean
228 downloadmanager_delete(GtkWidget *obj, gpointer data)
229 {
230         if (!quit_if_nothing_active())
231                 gtk_widget_hide(dm.win);
232
233         return TRUE;
234 }
235
236 void
237 downloadmanager_setup(void)
238 {
239         dm.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
240         gtk_window_set_type_hint(GTK_WINDOW(dm.win), GDK_WINDOW_TYPE_HINT_DIALOG);
241         gtk_window_set_default_size(GTK_WINDOW(dm.win), 500, 250);
242         gtk_window_set_title(GTK_WINDOW(dm.win), __NAME__" - Download Manager");
243         g_signal_connect(G_OBJECT(dm.win), "delete-event",
244                                                                          G_CALLBACK(downloadmanager_delete), NULL);
245         g_signal_connect(G_OBJECT(dm.win), "key-press-event",
246                                                                          G_CALLBACK(key_downloadmanager), NULL);
247
248         dm.toolbar = gtk_toolbar_new();
249         gtk_orientable_set_orientation(GTK_ORIENTABLE(dm.toolbar),
250                                                                                                                                  GTK_ORIENTATION_VERTICAL);
251         gtk_toolbar_set_style(GTK_TOOLBAR(dm.toolbar), GTK_TOOLBAR_BOTH_HORIZ);
252         gtk_toolbar_set_show_arrow(GTK_TOOLBAR(dm.toolbar), FALSE);
253
254         dm.scroll = gtk_scrolled_window_new(NULL, NULL);
255         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dm.scroll),
256                                                                                                                                  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
257         gtk_container_add(GTK_CONTAINER(dm.scroll), dm.toolbar);
258
259         gtk_container_add(GTK_CONTAINER(dm.win), dm.scroll);
260 }
261
262 void
263 downloadmanager_show(void)
264 {
265         gtk_widget_show_all(dm.win);
266 }