root/sweep/trunk/src/channelops.c

Revision 691, 17.9 kB (checked in by erikd, 2 years ago)

Remove needless #defines of buffer lengths.

Code had many instances of:

#undef BUF_LEN
#define BUF_LEN 64
char buf[BUF_LEN];
snprintf (buf, BUF_LEN, ....);

which can be replaced with:

char buf[64];
snprintf (buf, sizeof (buf), ....);

which is far cleaner and more difficult to get wrong.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 /*
2  * Sweep, a sound wave editor.
3  *
4  * Copyright (C) 2000 Conrad Parker
5  * Copyright (C) 2002 CSIRO Australia
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <sweep/sweep_i18n.h>
30 #include <sweep/sweep_types.h>
31 #include <sweep/sweep_typeconvert.h>
32 #include <sweep/sweep_undo.h>
33 #include <sweep/sweep_filter.h>
34 #include <sweep/sweep_selection.h>
35 #include <sweep/sweep_sounddata.h>
36 #include <sweep/sweep_sample.h>
37
38 #include "sweep_app.h"
39 #include "edit.h"
40 #include "sw_chooser.h"
41
42 #define BUFFER_LEN 4096
43
44 /* Mono dup channels */
45
46 static void
47 do_dup_channels_thread (sw_op_instance * inst)
48 {
49   sw_sample * sample = inst->sample;
50   int new_channels = GPOINTER_TO_INT(inst->do_data);
51   int min_channels;
52   sw_format * old_format = sample->sounddata->format;
53   sw_sounddata * old_sounddata, * new_sounddata;
54   sw_framecount_t nr_frames;
55
56   sw_audio_t * old_d, * new_d;
57
58   sw_framecount_t remaining, n, run_total, ctotal;
59   int i, j, k;
60   int percent;
61
62   gboolean active = TRUE;
63
64   old_sounddata = sample->sounddata;
65   nr_frames = old_sounddata->nr_frames;
66
67   new_sounddata = sounddata_new_empty (new_channels,
68                                        old_format->rate, nr_frames);
69
70   min_channels = MIN (old_format->channels, new_channels);
71
72   remaining = nr_frames;
73   ctotal = remaining / 100;
74   if (ctotal == 0) ctotal = 1;
75   run_total = 0;
76
77   old_d = (sw_audio_t *)old_sounddata->data;
78   new_d = (sw_audio_t *)new_sounddata->data;
79
80   /* Create selections */
81   g_mutex_lock (sample->ops_mutex);
82   new_sounddata->sels = sels_copy (old_sounddata->sels);
83   g_mutex_unlock (sample->ops_mutex);
84
85   /* Mix down */
86   while (active && remaining > 0) {
87     g_mutex_lock (sample->ops_mutex);
88
89     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
90       active = FALSE;
91     } else {
92
93       n = MIN (remaining, 4096);
94
95       for (i = 0; i < n; i++) {
96         k = 0;
97         while (k < new_channels) {
98           for (j = 0; j < min_channels; j++) {
99             new_d[k++] = old_d[j];
100           }
101         }
102         old_d += old_format->channels;
103         new_d += new_channels;
104       }
105
106       remaining -= n;
107       run_total += n;
108
109       percent = run_total / ctotal;
110       sample_set_progress_percent (sample, percent);
111     }
112
113     g_mutex_unlock (sample->ops_mutex);
114   }
115
116   if (remaining > 0) { /* cancelled or failed */
117     sounddata_destroy (new_sounddata);
118   } else if (sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
119     sample->sounddata = new_sounddata;
120
121     inst->redo_data = inst->undo_data =
122       sounddata_replace_data_new (sample, old_sounddata, new_sounddata);
123
124     register_operation (sample, inst);
125   }
126 }
127
128 static sw_operation dup_channels_op = {
129   SWEEP_EDIT_MODE_ALLOC,
130   (SweepCallback)do_dup_channels_thread,
131   (SweepFunction)NULL,
132   (SweepCallback)undo_by_sounddata_replace,
133   (SweepFunction)sounddata_replace_data_destroy,
134   (SweepCallback)redo_by_sounddata_replace,
135   (SweepFunction)sounddata_replace_data_destroy
136 };
137
138 void
139 dup_channels (sw_sample * sample, int new_channels)
140 {
141   char buf[128];
142
143   if (sample->sounddata->format->channels == 1) {
144     g_snprintf (buf, sizeof (buf), _("Duplicate to %d channels"), new_channels);
145   } else {
146     g_snprintf (buf, sizeof (buf), _("Duplicate from %d to %d channels"),
147                 sample->sounddata->format->channels, new_channels);
148   }
149  
150   schedule_operation (sample, buf, &dup_channels_op,
151                       GINT_TO_POINTER(new_channels));
152 }
153
154 void
155 dup_stereo_cb (GtkWidget * widget, gpointer data)
156 {
157   sw_view * view = (sw_view *)data;
158   sw_sample * sample = view->sample;
159
160   dup_channels (sample, 2);
161 }
162
163 static void
164 dup_channels_dialog_ok_cb (GtkWidget * widget, gpointer data)
165 {
166   sw_sample * sample = (sw_sample *)data;
167   GtkWidget * dialog;
168   GtkWidget * chooser;
169
170   int new_channels;
171
172   dialog = gtk_widget_get_toplevel (widget);
173
174   chooser = g_object_get_data (G_OBJECT(dialog), "default");
175   new_channels = channelcount_chooser_get_count (chooser);
176
177   gtk_widget_destroy (dialog);
178
179   dup_channels (sample, new_channels);
180 }
181
182 static void
183 dup_channels_dialog_cancel_cb (GtkWidget * widget, gpointer data)
184 {
185   GtkWidget * dialog;
186
187   dialog = gtk_widget_get_toplevel (widget);
188   gtk_widget_destroy (dialog);
189 }
190
191 void
192 dup_channels_dialog_new_cb (GtkWidget * widget, gpointer data)
193 {
194   sw_view * view = (sw_view *)data;
195   sw_sample * sample = view->sample;
196   GtkWidget * dialog;
197   GtkWidget * main_vbox;
198   /*GtkWidget * label;*/
199   GtkWidget * chooser;
200   GtkWidget * button, * ok_button;
201
202   /*gchar * current;*/
203
204   dialog = gtk_dialog_new ();
205   gtk_window_set_title (GTK_WINDOW(dialog), _("Sweep: Duplicate channel"));
206   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
207   gtk_container_set_border_width (GTK_CONTAINER(dialog), 8);
208
209   main_vbox = GTK_DIALOG(dialog)->vbox;
210
211   chooser = channelcount_chooser_new (_("Output channels"));
212   gtk_box_pack_start (GTK_BOX(main_vbox), chooser, TRUE, TRUE, 0);
213   channelcount_chooser_set_count (chooser,
214                                   sample->sounddata->format->channels);
215   gtk_widget_show (chooser);
216
217   g_object_set_data (G_OBJECT(dialog), "default", chooser);
218
219   /* OK */
220
221   ok_button = gtk_button_new_with_label (_("OK"));
222   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (ok_button), GTK_CAN_DEFAULT);
223   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), ok_button,
224                       TRUE, TRUE, 0);
225   gtk_widget_show (ok_button);
226   g_signal_connect (G_OBJECT(ok_button), "clicked",
227                       G_CALLBACK (dup_channels_dialog_ok_cb),
228                       sample);
229
230   /* Cancel */
231
232   button = gtk_button_new_with_label (_("Cancel"));
233   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
234   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), button,
235                       TRUE, TRUE, 0);
236   gtk_widget_show (button);
237   g_signal_connect (G_OBJECT(button), "clicked",
238                       G_CALLBACK (dup_channels_dialog_cancel_cb),
239                       NULL);
240
241   gtk_widget_grab_default (ok_button);
242
243   gtk_widget_show (dialog);
244 }
245
246 static void
247 do_mono_mixdown_thread (sw_op_instance * inst)
248 {
249   sw_sample * sample = inst->sample;
250
251   sw_format * old_format = sample->sounddata->format;
252   sw_sounddata * old_sounddata, * new_sounddata;
253   sw_framecount_t nr_frames;
254
255   sw_audio_t * old_d, * new_d;
256
257   sw_framecount_t remaining, n, run_total, ctotal;
258   int i, j;
259   int percent;
260
261   gboolean active = TRUE;
262
263   old_sounddata = sample->sounddata;
264   nr_frames = old_sounddata->nr_frames;
265
266   new_sounddata = sounddata_new_empty (1, old_format->rate, nr_frames);
267
268   remaining = nr_frames;
269   ctotal = remaining / 100;
270   if (ctotal == 0) ctotal = 1;
271   run_total = 0;
272
273   old_d = (sw_audio_t *)old_sounddata->data;
274   new_d = (sw_audio_t *)new_sounddata->data;
275
276   /* Create selections */
277   g_mutex_lock (sample->ops_mutex);
278   new_sounddata->sels = sels_copy (old_sounddata->sels);
279   g_mutex_unlock (sample->ops_mutex);
280
281   /* Mix down */
282   while (active && remaining > 0) {
283     g_mutex_lock (sample->ops_mutex);
284
285     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
286       active = FALSE;
287     } else {
288
289       n = MIN (remaining, 4096);
290
291       for (i = 0; i < n; i++) {
292         for (j = 0; j < old_format->channels; j++) {
293           *new_d += *old_d;
294           old_d++;
295         }
296         new_d++;
297       }
298
299       remaining -= n;
300       run_total += n;
301
302       percent = run_total / ctotal;
303       sample_set_progress_percent (sample, percent);
304     }
305
306     g_mutex_unlock (sample->ops_mutex);
307   }
308
309   if (remaining > 0) { /* cancelled or failed */
310     sounddata_destroy (new_sounddata);
311   } else if (sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
312     sample->sounddata = new_sounddata;
313
314     inst->redo_data = inst->undo_data =
315       sounddata_replace_data_new (sample, old_sounddata, new_sounddata);
316
317     register_operation (sample, inst);
318   }
319 }
320
321 static sw_operation mono_mixdown_op = {
322   SWEEP_EDIT_MODE_ALLOC,
323   (SweepCallback)do_mono_mixdown_thread,
324   (SweepFunction)NULL,
325   (SweepCallback)undo_by_sounddata_replace,
326   (SweepFunction)sounddata_replace_data_destroy,
327   (SweepCallback)redo_by_sounddata_replace,
328   (SweepFunction)sounddata_replace_data_destroy
329 };
330
331 void
332 mono_mixdown_cb (GtkWidget * widget, gpointer data)
333 {
334   sw_view * view = (sw_view *)data;
335   sw_sample * sample = view->sample;
336
337   schedule_operation (sample, _("Mix down to mono"), &mono_mixdown_op, NULL);
338 }
339
340 static void
341 do_remove_channel_thread (sw_op_instance * inst)
342 {
343   sw_sample * sample = inst->sample;
344   int channel = GPOINTER_TO_INT(inst->do_data);
345
346   sw_format * old_format = sample->sounddata->format;
347   sw_sounddata * old_sounddata, * new_sounddata;
348   sw_framecount_t nr_frames;
349
350   sw_audio_t * old_d, * new_d;
351
352   sw_framecount_t remaining, n, run_total, ctotal;
353   int i, j;
354   int percent;
355
356   gboolean active = TRUE;
357
358   old_sounddata = sample->sounddata;
359   nr_frames = old_sounddata->nr_frames;
360
361   new_sounddata = sounddata_new_empty (old_format->channels - 1,
362                                        old_format->rate, nr_frames);
363
364   remaining = nr_frames;
365   ctotal = remaining / 100;
366   if (ctotal == 0) ctotal = 1;
367   run_total = 0;
368
369   old_d = (sw_audio_t *)old_sounddata->data;
370   new_d = (sw_audio_t *)new_sounddata->data;
371
372   /* Create selections */
373   g_mutex_lock (sample->ops_mutex);
374   new_sounddata->sels = sels_copy (old_sounddata->sels);
375   g_mutex_unlock (sample->ops_mutex);
376
377   /* Mix down */
378   while (active && remaining > 0) {
379     g_mutex_lock (sample->ops_mutex);
380
381     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
382       active = FALSE;
383     } else {
384
385       n = MIN (remaining, 4096);
386
387       for (i = 0; i < n; i++) {
388         for (j = 0; j < old_format->channels; j++) {
389           if (j != channel) {
390             *new_d = *old_d;
391             new_d++;
392           }
393           old_d++;
394         }
395       }
396
397       remaining -= n;
398       run_total += n;
399
400       percent = run_total / ctotal;
401       sample_set_progress_percent (sample, percent);
402     }
403
404     g_mutex_unlock (sample->ops_mutex);
405   }
406
407   if (remaining > 0) { /* cancelled or failed */
408     sounddata_destroy (new_sounddata);
409   } else if (sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
410     sample->sounddata = new_sounddata;
411
412     inst->redo_data = inst->undo_data =
413       sounddata_replace_data_new (sample, old_sounddata, new_sounddata);
414
415     register_operation (sample, inst);
416   }
417 }
418
419 static sw_operation remove_channel_op = {
420   SWEEP_EDIT_MODE_ALLOC,
421   (SweepCallback)do_remove_channel_thread,
422   (SweepFunction)NULL,
423   (SweepCallback)undo_by_sounddata_replace,
424   (SweepFunction)sounddata_replace_data_destroy,
425   (SweepCallback)redo_by_sounddata_replace,
426   (SweepFunction)sounddata_replace_data_destroy
427 };
428
429 void
430 remove_left_cb (GtkWidget * widget, gpointer data)
431 {
432   sw_view * view = (sw_view *)data;
433   sw_sample * sample = view->sample;
434
435   schedule_operation (sample, _("Remove left channel"), &remove_channel_op,
436                       GINT_TO_POINTER(0));
437 }
438
439 void
440 remove_right_cb (GtkWidget * widget, gpointer data)
441 {
442   sw_view * view = (sw_view *)data;
443   sw_sample * sample = view->sample;
444
445   schedule_operation (sample, _("Remove right channel"), &remove_channel_op,
446                       GINT_TO_POINTER(1));
447 }
448
449 static void
450 do_stereo_swap (sw_sample * sample, gpointer data)
451 {
452   sw_framecount_t nr_frames;
453   sw_audio_t * dl, * dr, t;
454
455   sw_framecount_t remaining, n, run_total, ctotal;
456   int i;
457   int percent;
458
459   gboolean active = TRUE;
460
461   nr_frames = sample->sounddata->nr_frames;
462
463   remaining = nr_frames;
464   ctotal = remaining / 100;
465   if (ctotal == 0) ctotal = 1;
466   run_total = 0;
467
468   dl = (sw_audio_t *)sample->sounddata->data;
469   dr = dl; dr++;
470
471   /* Swap channels */
472   while (active && remaining > 0) {
473     g_mutex_lock (sample->ops_mutex);
474
475     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
476       active = FALSE;
477     } else {
478
479       n = MIN (remaining, 4096);
480
481       for (i = 0; i < n; i++) {
482         t = *dl;
483         *dl = *dr;
484         *dr = t;
485         dl = ++dr;
486         dr++;
487       }
488
489       remaining -= n;
490       run_total += n;
491    
492       percent = run_total / ctotal;
493       sample_set_progress_percent (sample, percent);
494     }
495
496     g_mutex_unlock (sample->ops_mutex);
497   }
498 }
499
500 static void
501 do_stereo_swap_thread (sw_op_instance * inst)
502 {
503   sw_sample * sample = inst->sample;
504
505   do_stereo_swap (sample, NULL);
506
507   if (sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
508     register_operation (sample, inst);
509   }
510 }
511
512 static sw_operation stereo_swap_op = {
513   SWEEP_EDIT_MODE_ALLOC,
514   (SweepCallback)do_stereo_swap_thread,
515   (SweepFunction)NULL,
516   (SweepCallback)do_stereo_swap,
517   (SweepFunction)NULL,
518   (SweepCallback)do_stereo_swap,
519   (SweepFunction)NULL
520 };
521
522 void
523 stereo_swap_cb (GtkWidget * widget, gpointer data)
524 {
525   sw_view * view = (sw_view *)data;
526   sw_sample * sample = view->sample;
527
528   if (sample->sounddata->format->channels == 2)
529     schedule_operation (sample, _("Swap channels"), &stereo_swap_op, NULL);
530   else
531     sample_set_tmp_message (sample, _("Not stereo"));
532 }
533
534
535 /* Add / Remove channels */
536
537 static void
538 do_change_channels_thread (sw_op_instance * inst)
539 {
540   sw_sample * sample = inst->sample;
541   int new_channels = GPOINTER_TO_INT(inst->do_data);
542   int min_channels;
543   sw_format * old_format = sample->sounddata->format;
544   sw_sounddata * old_sounddata, * new_sounddata;
545   sw_framecount_t nr_frames;
546
547   sw_audio_t * old_d, * new_d;
548
549   sw_framecount_t remaining, n, run_total, ctotal;
550   int i, j;
551   int percent;
552
553   gboolean active = TRUE;
554
555   old_sounddata = sample->sounddata;
556   nr_frames = old_sounddata->nr_frames;
557
558   new_sounddata = sounddata_new_empty (new_channels,
559                                        old_format->rate, nr_frames);
560
561   min_channels = MIN (old_format->channels, new_channels);
562
563   remaining = nr_frames;
564   ctotal = remaining / 100;
565   if (ctotal == 0) ctotal = 1;
566   run_total = 0;
567
568   old_d = (sw_audio_t *)old_sounddata->data;
569   new_d = (sw_audio_t *)new_sounddata->data;
570
571   /* Create selections */
572   g_mutex_lock (sample->ops_mutex);
573   new_sounddata->sels = sels_copy (old_sounddata->sels);
574   g_mutex_unlock (sample->ops_mutex);
575
576   /* Mix down */
577   while (active && remaining > 0) {
578     g_mutex_lock (sample->ops_mutex);
579
580     if (sample->edit_state == SWEEP_EDIT_STATE_CANCEL) {
581       active = FALSE;
582     } else {
583
584       n = MIN (remaining, 4096);
585
586       for (i = 0; i < n; i++) {
587         for (j = 0; j < min_channels; j++) {
588           new_d[j] = old_d[j];
589         }
590         old_d += old_format->channels;
591         new_d += new_channels;
592       }
593
594       remaining -= n;
595       run_total += n;
596
597       percent = run_total / ctotal;
598       sample_set_progress_percent (sample, percent);
599     }
600
601     g_mutex_unlock (sample->ops_mutex);
602   }
603
604   if (remaining > 0) { /* cancelled or failed */
605     sounddata_destroy (new_sounddata);
606   } else if (sample->edit_state == SWEEP_EDIT_STATE_BUSY) {
607     sample->sounddata = new_sounddata;
608
609     inst->redo_data = inst->undo_data =
610       sounddata_replace_data_new (sample, old_sounddata, new_sounddata);
611
612     register_operation (sample, inst);
613   }
614 }
615
616 static sw_operation change_channels_op = {
617   SWEEP_EDIT_MODE_ALLOC,
618   (SweepCallback)do_change_channels_thread,
619   (SweepFunction)NULL,
620   (SweepCallback)undo_by_sounddata_replace,
621   (SweepFunction)sounddata_replace_data_destroy,
622   (SweepCallback)redo_by_sounddata_replace,
623   (SweepFunction)sounddata_replace_data_destroy
624 };
625
626 void
627 change_channels (sw_sample * sample, int new_channels)
628 {
629   char buf[128];
630
631   g_snprintf (buf, sizeof (buf), _("Convert from %d to %d channels"),
632               sample->sounddata->format->channels, new_channels);
633  
634   schedule_operation (sample, buf, &change_channels_op,
635                       GINT_TO_POINTER(new_channels));
636 }
637
638 static void
639 channels_dialog_ok_cb (GtkWidget * widget, gpointer data)
640 {
641   sw_sample * sample = (sw_sample *)data;
642   GtkWidget * dialog;
643   GtkWidget * chooser;
644
645   int new_channels;
646
647   dialog = gtk_widget_get_toplevel (widget);
648
649   chooser = g_object_get_data (G_OBJECT(dialog), "default");
650   new_channels = channelcount_chooser_get_count (chooser);
651
652   gtk_widget_destroy (dialog);
653
654   change_channels (sample, new_channels);
655 }
656
657 static void
658 channels_dialog_cancel_cb (GtkWidget * widget, gpointer data)
659 {
660   GtkWidget * dialog;
661
662   dialog = gtk_widget_get_toplevel (widget);
663   gtk_widget_destroy (dialog);
664 }
665
666 void
667 channels_dialog_new_cb (GtkWidget * widget, gpointer data)
668 {
669   sw_view * view = (sw_view *)data;
670   sw_sample * sample = view->sample;
671   GtkWidget * dialog;
672   GtkWidget * main_vbox;
673   GtkWidget * label;
674   GtkWidget * chooser;
675   GtkWidget * button, * ok_button;
676
677   gchar * current;
678
679   dialog = gtk_dialog_new ();
680   gtk_window_set_title (GTK_WINDOW(dialog), _("Sweep: Add/Remove channels"));
681   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_MOUSE);
682   gtk_container_set_border_width (GTK_CONTAINER(dialog), 8);
683
684   main_vbox = GTK_DIALOG(dialog)->vbox;
685
686   current = g_strdup_printf (_("Currently: %d channels"),
687                              sample->sounddata->format->channels);
688   label = gtk_label_new (current);
689   gtk_box_pack_start (GTK_BOX(main_vbox), label, TRUE, TRUE, 8);
690   gtk_widget_show (label);
691
692   chooser = channelcount_chooser_new (_("Output channels"));
693   gtk_box_pack_start (GTK_BOX(main_vbox), chooser, TRUE, TRUE, 0);
694   channelcount_chooser_set_count (chooser,
695                                   sample->sounddata->format->channels);
696   gtk_widget_show (chooser);
697
698   g_object_set_data (G_OBJECT(dialog), "default", chooser);
699
700   /* OK */
701
702   ok_button = gtk_button_new_with_label (_("OK"));
703   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (ok_button), GTK_CAN_DEFAULT);
704   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), ok_button,
705                       TRUE, TRUE, 0);
706   gtk_widget_show (ok_button);
707   g_signal_connect (G_OBJECT(ok_button), "clicked",
708                       G_CALLBACK (channels_dialog_ok_cb),
709                       sample);
710
711   /* Cancel */
712
713   button = gtk_button_new_with_label (_("Cancel"));
714   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (button), GTK_CAN_DEFAULT);
715   gtk_box_pack_start (GTK_BOX (GTK_DIALOG(dialog)->action_area), button,
716                       TRUE, TRUE, 0);
717   gtk_widget_show (button);
718   g_signal_connect (G_OBJECT(button), "clicked",
719                       G_CALLBACK (channels_dialog_cancel_cb),
720                       NULL);
721
722   gtk_widget_grab_default (ok_button);
723
724   gtk_widget_show (dialog);
725 }
Note: See TracBrowser for help on using the browser.