source: trunk/gtk/dialogs.c @ 261

Last change on this file since 261 was 261, checked in by titer, 16 years ago

Updated svn:keywords

  • Property svn:keywords set to Date Rev Author Id
File size: 17.2 KB
Line 
1/*
2  $Id: dialogs.c 261 2006-05-29 21:27:31Z titer $
3
4  Copyright (c) 2005-2006 Joshua Elsasser. All rights reserved.
5   
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions
8  are met:
9   
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   
16  THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS "AS IS" AND
17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  POSSIBILITY OF SUCH DAMAGE.
27*/
28
29#include <errno.h>
30#include <stdlib.h>
31#include <string.h>
32
33#include <gtk/gtk.h>
34#include <glib/gi18n.h>
35
36#include "conf.h"
37#include "dialogs.h"
38#include "transmission.h"
39#include "util.h"
40
41struct prefdata {
42  GtkSpinButton *port;
43  GtkCheckButton *use_dlimit;
44  GtkSpinButton *dlimit;
45  GtkCheckButton *use_ulimit;
46  GtkSpinButton *ulimit;
47  GtkFileChooser *dir;
48  GtkWindow *parent;
49  TrBackend *back;
50};
51
52struct addcb {
53  add_torrents_func_t addfunc;
54  GtkWindow *parent;
55  void *data;
56  gboolean autostart;
57  gboolean usingaltdir;
58  GtkFileChooser *altdir;
59  GtkButtonBox *altbox;
60};
61
62static void
63windclosed(GtkWidget *widget SHUTUP, gpointer gdata);
64static void
65clicklimitbox(GtkWidget *widget, gpointer gdata);
66static void
67freedata(gpointer gdata, GClosure *closure);
68static void
69clickdialog(GtkWidget *widget, int resp, gpointer gdata);
70static void
71autoclick(GtkWidget *widget, gpointer gdata);
72static void
73dirclick(GtkWidget *widget, gpointer gdata);
74static void
75addresp(GtkWidget *widget, gint resp, gpointer gdata);
76
77void
78makeprefwindow(GtkWindow *parent, TrBackend *back, gboolean *opened) {
79  char *title = g_strdup_printf(_("%s Preferences"), g_get_application_name());
80  GtkWidget *wind = gtk_dialog_new_with_buttons(title, parent,
81   GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
82   GTK_STOCK_APPLY, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
83   GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
84  const unsigned int rowcount = 6;
85  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
86  GtkWidget *portnum = gtk_spin_button_new_with_range(1, 0xffff, 1);
87  GtkWidget *dirstr = gtk_file_chooser_button_new(
88    _("Choose a download directory"),
89    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
90  GtkWidget *label;
91  GtkWidget **array;
92  const char *pref;
93  struct prefdata *data = g_new0(struct prefdata, 1);
94  struct { GtkWidget *on; GtkWidget *num; GtkWidget *label; gboolean defuse;
95    const char *usepref; const char *numpref; long def; } lim[] = {
96    { gtk_check_button_new_with_mnemonic(_("_Limit download speed")),
97      gtk_spin_button_new_with_range(0, G_MAXLONG, 1),
98      gtk_label_new_with_mnemonic(_("Maximum _download speed:")),
99      DEF_USEDOWNLIMIT, PREF_USEDOWNLIMIT, PREF_DOWNLIMIT, DEF_DOWNLIMIT, },
100    { gtk_check_button_new_with_mnemonic(_("Li_mit upload speed")),
101      gtk_spin_button_new_with_range(0, G_MAXLONG, 1),
102      gtk_label_new_with_mnemonic(_("Maximum _upload speed:")),
103      DEF_USEUPLIMIT, PREF_USEUPLIMIT, PREF_UPLIMIT, DEF_UPLIMIT, },
104  };
105  unsigned int ii;
106
107  *opened = TRUE;
108
109  g_free(title);
110  gtk_widget_set_name(wind, "TransmissionDialog");
111  gtk_table_set_col_spacings(GTK_TABLE(table), 8);
112  gtk_table_set_row_spacings(GTK_TABLE(table), 8);
113  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_OK);
114  gtk_container_set_border_width(GTK_CONTAINER(table), 6);
115  gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
116
117  data->port = GTK_SPIN_BUTTON(portnum);
118  data->use_dlimit = GTK_CHECK_BUTTON(lim[0].on);
119  data->dlimit = GTK_SPIN_BUTTON(lim[0].num);
120  data->use_ulimit = GTK_CHECK_BUTTON(lim[1].on);
121  data->ulimit = GTK_SPIN_BUTTON(lim[1].num);
122  data->dir = GTK_FILE_CHOOSER(dirstr);
123  data->parent = parent;
124  data->back = back;
125  g_object_ref(G_OBJECT(back));
126
127#define RN(n) (n), (n) + 1
128
129  for(ii = 0; ii < ALEN(lim); ii++) {
130    /* limit checkbox */
131    pref = cf_getpref(lim[ii].usepref);
132    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(lim[ii].on),
133      (NULL == pref ? lim[ii].defuse : strbool(pref)));
134    array = g_new(GtkWidget*, 2);
135    g_signal_connect_data(lim[ii].on, "clicked", G_CALLBACK(clicklimitbox),
136                          array, (GClosureNotify)g_free, 0);
137    gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].on,    0, 2, RN(ii*2));
138
139    /* limit label and entry */
140    gtk_label_set_mnemonic_widget(GTK_LABEL(lim[ii].label), lim[ii].num);
141    gtk_misc_set_alignment(GTK_MISC(lim[ii].label), 0, .5);
142    pref = cf_getpref(lim[ii].numpref);
143    gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(lim[ii].num), TRUE);
144    gtk_spin_button_set_value(GTK_SPIN_BUTTON(lim[ii].num),
145      (NULL == pref ? lim[ii].def : strtol(pref, NULL, 10)));
146    gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].label, 0,1,RN(ii*2+1));
147    gtk_table_attach_defaults(GTK_TABLE(table), lim[ii].num,   1,2,RN(ii*2+1));
148    array[0] = lim[ii].label;
149    array[1] = lim[ii].num;
150    clicklimitbox(lim[ii].on, array);
151  }
152  ii *= 2;
153
154  /* directory label and chooser */
155  label = gtk_label_new_with_mnemonic(_("Download di_rectory:"));
156  gtk_label_set_mnemonic_widget(GTK_LABEL(label), dirstr);
157  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
158  if(NULL != (pref = cf_getpref(PREF_DIR)))
159    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirstr), pref);
160  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
161  gtk_table_attach_defaults(GTK_TABLE(table), dirstr,          1, 2, RN(ii));
162  ii++;
163
164  /* port label and entry */
165  label = gtk_label_new_with_mnemonic(_("Listening _port:"));
166  gtk_label_set_mnemonic_widget(GTK_LABEL(label), portnum);
167  gtk_misc_set_alignment(GTK_MISC(label), 0, .5);
168  pref = cf_getpref(PREF_PORT);
169  gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(portnum), TRUE);
170  gtk_spin_button_set_value(GTK_SPIN_BUTTON(portnum),
171    (NULL == pref ? TR_DEFAULT_PORT : strtol(pref, NULL, 10)));
172  gtk_table_attach_defaults(GTK_TABLE(table), label,           0, 1, RN(ii));
173  gtk_table_attach_defaults(GTK_TABLE(table), portnum,         1, 2, RN(ii));
174  ii++;
175
176#undef RN
177  g_assert(rowcount == ii);
178
179  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
180  g_signal_connect_data(wind, "response", G_CALLBACK(clickdialog),
181                        data, freedata, 0);
182  g_signal_connect(wind, "destroy", G_CALLBACK(windclosed), opened);
183  gtk_widget_show_all(wind);
184}
185
186static void
187windclosed(GtkWidget *widget SHUTUP, gpointer gdata) {
188  gboolean *preachy_gcc = gdata;
189 
190  *preachy_gcc = FALSE;
191}
192
193static void
194clicklimitbox(GtkWidget *widget, gpointer gdata) {
195  GtkWidget **widgets = gdata;
196  int ii;
197
198  for(ii = 0; 2 > ii; ii++)
199    gtk_widget_set_sensitive(widgets[ii],
200      gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
201}
202
203static void
204freedata(gpointer gdata, GClosure *closure SHUTUP) {
205  struct prefdata *data = gdata;
206
207  g_object_unref(G_OBJECT(data->back));
208  g_free(data);
209}
210
211static void
212clickdialog(GtkWidget *widget, int resp, gpointer gdata) {
213  struct prefdata *data = gdata;
214  int intval;
215  const char *strval;
216  char *strnum, *errstr;
217  gboolean bval;
218
219  if(GTK_RESPONSE_APPLY == resp || GTK_RESPONSE_OK == resp) {
220    /* check directory */
221    if(NULL != (strval = gtk_file_chooser_get_current_folder(data->dir))) {
222      if(!mkdir_p(strval, 0777)) {
223        errmsg(data->parent,
224               _("Failed to create the directory %s:\n%s"),
225               strval, strerror(errno));
226        return;
227      }
228
229      /* save dir pref */
230      cf_setpref(PREF_DIR, strval);
231    }
232
233    /* save port pref */
234    strnum = g_strdup_printf("%i",
235      gtk_spin_button_get_value_as_int(data->port));
236    cf_setpref(PREF_PORT, strnum);
237    g_free(strnum);
238
239    /* save usedownlimit pref */
240    bval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->use_dlimit));
241    cf_setpref(PREF_USEDOWNLIMIT, (bval ? "yes" : "no"));
242
243    /* save downlimit pref */
244    intval = gtk_spin_button_get_value_as_int(data->dlimit);
245    strnum = g_strdup_printf("%i", intval);
246    cf_setpref(PREF_DOWNLIMIT, strnum);
247
248    /* save useuplimit pref */
249    bval = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(data->use_ulimit));
250    cf_setpref(PREF_USEUPLIMIT, (bval ? "yes" : "no"));
251
252    /* save downlimit pref */
253    intval = gtk_spin_button_get_value_as_int(data->ulimit);
254    strnum = g_strdup_printf("%i", intval);
255    cf_setpref(PREF_UPLIMIT, strnum);
256
257    /* save prefs */
258    cf_saveprefs(&errstr);
259    if(NULL != errstr) {
260      errmsg(data->parent, "%s", errstr);
261      g_free(strnum);
262      g_free(errstr);
263    }
264
265    /* XXX would be nice to have errno strings, are they printed to stdout? */
266    tr_setBindPort(tr_backend_handle(data->back),
267                   gtk_spin_button_get_value_as_int(data->port));
268    setlimit(data->back);
269  }
270
271  if(GTK_RESPONSE_APPLY != resp)
272    gtk_widget_destroy(widget);
273}
274
275void
276setlimit(TrBackend *back) {
277  struct { void (*func)(tr_handle_t*, int);
278    const char *use; const char *num; gboolean defuse; long def; } lim[] = {
279    {tr_setDownloadLimit, PREF_USEDOWNLIMIT, PREF_DOWNLIMIT,
280                          DEF_USEDOWNLIMIT,  DEF_DOWNLIMIT},
281    {tr_setUploadLimit,   PREF_USEUPLIMIT,   PREF_UPLIMIT,
282                          DEF_USEUPLIMIT,    DEF_UPLIMIT},
283  };
284  const char *pref;
285  unsigned int ii;
286  tr_handle_t *tr = tr_backend_handle(back);
287
288  for(ii = 0; ii < ALEN(lim); ii++) {
289    pref = cf_getpref(lim[ii].use);
290    if(!(NULL == pref ? lim[ii].defuse : strbool(pref)))
291      lim[ii].func(tr, -1);
292    else {
293      pref = cf_getpref(lim[ii].num);
294      lim[ii].func(tr, (NULL == pref ? lim[ii].def : strtol(pref, NULL, 10)));
295    }
296  }
297}
298
299void
300makeaddwind(GtkWindow *parent, add_torrents_func_t addfunc, void *cbdata) {
301  GtkWidget *wind = gtk_file_chooser_dialog_new(_("Add a Torrent"), parent,
302    GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
303    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
304  struct addcb *data = g_new(struct addcb, 1);
305  GtkWidget *vbox = gtk_vbox_new(FALSE, 3);
306  GtkWidget *bbox = gtk_hbutton_box_new();
307  GtkWidget *autocheck = gtk_check_button_new_with_mnemonic(
308    _("Automatically _start torrent"));
309  GtkWidget *dircheck = gtk_check_button_new_with_mnemonic(
310    _("Use alternate _download directory"));
311  GtkFileFilter *filter = gtk_file_filter_new();
312  GtkFileFilter *unfilter = gtk_file_filter_new();
313  GtkWidget *getdir = gtk_file_chooser_button_new(
314    _("Choose a download directory"), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
315  const char *pref;
316
317  data->addfunc = addfunc;
318  data->parent = parent;
319  data->data = cbdata;
320  data->autostart = TRUE;
321  data->usingaltdir = FALSE;
322  data->altdir = GTK_FILE_CHOOSER(getdir);
323  data->altbox = GTK_BUTTON_BOX(bbox);
324
325  gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_EDGE);
326  gtk_box_pack_start_defaults(GTK_BOX(bbox), dircheck);
327  gtk_box_pack_start_defaults(GTK_BOX(bbox), getdir);
328
329  gtk_box_pack_start_defaults(GTK_BOX(vbox), autocheck);
330  gtk_box_pack_start_defaults(GTK_BOX(vbox), bbox);
331
332  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(autocheck), TRUE);
333  if(NULL != (pref = cf_getpref(PREF_DIR)))
334    gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(getdir), pref);
335
336  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dircheck), FALSE);
337  gtk_widget_set_sensitive(getdir, FALSE);
338
339  gtk_file_filter_set_name(filter, _("Torrent files"));
340  gtk_file_filter_add_pattern(filter, "*.torrent");
341  gtk_file_filter_set_name(unfilter, _("All files"));
342  gtk_file_filter_add_pattern(unfilter, "*");
343
344  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), filter);
345  gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(wind), unfilter);
346  gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(wind), TRUE);
347  gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(wind), vbox);
348
349  g_signal_connect(G_OBJECT(autocheck), "clicked", G_CALLBACK(autoclick),data);
350  g_signal_connect(G_OBJECT(dircheck), "clicked", G_CALLBACK(dirclick), data);
351  g_signal_connect(G_OBJECT(wind), "response", G_CALLBACK(addresp), data);
352
353  gtk_widget_show_all(wind);
354}
355
356static void
357autoclick(GtkWidget *widget, gpointer gdata) {
358  struct addcb *data = gdata;
359
360  data->autostart = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
361}
362
363static void
364dirclick(GtkWidget *widget, gpointer gdata) {
365  struct addcb *data = gdata;
366
367  data->usingaltdir = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
368  gtk_widget_set_sensitive(GTK_WIDGET(data->altdir), data->usingaltdir);
369}
370
371static void
372addresp(GtkWidget *widget, gint resp, gpointer gdata) {
373  struct addcb *data = gdata;
374  GSList *files, *ii;
375  GList *stupidgtk;
376  gboolean paused;
377  char *dir;
378
379  if(GTK_RESPONSE_ACCEPT == resp) {
380    dir = NULL;
381    if(data->usingaltdir)
382      dir = gtk_file_chooser_get_filename(data->altdir);
383    files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(widget));
384    stupidgtk = NULL;
385    for(ii = files; NULL != ii; ii = ii->next)
386      stupidgtk = g_list_append(stupidgtk, ii->data);
387    paused = !data->autostart;
388    data->addfunc(data->data, NULL, stupidgtk, dir, &paused);
389    if(NULL != dir)
390      g_free(dir);
391    g_slist_free(files);
392    freestrlist(stupidgtk);
393  }
394
395  gtk_widget_destroy(widget);
396}
397
398#define INFOLINE(tab, ii, nam, val) \
399  do { \
400    char *txt = g_markup_printf_escaped("<b>%s</b>", nam); \
401    GtkWidget *wid = gtk_label_new(NULL); \
402    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
403    gtk_label_set_markup(GTK_LABEL(wid), txt); \
404    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 1, ii, ii + 1); \
405    wid = gtk_label_new(val); \
406    gtk_label_set_selectable(GTK_LABEL(wid), TRUE); \
407    gtk_misc_set_alignment(GTK_MISC(wid), 0, .5); \
408    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 1, 2, ii, ii + 1); \
409    ii++; \
410    g_free(txt); \
411  } while(0)
412
413#define INFOLINEF(tab, ii, fmt, nam, val) \
414  do { \
415    char *buf = g_strdup_printf(fmt, val); \
416    INFOLINE(tab, ii, nam, buf); \
417    g_free(buf); \
418  } while(0)
419
420#define INFOLINEA(tab, ii, nam, val) \
421  do { \
422    char *buf = val; \
423    INFOLINE(tab, ii, nam, buf); \
424    g_free(buf); \
425  } while(0)
426
427#define INFOSEP(tab, ii) \
428  do { \
429    GtkWidget *wid = gtk_hseparator_new(); \
430    gtk_table_attach_defaults(GTK_TABLE(tab), wid, 0, 2, ii, ii + 1); \
431    ii++; \
432  } while(0)
433
434void
435makeinfowind(GtkWindow *parent, TrTorrent *tor) {
436  tr_stat_t *sb;
437  tr_info_t *in;
438  GtkWidget *wind, *label;
439  int ii;
440  char *str;
441  const int rowcount = 14;
442  GtkWidget *table = gtk_table_new(rowcount, 2, FALSE);
443
444  /* XXX should use model and update this window regularly */
445
446  sb = tr_torrent_stat(tor);
447  in = tr_torrent_info(tor);
448  str = g_strdup_printf(_("%s Properties"), in->name);
449  wind = gtk_dialog_new_with_buttons(str, parent,
450    GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR,
451    GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL);
452  g_free(str);
453
454  gtk_widget_set_name(wind, "TransmissionDialog");
455  gtk_table_set_col_spacings(GTK_TABLE(table), 12);
456  gtk_table_set_row_spacings(GTK_TABLE(table), 12);
457  gtk_dialog_set_default_response(GTK_DIALOG(wind), GTK_RESPONSE_ACCEPT);
458  gtk_container_set_border_width(GTK_CONTAINER(table), 6);
459  gtk_window_set_resizable(GTK_WINDOW(wind), FALSE);
460
461  label = gtk_label_new(NULL);
462  gtk_label_set_selectable(GTK_LABEL(label), TRUE);
463  str = g_markup_printf_escaped("<big>%s</big>", in->name);
464  gtk_label_set_markup(GTK_LABEL(label), str);
465  g_free(str);
466  gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 2, 0, 1);
467
468  ii = 1;
469
470  INFOSEP(table, ii);
471
472  if(80 == in->trackerPort)
473    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s",
474              in->trackerAddress));
475  else
476    INFOLINEA(table, ii, _("Tracker:"), g_strdup_printf("http://%s:%i",
477              in->trackerAddress, in->trackerPort));
478  INFOLINE(table, ii, _("Announce:"), in->trackerAnnounce);
479  INFOLINEA(table, ii, _("Piece Size:"), readablesize(in->pieceSize));
480  INFOLINEF(table, ii, "%i", _("Pieces:"), in->pieceCount);
481  INFOLINEA(table, ii, _("Total Size:"), readablesize(in->totalSize));
482  if(0 > sb->seeders)
483    INFOLINE(table, ii, _("Seeders:"), _("?"));
484  else
485    INFOLINEF(table, ii, "%i", _("Seeders:"), sb->seeders);
486  if(0 > sb->leechers)
487    INFOLINE(table, ii, _("Leechers:"), _("?"));
488  else
489    INFOLINEF(table, ii, "%i", _("Leechers:"), sb->leechers);
490
491  INFOSEP(table, ii);
492
493  INFOLINE(table, ii, _("Directory:"), tr_torrentGetFolder(tr_torrent_handle(tor)));
494  INFOLINEA(table, ii, _("Downloaded:"), readablesize(sb->downloaded));
495  INFOLINEA(table, ii, _("Uploaded:"), readablesize(sb->uploaded));
496
497  INFOSEP(table, ii);
498
499  g_assert(rowcount == ii);
500
501  gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(wind)->vbox), table);
502  g_signal_connect(G_OBJECT(wind), "response",
503                   G_CALLBACK(gtk_widget_destroy), NULL);
504  gtk_widget_show_all(wind);
505}
Note: See TracBrowser for help on using the repository browser.