4514
|
1 /**
|
|
2 * @file gtkft.c The GTK+ file transfer UI
|
|
3 *
|
|
4 * gaim
|
|
5 *
|
|
6 * Copyright (C) 2003, Christian Hammond <chipx86@gnupdate.org>
|
|
7 *
|
|
8 * This program is free software; you can redistribute it and/or modify
|
|
9 * it under the terms of the GNU General Public License as published by
|
|
10 * the Free Software Foundation; either version 2 of the License, or
|
|
11 * (at your option) any later version.
|
|
12 *
|
|
13 * This program is distributed in the hope that it will be useful,
|
|
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
16 * GNU General Public License for more details.
|
|
17 *
|
|
18 * You should have received a copy of the GNU General Public License
|
|
19 * along with this program; if not, write to the Free Software
|
|
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
21 *
|
|
22 */
|
|
23 #include "gaim.h"
|
|
24 #include "prpl.h"
|
|
25 #include <sys/types.h>
|
|
26 #include <sys/stat.h>
|
|
27 #include <unistd.h>
|
|
28 #include <string.h>
|
|
29 #include "gtkcellrendererprogress.h"
|
|
30
|
|
31 struct gaim_gtkxfer_dialog
|
|
32 {
|
|
33 GtkWidget *window;
|
|
34 GtkWidget *tree;
|
|
35 GtkListStore *model;
|
|
36 };
|
|
37
|
|
38 struct gaim_gtkxfer_ui_data
|
|
39 {
|
|
40 GtkWidget *filesel;
|
|
41 GtkTreeIter iter;
|
|
42 time_t start_time;
|
|
43
|
|
44 char *name;
|
|
45 };
|
|
46
|
|
47 static struct gaim_gtkxfer_dialog *xfer_dialog = NULL;
|
|
48
|
|
49 enum
|
|
50 {
|
|
51 COLUMN_STATUS = 0,
|
|
52 COLUMN_USER,
|
|
53 COLUMN_FILENAME,
|
|
54 COLUMN_PROGRESS,
|
|
55 COLUMN_SIZE,
|
|
56 COLUMN_REMAINING,
|
|
57 COLUMN_ESTIMATE,
|
|
58 COLUMN_SPEED,
|
|
59 NUM_COLUMNS
|
|
60 };
|
|
61
|
|
62 static gint
|
|
63 delete_win_cb(GtkWidget *w, GdkEventAny *e, gpointer d)
|
|
64 {
|
|
65 gaim_gtkxfer_dialog_hide();
|
|
66
|
|
67 return TRUE;
|
|
68 }
|
|
69
|
|
70 static void
|
|
71 close_win_cb(GtkButton *button, gpointer user_data)
|
|
72 {
|
|
73 gaim_gtkxfer_dialog_hide();
|
|
74 }
|
|
75
|
|
76 static struct gaim_gtkxfer_dialog *
|
|
77 build_xfer_dialog(void)
|
|
78 {
|
|
79 struct gaim_gtkxfer_dialog *dialog;
|
|
80 GtkWidget *window;
|
|
81 GtkWidget *vbox;
|
|
82 GtkWidget *hbox;
|
|
83 GtkWidget *frame;
|
|
84 GtkWidget *sw;
|
|
85 GtkWidget *sep;
|
|
86 GtkWidget *button;
|
|
87 GtkWidget *tree;
|
|
88 GtkTreeViewColumn *column;
|
|
89 GtkListStore *model;
|
|
90 GtkCellRenderer *renderer;
|
|
91 GtkSizeGroup *sg;
|
|
92
|
|
93 dialog = g_malloc0(sizeof(struct gaim_gtkxfer_dialog));
|
|
94
|
|
95 /* Create the window. */
|
|
96 dialog->window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
97 gtk_window_set_role(GTK_WINDOW(window), "file transfer");
|
|
98 gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
|
|
99 gtk_window_set_default_size(GTK_WINDOW(window), 550, 250);
|
|
100 gtk_container_border_width(GTK_CONTAINER(window), 0);
|
|
101 gtk_widget_realize(window);
|
|
102
|
|
103 g_signal_connect(G_OBJECT(window), "delete_event",
|
|
104 G_CALLBACK(delete_win_cb), dialog);
|
|
105
|
|
106 /* Create the parent vbox for everything. */
|
|
107 vbox = gtk_vbox_new(FALSE, 6);
|
|
108 gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
|
|
109 gtk_container_add(GTK_CONTAINER(window), vbox);
|
|
110 gtk_widget_show(vbox);
|
|
111
|
|
112 /* Create the scrolled window. */
|
|
113 sw = gtk_scrolled_window_new(0, 0);
|
|
114 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
|
|
115 GTK_POLICY_AUTOMATIC,
|
|
116 GTK_POLICY_ALWAYS);
|
|
117 gtk_widget_show(sw);
|
|
118
|
|
119 /* Build the tree model */
|
|
120 /* Transfer type, User, Filename, Progress Bar, Size, Remaining */
|
|
121 dialog->model = model = gtk_list_store_new(NUM_COLUMNS,
|
|
122 GDK_TYPE_PIXBUF, G_TYPE_STRING,
|
|
123 G_TYPE_STRING, G_TYPE_DOUBLE,
|
|
124 G_TYPE_LONG, G_TYPE_LONG,
|
|
125 G_TYPE_STRING, G_TYPE_STRING);
|
|
126
|
|
127 /* Create the treeview */
|
|
128 dialog->tree = tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
|
129 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree), TRUE);
|
|
130 gtk_tree_selection_set_mode(
|
|
131 gtk_tree_view_get_selection(GTK_TREE_VIEW(tree)),
|
|
132 GTK_SELECTION_MULTIPLE);
|
|
133 gtk_widget_show(tree);
|
|
134
|
|
135 g_object_unref(G_OBJECT(model));
|
|
136
|
|
137
|
|
138 /* Columns */
|
|
139
|
|
140 /* Transfer Type column */
|
|
141 renderer = gtk_cell_renderer_pixbuf_new();
|
|
142 column = gtk_tree_view_column_new_with_attributes(NULL, renderer,
|
|
143 "pixbuf", COLUMN_STATUS, NULL);
|
|
144 gtk_tree_view_column_set_sizing(GTK_TREE_VIEW_COLUMN(column),
|
|
145 GTK_TREE_VIEW_COLUMN_FIXED);
|
|
146 gtk_tree_view_column_set_fixed_width(GTK_TREE_VIEW_COLUMN(column), 25);
|
|
147 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
148 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
149
|
|
150 /* User column */
|
|
151 renderer = gtk_cell_renderer_text_new();
|
|
152 column = gtk_tree_view_column_new_with_attributes(_("User"), renderer,
|
|
153 "text", COLUMN_USER, NULL);
|
|
154 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
155 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
156
|
|
157 /* Filename column */
|
|
158 renderer = gtk_cell_renderer_text_new();
|
|
159 column = gtk_tree_view_column_new_with_attributes(_("Filename"), renderer,
|
|
160 "text", COLUMN_FILENAME, NULL);
|
|
161 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
162 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
163
|
|
164 /* Progress bar column */
|
|
165 renderer = gtk_cell_renderer_progress_new();
|
|
166 column = gtk_tree_view_column_new_with_attributes(_("Progress"), renderer,
|
|
167 "percentage", COLUMN_PROGRESS, NULL);
|
|
168 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
169 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
170
|
|
171 /* File Size column */
|
|
172 renderer = gtk_cell_renderer_text_new();
|
|
173 column = gtk_tree_view_column_new_with_attributes(_("Size"), renderer,
|
|
174 "text", COLUMN_SIZE, NULL);
|
|
175 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
176 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
177
|
|
178 /* Bytes Remaining column */
|
|
179 renderer = gtk_cell_renderer_text_new();
|
|
180 column = gtk_tree_view_column_new_with_attributes(_("Remaining"),
|
|
181 renderer, "text", COLUMN_REMAINING, NULL);
|
|
182 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
183 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
184
|
|
185 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree));
|
|
186
|
|
187 /* ETA column */
|
|
188 renderer = gtk_cell_renderer_text_new();
|
|
189 column = gtk_tree_view_column_new_with_attributes(_("ETA"),
|
|
190 renderer, "text", COLUMN_ESTIMATE, NULL);
|
|
191 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
192 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
193
|
|
194 /* Speed column */
|
|
195 renderer = gtk_cell_renderer_text_new();
|
|
196 column = gtk_tree_view_column_new_with_attributes(_("Speed"),
|
|
197 renderer, "text", COLUMN_SPEED, NULL);
|
|
198 gtk_tree_view_column_set_resizable(GTK_TREE_VIEW_COLUMN(column), TRUE);
|
|
199 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
|
|
200
|
|
201 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree));
|
|
202
|
|
203 gtk_container_add(GTK_CONTAINER(sw), tree);
|
|
204 gtk_widget_show(tree);
|
|
205
|
|
206 /* Create the outer frame for the scrolled window. */
|
|
207 frame = gtk_frame_new(NULL),
|
|
208 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
|
|
209 gtk_container_add(GTK_CONTAINER(frame), sw);
|
|
210 gtk_widget_show(frame);
|
|
211
|
|
212 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
|
|
213
|
|
214 /* Separator */
|
|
215 sep = gtk_hseparator_new();
|
|
216 gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
|
|
217 gtk_widget_show(sep);
|
|
218
|
|
219 /* Now the hbox for the buttons */
|
|
220 hbox = gtk_hbox_new(FALSE, 6);
|
|
221 gtk_container_set_border_width(GTK_CONTAINER(hbox), 6);
|
|
222 gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
|
|
223 gtk_widget_show(hbox);
|
|
224
|
|
225 sg = gtk_size_group_new(GTK_SIZE_GROUP_BOTH);
|
|
226
|
|
227 /* Close button */
|
|
228 button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
|
|
229 g_signal_connect(G_OBJECT(button), "clicked",
|
|
230 G_CALLBACK(close_win_cb), NULL);
|
|
231 gtk_size_group_add_widget(sg, button);
|
|
232 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
|
|
233 gtk_widget_show(button);
|
|
234
|
|
235 #if 0
|
|
236 /* Cancel button */
|
|
237 button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
|
|
238 gtk_size_group_add_widget(sg, button);
|
|
239 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 0);
|
|
240 gtk_widget_show(button);
|
|
241 #endif
|
|
242
|
|
243 return dialog;
|
|
244 }
|
|
245
|
|
246 static void
|
|
247 gaim_gtkxfer_destroy(struct gaim_xfer *xfer)
|
|
248 {
|
|
249 struct gaim_gtkxfer_ui_data *data;
|
|
250
|
|
251 data = xfer->ui_data;
|
|
252
|
|
253 if (data == NULL)
|
|
254 return;
|
|
255 }
|
|
256
|
|
257 static gboolean
|
|
258 choose_file_close_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
|
259 {
|
|
260 gaim_xfer_request_denied((struct gaim_xfer *)user_data);
|
|
261
|
|
262 return FALSE;
|
|
263 }
|
|
264
|
|
265 static void
|
|
266 choose_file_cancel_cb(GtkButton *button, gpointer user_data)
|
|
267 {
|
|
268 struct gaim_xfer *xfer = (struct gaim_xfer *)user_data;
|
|
269 struct gaim_gtkxfer_ui_data *data;
|
|
270
|
|
271 data = (struct gaim_gtkxfer_ui_data *)xfer->ui_data;
|
|
272
|
|
273 gaim_xfer_request_denied(xfer);
|
|
274
|
|
275 gtk_widget_destroy(data->filesel);
|
|
276 data->filesel = NULL;
|
|
277 }
|
|
278
|
|
279 static int
|
|
280 do_overwrite_cb(struct gaim_xfer *xfer)
|
|
281 {
|
|
282 struct gaim_gtkxfer_ui_data *data;
|
|
283
|
|
284 data = (struct gaim_gtkxfer_ui_data *)xfer->ui_data;
|
|
285
|
|
286 gaim_xfer_request_accepted(xfer, data->name);
|
|
287
|
|
288 /*
|
|
289 * No, we don't want to free data->name. gaim_xfer_request_accepted
|
|
290 * will deal with it.
|
|
291 */
|
|
292 data->name = NULL;
|
|
293
|
|
294 return 0;
|
|
295 }
|
|
296
|
|
297 static int
|
|
298 dont_overwrite_cb(struct gaim_xfer *xfer)
|
|
299 {
|
|
300 struct gaim_gtkxfer_ui_data *data;
|
|
301
|
|
302 data = (struct gaim_gtkxfer_ui_data *)xfer->ui_data;
|
|
303
|
|
304 g_free(data->name);
|
|
305 data->name = NULL;
|
|
306
|
|
307 gaim_xfer_request_denied(xfer);
|
|
308
|
|
309 return 0;
|
|
310 }
|
|
311
|
|
312 static void
|
|
313 choose_file_ok_cb(GtkButton *button, gpointer user_data)
|
|
314 {
|
|
315 struct gaim_xfer *xfer;
|
|
316 struct gaim_gtkxfer_ui_data *data;
|
|
317 struct stat st;
|
|
318 const char *name;
|
|
319
|
|
320 xfer = (struct gaim_xfer *)user_data;
|
|
321 data = (struct gaim_gtkxfer_ui_data *)xfer->ui_data;
|
|
322
|
|
323 name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(data->filesel));
|
|
324
|
|
325 if (stat(name, &st) == 0) {
|
|
326 if (S_ISDIR(st.st_mode)) {
|
|
327 /* XXX */
|
|
328 gaim_xfer_request_denied(xfer);
|
|
329 }
|
|
330 else if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
|
|
331 data->name = g_strdup(name);
|
|
332
|
|
333 do_ask_dialog(_("That file already exists. "
|
|
334 "Would you like to overwrite it?"),
|
|
335 NULL, xfer,
|
|
336 _("Yes"), do_overwrite_cb,
|
|
337 _("No"), dont_overwrite_cb,
|
|
338 NULL, FALSE);
|
|
339 }
|
|
340 else {
|
|
341 gaim_xfer_request_accepted(xfer, g_strdup(name));
|
|
342 }
|
|
343 }
|
|
344 else {
|
|
345 /* File not found. */
|
|
346 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE) {
|
|
347 gaim_xfer_request_accepted(xfer, g_strdup(name));
|
|
348 }
|
|
349 else {
|
|
350 do_error_dialog(_("That file does not exist."),
|
|
351 NULL, GAIM_ERROR);
|
|
352
|
|
353 gaim_xfer_request_denied(xfer);
|
|
354 }
|
|
355 }
|
|
356
|
|
357 gtk_widget_destroy(data->filesel);
|
|
358 data->filesel = NULL;
|
|
359 }
|
|
360
|
|
361 static int
|
|
362 choose_file(struct gaim_xfer *xfer)
|
|
363 {
|
|
364 char *cur_dir, *init_str;
|
|
365 struct gaim_gtkxfer_ui_data *data;
|
|
366
|
|
367 cur_dir = g_get_current_dir();
|
|
368
|
|
369 /* This is where we're setting xfer->ui_data for the first time. */
|
|
370 data = g_malloc0(sizeof(struct gaim_gtkxfer_ui_data));
|
|
371 xfer->ui_data = data;
|
|
372
|
|
373 if (gaim_xfer_get_type(xfer) == GAIM_XFER_SEND)
|
|
374 data->filesel = gtk_file_selection_new(_("Gaim - Open..."));
|
|
375 else
|
|
376 data->filesel = gtk_file_selection_new(_("Gaim - Save As..."));
|
|
377
|
|
378 if (gaim_xfer_get_filename(xfer) == NULL)
|
|
379 init_str = g_strdup(cur_dir);
|
|
380 else
|
|
381 init_str = g_build_filename(cur_dir, gaim_xfer_get_filename(xfer),
|
|
382 NULL);
|
|
383
|
|
384 g_free(cur_dir);
|
|
385
|
|
386 gtk_file_selection_set_filename(GTK_FILE_SELECTION(data->filesel),
|
|
387 init_str);
|
|
388
|
|
389 g_free(init_str);
|
|
390
|
|
391 g_signal_connect(G_OBJECT(data->filesel), "delete_event",
|
|
392 G_CALLBACK(choose_file_close_cb), xfer);
|
|
393 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(data->filesel)->cancel_button),
|
|
394 "clicked",
|
|
395 G_CALLBACK(choose_file_cancel_cb), xfer);
|
|
396 g_signal_connect(G_OBJECT(GTK_FILE_SELECTION(data->filesel)->ok_button),
|
|
397 "clicked",
|
|
398 G_CALLBACK(choose_file_ok_cb), xfer);
|
|
399
|
|
400 gtk_widget_show(data->filesel);
|
|
401
|
|
402 return 0;
|
|
403 }
|
|
404
|
|
405 static int
|
|
406 cancel_recv_cb(struct gaim_xfer *xfer)
|
|
407 {
|
|
408 gaim_xfer_request_denied(xfer);
|
|
409
|
|
410 return 0;
|
|
411 }
|
|
412
|
|
413 static void
|
|
414 gaim_gtkxfer_ask_recv(struct gaim_xfer *xfer)
|
|
415 {
|
|
416 static const char *size_str[4] = { "bytes", "KB", "MB", "GB" };
|
|
417 char *buf;
|
|
418 char *size_buf;
|
|
419 float size_mag;
|
|
420 size_t size;
|
|
421 int size_index = 0;
|
|
422
|
|
423 size = gaim_xfer_get_size(xfer);
|
|
424 size_mag = (float)size;
|
|
425
|
|
426 while ((size_index < 4) && (size_mag > 1024)) {
|
|
427 size_mag /= 1024;
|
|
428 size_index++;
|
|
429 }
|
|
430
|
|
431 if (size == -1)
|
|
432 size_buf = g_strdup_printf(_("Unknown size"));
|
|
433 else
|
|
434 size_buf = g_strdup_printf("%.3g %s", size_mag, size_str[size_index]);
|
|
435
|
|
436 buf = g_strdup_printf(_("%s wants to send you %s (%s)"),
|
|
437 xfer->who, gaim_xfer_get_filename(xfer), size_buf);
|
|
438
|
|
439 g_free(size_buf);
|
|
440
|
|
441 do_ask_dialog(buf, NULL, xfer,
|
|
442 _("Accept"), choose_file,
|
|
443 _("Cancel"), cancel_recv_cb,
|
|
444 NULL, FALSE);
|
|
445
|
|
446 g_free(buf);
|
|
447 }
|
|
448
|
|
449 static void
|
|
450 gaim_gtkxfer_request_file(struct gaim_xfer *xfer)
|
|
451 {
|
|
452 if (gaim_xfer_get_type(xfer) == GAIM_XFER_RECEIVE)
|
|
453 {
|
|
454 gaim_gtkxfer_ask_recv(xfer);
|
|
455 }
|
|
456 else
|
|
457 {
|
|
458 choose_file(xfer);
|
|
459 }
|
|
460 }
|
|
461
|
|
462 static void
|
|
463 gaim_gtkxfer_ask_cancel(struct gaim_xfer *xfer)
|
|
464 {
|
|
465 }
|
|
466
|
|
467 static void
|
|
468 gaim_gtkxfer_add_xfer(struct gaim_xfer *xfer)
|
|
469 {
|
|
470 struct gaim_gtkxfer_ui_data *data;
|
|
471 GaimXferType type;
|
|
472 GdkPixbuf *pixbuf;
|
|
473
|
|
474 data = (struct gaim_gtkxfer_ui_data *)xfer->ui_data;
|
|
475
|
|
476 gaim_gtkxfer_dialog_show();
|
|
477
|
|
478 data->start_time = time(NULL);
|
|
479
|
|
480 type = gaim_xfer_get_type(xfer);
|
|
481
|
|
482 pixbuf = gtk_widget_render_icon(xfer_dialog->window,
|
|
483 (type == GAIM_XFER_RECEIVE
|
|
484 ? GAIM_STOCK_DOWNLOAD
|
|
485 : GAIM_STOCK_UPLOAD),
|
|
486 GTK_ICON_SIZE_MENU, NULL);
|
|
487
|
|
488 gtk_list_store_append(xfer_dialog->model, &data->iter);
|
|
489 gtk_list_store_set(xfer_dialog->model, &data->iter,
|
|
490 COLUMN_STATUS, pixbuf,
|
|
491 COLUMN_USER, xfer->who,
|
|
492 COLUMN_FILENAME, gaim_xfer_get_filename(xfer),
|
|
493 COLUMN_PROGRESS, 0.0,
|
|
494 COLUMN_SIZE, gaim_xfer_get_size(xfer),
|
|
495 COLUMN_REMAINING, gaim_xfer_get_bytes_remaining(xfer),
|
|
496 COLUMN_ESTIMATE, NULL,
|
|
497 COLUMN_SPEED, NULL,
|
|
498 -1);
|
|
499
|
|
500 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(xfer_dialog->tree));
|
|
501
|
|
502 g_object_unref(pixbuf);
|
|
503 }
|
|
504
|
|
505 static void
|
|
506 gaim_gtkxfer_update_progress(struct gaim_xfer *xfer, double percent)
|
|
507 {
|
|
508 struct gaim_gtkxfer_ui_data *data;
|
|
509 time_t now;
|
|
510 char speed_buf[256];
|
|
511 char estimate_buf[256];
|
|
512 double kb_sent, kb_rem;
|
|
513 double kbps = 0.0;
|
|
514 time_t elapsed;
|
|
515 int secs_remaining;
|
|
516
|
|
517 data = (struct gaim_gtkxfer_ui_data *)xfer->ui_data;
|
|
518
|
|
519 now = time(NULL);
|
|
520 kb_rem = gaim_xfer_get_bytes_remaining(xfer) / 1024.0;
|
|
521 kb_sent = gaim_xfer_get_bytes_sent(xfer) / 1024.0;
|
|
522 elapsed = (now - data->start_time);
|
|
523 kbps = (elapsed > 0 ? (kb_sent / elapsed) : 0);
|
|
524
|
|
525 secs_remaining = (int)(kb_rem / kbps);
|
|
526
|
|
527 if (secs_remaining <= 0) {
|
|
528 GdkPixbuf *pixbuf = NULL;
|
|
529
|
|
530 *speed_buf = '\0';
|
|
531 strncpy(estimate_buf, _("Done."), sizeof(estimate_buf));
|
|
532
|
|
533 pixbuf = gtk_widget_render_icon(xfer_dialog->window,
|
|
534 GAIM_STOCK_FILE_DONE,
|
|
535 GTK_ICON_SIZE_MENU, NULL);
|
|
536
|
|
537 gtk_list_store_set(xfer_dialog->model, &data->iter,
|
|
538 COLUMN_STATUS, pixbuf,
|
|
539 -1);
|
|
540
|
|
541 g_object_unref(pixbuf);
|
|
542 }
|
|
543 else {
|
|
544 int h = secs_remaining / 3600;
|
|
545 int m = (secs_remaining % 3600) / 60;
|
|
546 int s = secs_remaining % 60;
|
|
547
|
|
548 g_snprintf(estimate_buf, sizeof(estimate_buf),
|
|
549 _("%d:%02d:%02d"), h, m, s);
|
|
550 g_snprintf(speed_buf, sizeof(speed_buf),
|
|
551 _("%.2f KB/s"), kbps);
|
|
552 }
|
|
553
|
|
554 gtk_list_store_set(xfer_dialog->model, &data->iter,
|
|
555 COLUMN_REMAINING, gaim_xfer_get_bytes_remaining(xfer),
|
|
556 COLUMN_PROGRESS, percent,
|
|
557 COLUMN_ESTIMATE, estimate_buf,
|
|
558 COLUMN_SPEED, speed_buf,
|
|
559 -1);
|
|
560 }
|
|
561
|
|
562 static void
|
|
563 gaim_gtkxfer_cancel(struct gaim_xfer *xfer)
|
|
564 {
|
|
565 struct gaim_gtkxfer_ui_data *data;
|
|
566 GdkPixbuf *pixbuf;
|
|
567
|
|
568 data = (struct gaim_gtkxfer_ui_data *)xfer->ui_data;
|
|
569
|
|
570 pixbuf = gtk_widget_render_icon(xfer_dialog->window,
|
|
571 GAIM_STOCK_FILE_CANCELED,
|
|
572 GTK_ICON_SIZE_MENU, NULL);
|
|
573
|
|
574 gtk_list_store_set(xfer_dialog->model, &data->iter,
|
|
575 COLUMN_STATUS, pixbuf,
|
|
576 -1);
|
|
577
|
|
578 g_object_unref(pixbuf);
|
|
579 }
|
|
580
|
|
581 struct gaim_xfer_ui_ops ops =
|
|
582 {
|
|
583 gaim_gtkxfer_destroy,
|
|
584 gaim_gtkxfer_request_file,
|
|
585 gaim_gtkxfer_ask_cancel,
|
|
586 gaim_gtkxfer_add_xfer,
|
|
587 gaim_gtkxfer_update_progress,
|
|
588 gaim_gtkxfer_cancel
|
|
589 };
|
|
590
|
|
591 void
|
|
592 gaim_gtkxfer_dialog_show(void)
|
|
593 {
|
|
594 if (xfer_dialog == NULL)
|
|
595 xfer_dialog = build_xfer_dialog();
|
|
596
|
|
597 gtk_widget_show(xfer_dialog->window);
|
|
598 }
|
|
599
|
|
600 void
|
|
601 gaim_gtkxfer_dialog_hide(void)
|
|
602 {
|
|
603 gtk_widget_hide(xfer_dialog->window);
|
|
604 }
|
|
605
|
|
606 struct gaim_xfer_ui_ops *
|
|
607 gaim_get_gtk_xfer_ui_ops(void)
|
|
608 {
|
|
609 return &ops;
|
|
610 }
|