source: branches/oneport/gtk/prefs.c @ 40

Last change on this file since 40 was 40, checked in by joshe, 16 years ago

More random debug stuff, also actually change the port right away via the gtk prefs.

File size: 13.5 KB
Line 
1/*
2  Copyright (c) 2005 Joshua Elsasser. All rights reserved.
3   
4  Redistribution and use in source and binary forms, with or without
5  modification, are permitted provided that the following conditions
6  are met:
7   
8   1. Redistributions of source code must retain the above copyright
9      notice, this list of conditions and the following disclaimer.
10   2. Redistributions in binary form must reproduce the above copyright
11      notice, this list of conditions and the following disclaimer in the
12      documentation and/or other materials provided with the distribution.
13   
14  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
15  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  POSSIBILITY OF SUCH DAMAGE.
25*/
26
27#include <assert.h>
28#include <errno.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <gtk/gtk.h>
33
34#include "conf.h"
35#include "prefs.h"
36#include "transmission.h"
37#include "util.h"
38
39struct prefdata {
40  GtkSpinButton *port;
41  GtkCheckButton *uselimit;
42  GtkSpinButton *limit;
43  GtkEntry *dir;
44  GtkWindow *parent;
45  tr_handle_t *tr;
46};
47
48struct addcb {
49  add_torrent_func_t addfunc;
50  GtkWindow *parent;
51  tr_handle_t *tr;
52  torrents_added_func_t donefunc;
53  void *donedata;
54  gboolean autostart;
55  gboolean usingaltdir;
56  GtkFileChooser *altdir;
57  GtkButtonBox *altbox;
58};
59
60static void
61clicklimitbox(GtkWidget *widget, gpointer gdata);
62static void
63clickdialog(GtkWidget *widget, int resp, gpointer gdata);
64static void
65autoclick(GtkWidget *widget, gpointer gdata);
66static void
67dirclick(GtkWidget *widget, gpointer gdata);
68static void
69addresp(GtkWidget *widget, gint resp, gpointer gdata);
70
71void
72makeprefwindow(GtkWindow *parent, tr_handle_t *tr) {
73  GtkWidget *wind = gtk_dialog_new_with_buttons("Preferences", parent,
74    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK,
75    GTK_RESPONSE_OK, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
76  GtkWidget *table = gtk_table_new(4, 2, FALSE);
77  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
78  GtkWidget *limitbox = gtk_check_button_new_with_label("Limit upload speed");
79  GtkWidget *limitnum = gtk_spin_button_new_with_range(0, G_MAXLONG, 1);
80  GtkWidget *dirstr = gtk_entry_new();
81  GtkWidget *label;
82  const char *pref;
83  struct prefdata *data = g_new0(struct prefdata, 1);
84
85  data->port = GTK_SPIN_BUTTON(portnum);
86  data->uselimit = GTK_CHECK_BUTTON(limitbox);
87  data->limit = GTK_SPIN_BUTTON(limitnum);
88  data->dir = GTK_ENTRY(dirstr);
89  data->parent = parent;
90  data->tr = tr;
91
92  /* port label and entry */
93  label = gtk_label_new("Listening port");
94  if(NULL != (pref = cf_getpref(PREF_PORT)))
95    gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum), strtol(pref,NULL,10));
96  else
97    gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum), TR_DEFAULT_PORT);
98  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 0, 1);
99  gtk_table_attach_defaults(GTK_TABLE(table), portnum,          1, 2, 0, 1);
100
101  /* limit checkbox */
102  pref = cf_getpref(PREF_USELIMIT);
103  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(limitbox),
104    (NULL == pref ? TRUE : strbool(pref)));
105  gtk_widget_set_sensitive(limitnum,
106    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(limitbox)));
107  g_signal_connect(G_OBJECT(limitbox), "clicked",
108                   G_CALLBACK(clicklimitbox), limitnum);
109  gtk_table_attach_defaults(GTK_TABLE(table), limitbox,         0, 2, 1, 2);
110
111  /* limit label and entry */
112  label = gtk_label_new("Maximum upload speed");
113  pref = cf_getpref(PREF_LIMIT);
114  gtk_spin_button_set_value(GTK_SPIN_BUTTON(limitnum),
115    (NULL == pref ? DEFAULT_UPLIMIT : strtol(pref,NULL,10)));
116  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 2, 3);
117  gtk_table_attach_defaults(GTK_TABLE(table), limitnum,         1, 2, 2, 3);
118
119  /* directory label and entry */
120  label = gtk_label_new("Download directory");
121  if(NULL != (pref = cf_getpref(PREF_DIR)))
122    gtk_entry_set_text(GTK_ENTRY(dirstr), pref);
123  gtk_table_attach_defaults(GTK_TABLE(table), label,            0, 1, 3, 4);
124  gtk_table_attach_defaults(GTK_TABLE(table), dirstr,           1, 2, 3, 4);
125
126  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
127  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(clickdialog), data);
128  gtk_widget_show_all(wind);
129}
130
131static void
132clicklimitbox(GtkWidget *widget, gpointer gdata) {
133  GtkWidget *entry = gdata;
134
135  gtk_widget_set_sensitive(entry,
136    gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
137}
138
139static void
140clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
141  struct prefdata *data = gdata;
142  int intval;
143  const char *strval;
144  char *strnum, *errstr;
145  gboolean boolval;
146
147  if(GTK_RESPONSE_OK == resp) {
148    /* check directory */
149    strval = gtk_entry_get_text(data->dir);
150    if('\0' != strval[0] &&!mkdir_p(strval, 0777)) {
151      errmsg(data->parent, "Failed to create directory %s:\n%s",
152             strval, strerror(errno));
153      return;
154    }
155
156    /* save dir pref */
157    cf_setpref(PREF_DIR, gtk_entry_get_text(data->dir), NULL);
158
159    /* save port pref */
160    strnum = g_strdup_printf("%i",
161      gtk_spin_button_get_value_as_int(data->port));
162    cf_setpref(PREF_PORT, strnum, NULL);
163    g_free(strnum);
164
165    /* save uselimit pref */
166    boolval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->uselimit));
167    cf_setpref(PREF_USELIMIT, (boolval ? "yes" : "no"), NULL);
168
169    /* save limit pref */
170    intval = gtk_spin_button_get_value_as_int(data->limit);
171    strnum = g_strdup_printf("%i", intval);
172    /*
173      note that prefs aren't written to disk unless we pass a pointer
174      to an error string, so do this for the last call to cf_setpref()
175    */
176    if(!cf_setpref(PREF_LIMIT, strnum, &errstr)) {
177      errmsg(data->parent, "%s", errstr);
178      g_free(strnum);
179      g_free(errstr);
180    }
181
182    tr_setBindPort(data->tr, gtk_spin_button_get_value_as_int(data->port));
183    setlimit(data->tr);
184  }
185
186  gtk_widget_destroy(widget);
187  g_free(data);
188}
189
190void
191setlimit(tr_handle_t *tr) {
192  const char *pref;
193
194  if(NULL != (pref = cf_getpref(PREF_USELIMIT)) && !strbool(pref))
195    tr_setUploadLimit(tr, -1);
196  else if(NULL != (pref = cf_getpref(PREF_LIMIT)))
197    tr_setUploadLimit(tr, strtol(pref, NULL, 10));
198  else
199    tr_setUploadLimit(tr, DEFAULT_UPLIMIT);
200}
201
202void
203makeaddwind(add_torrent_func_t addfunc, GtkWindow *parent, tr_handle_t *tr,
204            torrents_added_func_t donefunc, void *donedata) {
205  GtkWidget *wind = gtk_file_chooser_dialog_new("Add a Torrent", parent,
206    GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
207    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
208  struct addcb *data = g_new(struct addcb, 1);
209  GtkWidget *vbox = gtk_vbox_new(FALSE, 5);
210  GtkWidget *bbox = gtk_hbutton_box_new();
211  GtkWidget *autocheck = gtk_check_button_new_with_label(
212    "Automatically start torrent");
213  GtkWidget *dircheck = gtk_check_button_new_with_label(
214    "Use alternate download directory");
215  GtkFileFilter *filter = gtk_file_filter_new();
216  GtkFileFilter *unfilter = gtk_file_filter_new();
217  GtkWidget *getdir = gtk_file_chooser_button_new(
218    "Choose a download directory", GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
219  const char *pref;
220
221  data->addfunc = addfunc;
222  data->parent = parent;
223  data->tr = tr;
224  data->donefunc = donefunc;
225  data->donedata = donedata;
226  data->autostart = TRUE;
227  data->usingaltdir = FALSE;
228  data->altdir = GTK_FILE_CHOOSER(getdir);
229  data->altbox = GTK_BUTTON_BOX(bbox);
230
231  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_START);
232  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
233  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
234
235  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
236  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
237
238  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
239  if(NULL != (pref = cf_getpref(PREF_DIR)))
240    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
241  else {
242    pref = g_get_current_dir();
243    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
244    g_free((char*)pref);
245  }
246
247  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
248
249  gtk_file_filter_set_name(filter, "Torrent files");
250  gtk_file_filter_add_pattern(filter, "*.torrent");
251  gtk_file_filter_set_name(unfilter, "All files");
252  gtk_file_filter_add_pattern(unfilter, "*");
253
254  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
255  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
256  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
257  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
258
259  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
260  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
261  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
262
263  gtk_widget_show_all(wind);
264  gtk_widget_hide(getdir);
265}
266
267static void
268autoclick(GtkWidget *widget, gpointer gdata) {
269  struct addcb *data = gdata;
270
271  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
272}
273
274static void
275dirclick(GtkWidget *widget, gpointer gdata) {
276  struct addcb *data = gdata;
277
278  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
279  gtk_button_box_set_layout(data->altbox,
280    (data->usingaltdir ? GTK_BUTTONBOX_EDGE : GTK_BUTTONBOX_START));
281  if(data->usingaltdir)
282    gtk_widget_show(GTK_WIDGET(data->altdir));
283  else
284    gtk_widget_hide(GTK_WIDGET(data->altdir));
285}
286
287static void
288addresp(GtkWidget *widget, gint resp, gpointer gdata) {
289  struct addcb *data = gdata;
290  GSList *files, *ii;
291  gboolean added = FALSE;
292  char *dir = NULL;
293
294  if(GTK_RESPONSE_ACCEPT == resp) {
295    if(data->usingaltdir)
296      dir = gtk_file_chooser_get_filename(data->altdir);
297    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
298    for(ii = files; NULL != ii; ii = ii->next)
299      if(data->addfunc(data->tr, data->parent, ii->data, dir,
300                       !data->autostart))
301        added = TRUE;
302    if(added)
303      data->donefunc(data->donedata);
304    if(NULL != dir)
305      g_free(dir);
306  }
307
308  gtk_widget_destroy(widget);
309}
310
311#define INFOLINE(tab, ii, nam, val) \
312  do { \
313    GtkWidget *wid = gtk_label_new(NULL); \
314    gtk_misc_set_alignment(GTK_MISC(wid), 1, .5); \
315    gtk_label_set_markup(GTK_LABEL(wid), "<b>" nam ":</b>"); \
316    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 1, ii, ii + 1); \
317    wid = gtk_label_new(val); \
318    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
319    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 1, 2, ii, ii + 1); \
320    ii++; \
321  } while(0);
322
323#define INFOLINEF(tab, ii, fmt, nam, val) \
324  do { \
325    char *buf = g_strdup_printf(fmt, val); \
326    INFOLINE(tab, ii, nam, buf); \
327    g_free(buf); \
328  } while(0);
329
330#define INFOLINEA(tab, ii, nam, val) \
331  do { \
332    char *buf = val; \
333    INFOLINE(tab, ii, nam, buf); \
334    g_free(buf); \
335  } while(0);
336
337#define INFOSEP(tab, ii) \
338  do { \
339    GtkWidget *wid = gtk_hseparator_new(); \
340    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 2, ii, ii + 1); \
341    ii++; \
342  } while(0);
343
344#define INFOSTATUS(st) \
345  (TR_STATUS_CHECK    & (st) ? "check" : \
346  (TR_STATUS_DOWNLOAD & (st) ? "download" : \
347  (TR_STATUS_SEED     & (st) ? "seed" : \
348  (TR_STATUS_STOPPING & (st) ? "stopping" : \
349  (TR_STATUS_STOPPED  & (st) ? "stopped" : \
350  (TR_STATUS_PAUSE    & (st) ? "pause" : \
351  "???"))))))
352
353void
354makeinfowind(GtkWindow *parent, tr_handle_t *tr, int id) {
355  tr_stat_t *sb;
356  GtkWidget *wind, *table, *label;
357  int ii;
358  char *str;
359  const int rowcount = 11;
360
361  /* XXX would be nice to be able to stat just one */
362  if(id >= tr_torrentStat(tr, &sb))
363    assert(!"XXX ");
364  str = g_strdup_printf("%s Properties", sb[id].info.name);
365  wind = gtk_dialog_new_with_buttons(str, parent,
366    GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
367  g_free(str);
368
369  table = gtk_table_new(rowcount, 2, FALSE);
370  gtk_table_set_col_spacings(GTK_TABLE(table), 10);
371  gtk_table_set_row_spacings(GTK_TABLE(table), 10);
372
373  label = gtk_label_new(NULL);
374  str = g_markup_printf_escaped("<big>%s</big>", sb[id].info.name);
375  gtk_label_set_markup(GTK_LABEL(label), str);
376  g_free(str);
377  gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
378
379  ii = 1;
380
381  INFOSEP(table, ii);
382
383  INFOLINEA(table, ii, "Tracker", g_strdup_printf("http://%s:%i",
384            sb[id].info.trackerAddress, sb[id].info.trackerPort));
385  INFOLINE(table, ii, "Announce", sb[id].info.trackerAnnounce);
386  INFOLINEA(table, ii, "Piece Size", readablesize(sb[id].info.pieceSize, 1));
387  INFOLINEF(table, ii, "%i", "Pieces", sb[id].info.pieceCount);
388  INFOLINEA(table, ii, "Total Size", readablesize(sb[id].info.totalSize, 1));
389
390  INFOSEP(table, ii);
391
392  INFOLINE(table, ii, "Directory", sb[id].folder);
393  INFOLINEA(table, ii, "Downloaded", readablesize(sb[id].downloaded, 1));
394  INFOLINEA(table, ii, "Uploaded", readablesize(sb[id].uploaded, 1));
395
396  assert(rowcount == ii);
397
398  gtk_container_set_border_width(GTK_CONTAINER(table), 10);
399  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
400  g_signal_connect(G_OBJECT(wind), "response",
401                   G_CALLBACK(gtk_widget_destroy), NULL);
402  gtk_widget_show_all(wind);
403  free(sb);
404}
Note: See TracBrowser for help on using the repository browser.