]> git.armaanb.net Git - chorizo.git/blob - downloads.c
draft 2
[chorizo.git] / 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         GtkWidget *scroll;
12         GtkWidget *toolbar;
13         GtkWidget *win;
14 } dm;
15
16 gint downloads = 0;
17
18 struct DownloadItem {
19         GtkToolButton *tb;
20         WebKitDownload *download;
21 };
22
23 gboolean
24 key_downloadmanager(GtkWidget *widget, GdkEvent *event, gpointer data)
25 {
26         if (event->type == GDK_KEY_PRESS) {
27                 if (((GdkEventKey *)event)->state & GDK_CONTROL_MASK) {
28                         int key = ((GdkEventKey *)event)->keyval;
29                         if ((GDK_KEY_q == key) || (GDK_KEY_y == key)) {
30                                 downloadmanager_delete(dm.win, NULL);
31                                 return TRUE;
32                         }
33                 }
34         }
35         return FALSE;
36 }
37
38 void
39 changed_download_progress(GObject *obj, GParamSpec *pspec, gpointer data)
40 {
41         WebKitDownload *download = WEBKIT_DOWNLOAD(obj);
42         WebKitURIResponse *resp;
43         GtkToolItem *tb = GTK_TOOL_ITEM(data);
44         gdouble p, size_mb;
45         const gchar *uri;
46         gchar *t, *filename, *base;
47         p = webkit_download_get_estimated_progress(download);
48         p = p > 1 ? 1 : p;
49         p = p < 0 ? 0 : p;
50         p *= 100;
51         resp = webkit_download_get_response(download);
52         size_mb = webkit_uri_response_get_content_length(resp) / 1e6;
53
54         uri = webkit_download_get_destination(download);
55         filename = g_filename_from_uri(uri, NULL, NULL);
56         base = g_path_get_basename(filename);
57         t = g_strdup_printf("%s (%.0f%% of %.1f MB)", base, p, size_mb);
58         g_free(filename);
59         g_free(base);
60         gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), t);
61         g_free(t);
62 }
63
64 void
65 download_finished(WebKitDownload *download, gpointer data)
66 {
67         if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(data)),
68                    "dialog-error") != 0)
69                 gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(data),
70                                               "emblem-downloads");
71         downloads--;
72 }
73
74 void
75 download_start(WebKitWebView *web_view, WebKitDownload *download, gpointer data)
76 {
77         g_signal_connect(G_OBJECT(download), "decide-destination",
78                          G_CALLBACK(download_handle), data);
79 }
80 gboolean
81 download_handle(WebKitDownload *download, gchar *suggested_filename,
82                 gpointer data)
83 {
84         gchar *uri;
85         GtkToolItem *tb;
86
87         GtkWidget *chooser = gtk_file_chooser_dialog_new(
88                 "Choose download location", GTK_WINDOW(dm.win),
89                 GTK_FILE_CHOOSER_ACTION_SAVE, "Save file", GTK_RESPONSE_ACCEPT,
90                 "Cancel", GTK_RESPONSE_CANCEL, NULL);
91         gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(chooser),
92                                             (char *)data);
93         gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(chooser),
94                                           suggested_filename);
95         gtk_file_chooser_set_do_overwrite_confirmation(
96                 GTK_FILE_CHOOSER(chooser), TRUE);
97         gint res = gtk_dialog_run(GTK_DIALOG(chooser));
98         switch (res) {
99         case GTK_RESPONSE_ACCEPT:
100                 uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(chooser));
101                 webkit_download_set_destination(
102                         download,
103                         gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(chooser)));
104                 break;
105         case GTK_RESPONSE_CANCEL:
106                 return FALSE;
107         default:
108                 return FALSE;
109         }
110
111         gtk_widget_destroy(chooser);
112
113         remove(uri + 7);
114         tb = gtk_tool_button_new(NULL, NULL);
115         gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(tb), "network-receive");
116         gtk_tool_button_set_label(GTK_TOOL_BUTTON(tb), uri);
117         gtk_toolbar_insert(GTK_TOOLBAR(dm.toolbar), tb, 0);
118         gtk_widget_show_all(dm.win);
119
120         g_signal_connect(G_OBJECT(download), "notify::estimated-progress",
121                          G_CALLBACK(changed_download_progress), tb);
122
123         downloads++;
124         g_signal_connect(G_OBJECT(download), "finished",
125                          G_CALLBACK(download_finished), tb);
126
127         g_object_ref(download);
128
129         struct DownloadItem *payload = malloc(sizeof(*payload));
130         payload->tb = (GtkToolButton *)tb;
131         payload->download = download;
132         g_signal_connect(G_OBJECT(tb), "clicked", G_CALLBACK(download_click),
133                          payload);
134         g_signal_connect(G_OBJECT(tb), "failed", G_CALLBACK(download_cancel),
135                          payload);
136         g_signal_connect(G_OBJECT(tb), "destroy_event", G_CALLBACK(g_free),
137                          payload);
138
139         //Propagate-- to whom it may concern.
140         return FALSE;
141 }
142
143 void
144 download_cancel(GtkMenuItem *tb, gpointer data)
145 {
146         struct DownloadItem *payload = data;
147         gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(payload->tb),
148                                       "dialog-error");
149         webkit_download_cancel(payload->download);
150 }
151
152 const char *
153 download_get_path(struct DownloadItem *payload)
154 {
155         const char *path = webkit_download_get_destination(payload->download);
156         // Offset by 7 to remove "file://"
157         return path += 7;
158 }
159
160 void
161 download_hide(GtkMenuItem *tb, gpointer data)
162 {
163         struct DownloadItem *payload = data;
164         g_object_unref(payload->download);
165         gtk_widget_destroy(GTK_WIDGET(payload->tb));
166 }
167
168 void
169 download_delete(GtkMenuItem *tb, gpointer data)
170 {
171         remove(download_get_path((struct DownloadItem *)data));
172         download_hide(tb, data);
173 }
174
175 void
176 download_copy_url(GtkMenuItem *tb, gpointer data)
177 {
178         struct DownloadItem *payload = data;
179         WebKitURIRequest *req = webkit_download_get_request(payload->download);
180         const gchar *uri = webkit_uri_request_get_uri(req);
181         gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), uri,
182                                strlen(uri));
183 }
184
185 void
186 download_copy_path(GtkMenuItem *tb, gpointer data)
187 {
188         const char *path = download_get_path((struct DownloadItem *)data);
189         gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD),
190                                path + 7, strlen(path) - 7);
191 }
192
193 void
194 download_xdg_open(GtkMenuItem *tb, gpointer data)
195 {
196         struct DownloadItem *payload = data;
197         const gchar *path = webkit_download_get_destination(payload->download);
198         char *cmd = malloc(strlen(path) + 9);
199         sprintf(cmd, "xdg-open %s", path);
200         system(cmd);
201 }
202
203 void
204 download_click(GtkToolButton *tb, gpointer data)
205 {
206         GtkWidget *pmenu = gtk_menu_new();
207         GtkWidget *option;
208         if (strcmp(gtk_tool_button_get_icon_name(GTK_TOOL_BUTTON(tb)),
209                    "network-receive") == 0) {
210                 option = gtk_menu_item_new_with_label("Cancel download");
211                 g_signal_connect(G_OBJECT(option), "activate",
212                                  G_CALLBACK(download_cancel), data);
213                 gtk_widget_show(option);
214                 gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
215         } else {
216                 option =
217                         gtk_menu_item_new_with_label("Hide download from list");
218                 g_signal_connect(G_OBJECT(option), "activate",
219                                  G_CALLBACK(download_hide), data);
220                 gtk_widget_show(option);
221                 gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
222
223                 option = gtk_menu_item_new_with_label("Delete downloaded file");
224                 g_signal_connect(G_OBJECT(option), "activate",
225                                  G_CALLBACK(download_delete), data);
226                 gtk_widget_show(option);
227                 gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
228
229                 option =
230                         gtk_menu_item_new_with_label("Open file with xdg-open");
231                 gtk_widget_show(option);
232                 gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
233                 g_signal_connect(G_OBJECT(option), "activate",
234                                  G_CALLBACK(download_xdg_open), data);
235         }
236
237         option = gtk_menu_item_new_with_label("Copy download URL");
238         gtk_widget_show(option);
239         gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
240         g_signal_connect(G_OBJECT(option), "activate",
241                          G_CALLBACK(download_copy_url), data);
242
243         option = gtk_menu_item_new_with_label("Copy local path");
244         gtk_widget_show(option);
245         gtk_menu_shell_append(GTK_MENU_SHELL(pmenu), option);
246         g_signal_connect(G_OBJECT(option), "activate",
247                          G_CALLBACK(download_copy_path), data);
248
249         gtk_menu_popup_at_pointer(GTK_MENU(pmenu), NULL);
250 }
251 gboolean
252 downloadmanager_delete(GtkWidget *obj, gpointer data)
253 {
254         if (!quit_if_nothing_active()) gtk_widget_hide(dm.win);
255
256         return TRUE;
257 }
258
259 void
260 downloadmanager_setup(void)
261 {
262         dm.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
263         gtk_window_set_type_hint(GTK_WINDOW(dm.win),
264                                  GDK_WINDOW_TYPE_HINT_DIALOG);
265         gtk_window_set_default_size(GTK_WINDOW(dm.win), 500, 250);
266         gtk_window_set_title(GTK_WINDOW(dm.win), "chorizo - Download Manager");
267         g_signal_connect(G_OBJECT(dm.win), "delete-event",
268                          G_CALLBACK(downloadmanager_delete), NULL);
269         g_signal_connect(G_OBJECT(dm.win), "key-press-event",
270                          G_CALLBACK(key_downloadmanager), NULL);
271
272         dm.toolbar = gtk_toolbar_new();
273         gtk_orientable_set_orientation(GTK_ORIENTABLE(dm.toolbar),
274                                        GTK_ORIENTATION_VERTICAL);
275         gtk_toolbar_set_style(GTK_TOOLBAR(dm.toolbar), GTK_TOOLBAR_BOTH_HORIZ);
276         gtk_toolbar_set_show_arrow(GTK_TOOLBAR(dm.toolbar), FALSE);
277
278         dm.scroll = gtk_scrolled_window_new(NULL, NULL);
279         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(dm.scroll),
280                                        GTK_POLICY_AUTOMATIC,
281                                        GTK_POLICY_AUTOMATIC);
282         gtk_container_add(GTK_CONTAINER(dm.scroll), dm.toolbar);
283
284         gtk_container_add(GTK_CONTAINER(dm.win), dm.scroll);
285 }
286
287 void
288 downloadmanager_show(void)
289 {
290         gtk_widget_show_all(dm.win);
291 }