1 /* -*- linux-c -*-
2 Copyright (C) 2007 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: utils_gui.c 1295 2014-05-04 22:07:31Z tszilagyi $
19 */
20
21 #include <config.h>
22
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <string.h>
28 #include <glib.h>
29 #include <glib-object.h>
30 #include <gdk/gdk.h>
31 #include <gtk/gtk.h>
32
33 #include "common.h"
34 #include "i18n.h"
35 #include "options.h"
36 #include "utils.h"
37 #include "utils_gui.h"
38
39
40 extern options_t options;
41
42 #ifdef HAVE_SNDFILE
43 extern char * valid_extensions_sndfile[];
44 #endif /* HAVE_SNDFILE */
45
46 #ifdef HAVE_MPEG
47 extern char * valid_extensions_mpeg[];
48 #endif /* HAVE_MPEG */
49
50 #ifdef HAVE_MOD
51 extern char * valid_extensions_mod[];
52 #endif /* HAVE_MOD */
53
54 GSList * toplevel_windows;
55
56 typedef struct {
57 GtkWidget * window;
58 int flag;
59 } top_win_t;
60
61 void
unregister_toplevel_window(GtkWidget * window)62 unregister_toplevel_window(GtkWidget * window) {
63
64 GSList * node;
65
66 for (node = toplevel_windows; node; node = node->next) {
67
68 top_win_t * tw = (top_win_t *)node->data;
69
70 if (tw->window == window) {
71 toplevel_windows = g_slist_remove(toplevel_windows, tw);
72 free(tw);
73 break;
74 }
75 }
76 }
77
78 void
register_toplevel_window(GtkWidget * window,int flag)79 register_toplevel_window(GtkWidget * window, int flag) {
80
81 top_win_t * tw;
82
83 if ((tw = (top_win_t *)calloc(1, sizeof(top_win_t))) == NULL) {
84 fprintf(stderr, "register_toplevel_window: calloc error\n");
85 return;
86 }
87
88 tw->window = window;
89 tw->flag = flag;
90
91 unregister_toplevel_window(window);
92 toplevel_windows = g_slist_append(toplevel_windows, tw);
93 }
94
95 void
toplevel_window_foreach(int flag,void (* callback)(GtkWidget * window))96 toplevel_window_foreach(int flag, void (* callback)(GtkWidget * window)) {
97
98 GSList * node;
99
100 for (node = toplevel_windows; node; node = node->next) {
101
102 top_win_t * tw = (top_win_t *)node->data;
103
104 if (tw->flag & flag) {
105 callback(tw->window);
106 }
107 }
108 }
109
110
111 #ifdef HAVE_SYSTRAY
112 int systray_semaphore = 0;
113
114 int
get_systray_semaphore()115 get_systray_semaphore() {
116
117 return systray_semaphore;
118 }
119
120 #endif /* HAVE_SYSTRAY */
121
122
123 gint
aqualung_dialog_run(GtkDialog * dialog)124 aqualung_dialog_run(GtkDialog * dialog) {
125 #ifdef HAVE_SYSTRAY
126 int ret;
127 systray_semaphore++;
128 gtk_window_present(GTK_WINDOW(dialog));
129 ret = gtk_dialog_run(dialog);
130 systray_semaphore--;
131 return ret;
132 #else
133 gtk_window_present(GTK_WINDOW(dialog));
134 return gtk_dialog_run(dialog);
135 #endif /* HAVE_SYSTRAY */
136 }
137
138 typedef struct {
139 GSourceFunc func;
140 gpointer data;
141 GDestroyNotify destroy;
142 } threads_dispatch_t;
143
144 static gboolean
threads_dispatch(gpointer data)145 threads_dispatch(gpointer data) {
146
147 threads_dispatch_t * dispatch = data;
148 gboolean ret = FALSE;
149
150 GDK_THREADS_ENTER();
151
152 if (!g_source_is_destroyed(g_main_current_source())) {
153 ret = dispatch->func(dispatch->data);
154 }
155
156 GDK_THREADS_LEAVE();
157
158 return ret;
159 }
160
161 static void
threads_dispatch_free(gpointer data)162 threads_dispatch_free(gpointer data) {
163
164 threads_dispatch_t * dispatch = data;
165
166 if (dispatch->destroy && dispatch->data) {
167 dispatch->destroy(dispatch->data);
168 }
169
170 g_slice_free(threads_dispatch_t, data);
171 }
172
173 guint
aqualung_idle_add(GSourceFunc function,gpointer data)174 aqualung_idle_add(GSourceFunc function, gpointer data) {
175
176 threads_dispatch_t * dispatch;
177
178 dispatch = g_slice_new(threads_dispatch_t);
179 dispatch->func = function;
180 dispatch->data = data;
181 dispatch->destroy = NULL;
182
183 return g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
184 threads_dispatch,
185 dispatch,
186 threads_dispatch_free);
187 }
188
189 guint
aqualung_timeout_add(guint interval,GSourceFunc function,gpointer data)190 aqualung_timeout_add(guint interval, GSourceFunc function, gpointer data) {
191
192 threads_dispatch_t * dispatch;
193
194 dispatch = g_slice_new(threads_dispatch_t);
195 dispatch->func = function;
196 dispatch->data = data;
197 dispatch->destroy = NULL;
198
199 if (interval % 1000 == 0) {
200 return g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
201 interval / 1000,
202 threads_dispatch,
203 dispatch,
204 threads_dispatch_free);
205 }
206 return g_timeout_add_full(G_PRIORITY_DEFAULT,
207 interval,
208 threads_dispatch,
209 dispatch,
210 threads_dispatch_free);
211 }
212
213 void
aqualung_tooltips_set_enabled(gboolean enabled)214 aqualung_tooltips_set_enabled(gboolean enabled) {
215
216 GtkSettings * settings = gtk_settings_get_default();
217
218 if (settings != NULL) {
219 g_object_set(settings, "gtk-enable-tooltips", enabled, NULL);
220 }
221
222 }
223
224 #ifdef HAVE_SYSTRAY
225 void
aqualung_status_icon_set_tooltip_text(GtkStatusIcon * icon,const gchar * text)226 aqualung_status_icon_set_tooltip_text(GtkStatusIcon * icon, const gchar * text) {
227 gtk_status_icon_set_tooltip_text(icon, text);
228 }
229 #endif /* HAVE_SYSTRAY */
230
231 void
aqualung_widget_set_tooltip_text(GtkWidget * widget,const gchar * text)232 aqualung_widget_set_tooltip_text(GtkWidget * widget, const gchar * text) {
233
234 gtk_widget_set_tooltip_text(widget, text);
235
236 }
237
238 /* create button with stock item
239 *
240 * in: label - label for button (label=NULL to disable label, label=-1 to disable button relief)
241 * stock - stock icon identifier
242 */
243 GtkWidget*
gui_stock_label_button(gchar * label,const gchar * stock)244 gui_stock_label_button(gchar *label, const gchar *stock) {
245
246 GtkWidget *button;
247 GtkWidget *alignment;
248 GtkWidget *hbox;
249 GtkWidget *image;
250
251 button = g_object_new (GTK_TYPE_BUTTON, "visible", TRUE, NULL);
252
253 if (label== (gchar *)-1) {
254 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
255 }
256
257 alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
258 hbox = gtk_hbox_new (FALSE, 2);
259 gtk_container_add (GTK_CONTAINER (alignment), hbox);
260
261 image = gtk_image_new_from_stock (stock, GTK_ICON_SIZE_BUTTON);
262
263 if (image) {
264 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
265 }
266
267 if (label != NULL && label != (gchar *)-1) {
268 gtk_box_pack_start (GTK_BOX (hbox),
269 g_object_new (GTK_TYPE_LABEL, "label", label, "use_underline", TRUE, NULL),
270 FALSE, TRUE, 0);
271 }
272
273 gtk_widget_show_all (alignment);
274 gtk_container_add (GTK_CONTAINER (button), alignment);
275
276 return button;
277 }
278
279
280 void
assign_etf_fc_filters(GtkFileChooser * fc)281 assign_etf_fc_filters(GtkFileChooser *fc) {
282
283 GtkFileFilter *filter_1, *filter_2;
284
285 /* all files filter */
286 filter_1 = gtk_file_filter_new();
287 gtk_file_filter_add_pattern(filter_1, "*");
288 gtk_file_filter_set_name(GTK_FILE_FILTER(filter_1), _("All Files"));
289 gtk_file_chooser_add_filter(fc, filter_1);
290
291 /* music store files filter */
292 filter_2 = gtk_file_filter_new();
293 gtk_file_filter_add_pattern(filter_2, "*.[lL][uU][aA]");
294 gtk_file_filter_set_name(GTK_FILE_FILTER(filter_2), _("Lua Extension Files (*.lua)"));
295 gtk_file_chooser_add_filter(fc, filter_2);
296
297 gtk_file_chooser_set_filter(fc, filter_2);
298 }
299
300
301 void
assign_store_fc_filters(GtkFileChooser * fc)302 assign_store_fc_filters(GtkFileChooser *fc) {
303
304 GtkFileFilter *filter_1, *filter_2;
305
306 /* all files filter */
307 filter_1 = gtk_file_filter_new();
308 gtk_file_filter_add_pattern(filter_1, "*");
309 gtk_file_filter_set_name(GTK_FILE_FILTER(filter_1), _("All Files"));
310 gtk_file_chooser_add_filter(fc, filter_1);
311
312 /* music store files filter */
313 filter_2 = gtk_file_filter_new();
314 gtk_file_filter_add_pattern(filter_2, "*.[xX][mM][lL]");
315 gtk_file_filter_set_name(GTK_FILE_FILTER(filter_2), _("Music Store Files (*.xml)"));
316 gtk_file_chooser_add_filter(fc, filter_2);
317
318 gtk_file_chooser_set_filter(fc, filter_2);
319 }
320
321
322 void
assign_playlist_fc_filters(GtkFileChooser * fc)323 assign_playlist_fc_filters(GtkFileChooser *fc) {
324
325 gchar *file_filters[] = {
326 _("Aqualung playlist (*.xml)"), "*.[xX][mM][lL]",
327 _("MP3 Playlist (*.m3u)"), "*.[mM]3[uU]",
328 _("Multimedia Playlist (*.pls)"), "*.[pP][lL][sS]",
329 };
330
331 gint i, len;
332 GtkFileFilter *filter_1, *filter_2, *filter_3;
333
334 len = sizeof(file_filters)/sizeof(gchar*)/2;
335
336 /* all files filter */
337 filter_1 = gtk_file_filter_new();
338 gtk_file_filter_add_pattern(filter_1, "*");
339 gtk_file_filter_set_name(GTK_FILE_FILTER(filter_1), _("All Files"));
340 gtk_file_chooser_add_filter(fc, filter_1);
341
342 /* all playlist files filter */
343 filter_2 = gtk_file_filter_new();
344
345 for (i = 0; i < len; i++) {
346 gtk_file_filter_add_pattern(filter_2, file_filters[2*i+1]);
347 }
348
349 gtk_file_filter_set_name(GTK_FILE_FILTER(filter_2), _("All Playlist Files"));
350 gtk_file_chooser_add_filter(fc, filter_2);
351 gtk_file_chooser_set_filter(fc, filter_2);
352
353 /* single extensions */
354 for (i = 0; i < len; i++) {
355
356 filter_3 = gtk_file_filter_new();
357 gtk_file_filter_add_pattern(filter_3, file_filters[2*i+1]);
358 gtk_file_filter_set_name(GTK_FILE_FILTER(filter_3), file_filters[2*i]);
359 gtk_file_chooser_add_filter(fc, filter_3);
360 }
361 }
362
363
364 void
build_filter_from_extensions(GtkFileFilter * f1,GtkFileFilter * f2,char * extensions[])365 build_filter_from_extensions(GtkFileFilter * f1, GtkFileFilter * f2, char * extensions[]) {
366
367 int i, j, k;
368
369 for (i = 0; extensions[i]; i++) {
370 char buf[32];
371 buf[0] = '*';
372 buf[1] = '.';
373 k = 2;
374 for (j = 0; extensions[i][j]; j++) {
375 if (isalpha(extensions[i][j]) && k < 28) {
376 buf[k++] = '[';
377 buf[k++] = tolower(extensions[i][j]);
378 buf[k++] = toupper(extensions[i][j]);
379 buf[k++] = ']';
380 } else if (k < 31) {
381 buf[k++] = extensions[i][j];
382 }
383 }
384 buf[k] = '\0';
385 gtk_file_filter_add_pattern(f1, buf);
386 gtk_file_filter_add_pattern(f2, buf);
387 }
388 }
389
390
391 void
assign_audio_fc_filters(GtkFileChooser * fc)392 assign_audio_fc_filters(GtkFileChooser * fc) {
393
394 GtkFileFilter * filter;
395 GtkFileFilter * filter_all;
396
397 filter = gtk_file_filter_new();
398 gtk_file_filter_set_name(filter, _("All Files"));
399 gtk_file_filter_add_pattern(filter, "*");
400 gtk_file_chooser_add_filter(fc, filter);
401
402 filter_all = gtk_file_filter_new();
403 gtk_file_filter_set_name(filter_all, _("All Audio Files"));
404 gtk_file_chooser_add_filter(fc, filter_all);
405 gtk_file_chooser_set_filter(fc, filter_all);
406
407 #ifdef HAVE_SNDFILE
408 filter = gtk_file_filter_new();
409 gtk_file_filter_set_name(filter, _("Sound Files (*.wav, *.aiff, *.au, ...)"));
410 build_filter_from_extensions(filter, filter_all, valid_extensions_sndfile);
411 gtk_file_chooser_add_filter(fc, filter);
412 #endif /* HAVE_SNDFILE */
413
414 #ifdef HAVE_FLAC
415 filter = gtk_file_filter_new();
416 gtk_file_filter_set_name(filter, _("Free Lossless Audio Codec (*.flac)"));
417 gtk_file_filter_add_pattern(filter, "*.[fF][lL][aA][cC]");
418 gtk_file_filter_add_pattern(filter_all, "*.[fF][lL][aA][cC]");
419 gtk_file_chooser_add_filter(fc, filter);
420 #endif /* HAVE_FLAC */
421
422 #ifdef HAVE_MPEG
423 filter = gtk_file_filter_new();
424 gtk_file_filter_set_name(filter, _("MPEG Audio (*.mp3, *.mpa, *.mpega, ...)"));
425 build_filter_from_extensions(filter, filter_all, valid_extensions_mpeg);
426 gtk_file_chooser_add_filter(fc, filter);
427 #endif /* HAME_MPEG */
428
429 #ifdef HAVE_VORBIS
430 filter = gtk_file_filter_new();
431 gtk_file_filter_set_name(filter, _("Ogg Vorbis (*.ogg)"));
432 gtk_file_filter_add_pattern(filter, "*.[oO][gG][gG]");
433 gtk_file_filter_add_pattern(filter_all, "*.[oO][gG][gG]");
434 gtk_file_chooser_add_filter(fc, filter);
435 #endif /* HAVE_VORBIS */
436
437 #ifdef HAVE_SPEEX
438 filter = gtk_file_filter_new();
439 gtk_file_filter_set_name(filter, _("Ogg Speex (*.spx)"));
440 gtk_file_filter_add_pattern(filter, "*.[sS][pP][xX]");
441 gtk_file_filter_add_pattern(filter_all, "*.[sS][pP][xX]");
442 gtk_file_chooser_add_filter(fc, filter);
443 #endif /* HAVE_SPEEX */
444
445 #ifdef HAVE_MPC
446 filter = gtk_file_filter_new();
447 gtk_file_filter_set_name(filter, _("Musepack (*.mpc)"));
448 gtk_file_filter_add_pattern(filter, "*.[mM][pP][cC]");
449 gtk_file_filter_add_pattern(filter_all, "*.[mM][pP][cC]");
450 gtk_file_chooser_add_filter(fc, filter);
451 #endif /* HAVE_MPC */
452
453 #ifdef HAVE_MAC
454 filter = gtk_file_filter_new();
455 gtk_file_filter_set_name(filter, _("Monkey's Audio Codec (*.ape)"));
456 gtk_file_filter_add_pattern(filter, "*.[aA][pP][eE]");
457 gtk_file_filter_add_pattern(filter_all, "*.[aA][pP][eE]");
458 gtk_file_chooser_add_filter(fc, filter);
459 #endif /* HAVE_MAC */
460
461 #ifdef HAVE_MOD
462 filter = gtk_file_filter_new();
463 gtk_file_filter_set_name(filter, _("Modules (*.xm, *.mod, *.it, *.s3m, ...)"));
464 build_filter_from_extensions(filter, filter_all, valid_extensions_mod);
465 gtk_file_chooser_add_filter(fc, filter);
466 #endif /* HAVE_MOD */
467
468 #if defined(HAVE_MOD) && (defined(HAVE_LIBZ) || defined(HAVE_LIBBZ2))
469 filter = gtk_file_filter_new();
470 #if defined(HAVE_LIBZ) && defined(HAVE_LIBBZ2)
471 gtk_file_filter_set_name(filter, _("Compressed modules (*.gz, *.bz2)"));
472 #elif defined(HAVE_LIBZ)
473 gtk_file_filter_set_name(filter, _("Compressed modules (*.gz)"));
474 #elif defined(HAVE_LIBBZ2)
475 gtk_file_filter_set_name(filter, _("Compressed modules (*.bz2)"));
476 #endif /* HAVE_LIBZ, HAVE_LIBBZ2 */
477
478 #ifdef HAVE_LIBZ
479 gtk_file_filter_add_pattern(filter, "*.[gG][zZ]");
480 gtk_file_filter_add_pattern(filter_all, "*.[gG][zZ]");
481 #endif /* HAVE_LIBZ */
482 #ifdef HAVE_LIBBZ2
483 gtk_file_filter_add_pattern(filter, "*.[bB][zZ]2");
484 gtk_file_filter_add_pattern(filter_all, "*.[bB][zZ]2");
485 #endif /* HAVE_LIBBZ2 */
486 gtk_file_chooser_add_filter(fc, filter);
487 #endif /* (HAVE_MOD && HAVE LIBZ) */
488
489 #ifdef HAVE_WAVPACK
490 filter = gtk_file_filter_new();
491 gtk_file_filter_set_name(filter, _("WavPack (*.wv)"));
492 gtk_file_filter_add_pattern(filter, "*.[wW][vV]");
493 gtk_file_filter_add_pattern(filter_all, "*.[wW][vV]");
494 gtk_file_chooser_add_filter(fc, filter);
495 #endif /* HAVE_WAVPACK */
496
497 #ifdef HAVE_LAVC
498 filter = gtk_file_filter_new();
499 gtk_file_filter_set_name(filter, _("LAVC audio/video files"));
500 {
501 char * valid_ext_lavc[] = {
502 "aac", "ac3", "asf", "avi", "mpeg", "mpg", "mp3", "ra",
503 "wav", "wma", "wv", NULL };
504 build_filter_from_extensions(filter, filter_all, valid_ext_lavc);
505 }
506 gtk_file_chooser_add_filter(fc, filter);
507 #endif /* HAVE_LAVC */
508 }
509
510
511 void
assign_fc_filters(GtkFileChooser * fc,int filter)512 assign_fc_filters(GtkFileChooser * fc, int filter) {
513
514 gtk_widget_realize(GTK_WIDGET(fc));
515
516 if (filter == FILE_CHOOSER_FILTER_AUDIO) {
517 assign_audio_fc_filters(fc);
518 }
519 if (filter == FILE_CHOOSER_FILTER_PLAYLIST) {
520 assign_playlist_fc_filters(fc);
521 }
522 if (filter == FILE_CHOOSER_FILTER_STORE) {
523 assign_store_fc_filters(fc);
524 }
525 if (filter == FILE_CHOOSER_FILTER_ETF) {
526 assign_etf_fc_filters(fc);
527 }
528 }
529
530 GSList *
file_chooser(char * title,GtkWidget * parent,GtkFileChooserAction action,int filter,gint multiple,char * destpath)531 file_chooser(char * title, GtkWidget * parent, GtkFileChooserAction action, int filter,
532 gint multiple, char * destpath) {
533
534 GtkWidget * dialog;
535 GSList * files = NULL;
536
537 dialog = gtk_file_chooser_dialog_new(title,
538 GTK_WINDOW(parent),
539 action,
540 (action == GTK_FILE_CHOOSER_ACTION_SAVE) ? GTK_STOCK_SAVE : GTK_STOCK_OPEN,
541 GTK_RESPONSE_ACCEPT,
542 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
543 NULL);
544
545 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
546 gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), multiple);
547 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(dialog), destpath);
548
549 if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
550 char * bname = g_path_get_basename(destpath);
551 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), bname);
552 g_free(bname);
553 }
554
555 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
556 assign_fc_filters(GTK_FILE_CHOOSER(dialog), filter);
557
558 if (options.show_hidden) {
559 gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), TRUE);
560 }
561
562 if (aqualung_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
563
564 strncpy(destpath,
565 gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)),
566 MAXLEN-1);
567
568 files = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
569 }
570
571 gtk_widget_destroy(dialog);
572
573 return files;
574 }
575
576 void
file_chooser_with_entry(char * title,GtkWidget * parent,GtkFileChooserAction action,int filter,GtkWidget * entry,char * destpath)577 file_chooser_with_entry(char * title, GtkWidget * parent, GtkFileChooserAction action, int filter,
578 GtkWidget * entry, char * destpath) {
579
580 GtkWidget * dialog;
581 const gchar * selected_filename = gtk_entry_get_text(GTK_ENTRY(entry));
582 char path[MAXLEN];
583
584 path[0] = '\0';
585
586 dialog = gtk_file_chooser_dialog_new(title,
587 GTK_WINDOW(parent),
588 action,
589 GTK_STOCK_APPLY, GTK_RESPONSE_ACCEPT,
590 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
591 NULL);
592
593 if (options.show_hidden) {
594 gtk_file_chooser_set_show_hidden(GTK_FILE_CHOOSER(dialog), options.show_hidden);
595 }
596
597 if (strlen(selected_filename)) {
598 char * filename = g_filename_from_utf8(selected_filename, -1, NULL, NULL, NULL);
599
600 if (filename == NULL) {
601 gtk_widget_destroy(dialog);
602 return;
603 }
604
605 normalize_filename(filename, path);
606 g_free(filename);
607 } else {
608 strncpy(path, destpath, MAXLEN-1);
609 }
610
611 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), path);
612
613 if (action == GTK_FILE_CHOOSER_ACTION_SAVE) {
614 char * bname = g_path_get_basename(path);
615 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), bname);
616 g_free(bname);
617 }
618
619 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT);
620 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
621 assign_fc_filters(GTK_FILE_CHOOSER(dialog), filter);
622
623 if (aqualung_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
624
625 char * utf8;
626
627 selected_filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
628 utf8 = g_filename_to_utf8(selected_filename, -1, NULL, NULL, NULL);
629
630 if (utf8 == NULL) {
631 gtk_widget_destroy(dialog);
632 }
633
634 gtk_entry_set_text(GTK_ENTRY(entry), utf8);
635
636 strncpy(destpath, selected_filename, MAXLEN-1);
637 g_free(utf8);
638 }
639
640 gtk_widget_destroy(dialog);
641 }
642
643 int
message_dialog(char * title,GtkWidget * parent,GtkMessageType type,GtkButtonsType buttons,GtkWidget * extra,char * text,...)644 message_dialog(char * title, GtkWidget * parent, GtkMessageType type, GtkButtonsType buttons,
645 GtkWidget * extra, char * text, ...) {
646
647 GtkWidget * dialog;
648 va_list args;
649 gchar * msg = NULL;
650 int res;
651
652
653 va_start(args, text);
654 msg = g_strdup_vprintf(text, args);
655 va_end(args);
656
657 dialog = gtk_message_dialog_new(GTK_WINDOW(parent),
658 GTK_DIALOG_DESTROY_WITH_PARENT,
659 type,
660 buttons,
661 "%s",
662 msg);
663 g_free(msg);
664
665 if (extra != NULL) {
666 gtk_box_pack_start(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
667 extra, FALSE, FALSE, 5);
668 gtk_widget_show_all(extra);
669 }
670
671 gtk_window_set_title(GTK_WINDOW(dialog), title);
672 res = aqualung_dialog_run(GTK_DIALOG(dialog));
673 gtk_widget_destroy(dialog);
674
675 return res;
676 }
677
678 void
insert_label_entry(GtkWidget * table,char * ltext,GtkWidget ** entry,char * etext,int y1,int y2,gboolean editable)679 insert_label_entry(GtkWidget * table, char * ltext, GtkWidget ** entry, char * etext,
680 int y1, int y2, gboolean editable) {
681
682 GtkWidget * label;
683 GtkWidget * hbox;
684
685 label = gtk_label_new(ltext);
686 hbox = gtk_hbox_new(FALSE, 0);
687 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
688 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, y1, y2, GTK_FILL, GTK_FILL, 5, 5);
689
690 *entry = gtk_entry_new();
691 gtk_entry_set_max_length(GTK_ENTRY(*entry), MAXLEN-1);
692 gtk_editable_set_editable(GTK_EDITABLE (*entry), editable ? TRUE : FALSE);
693 if (etext != NULL) {
694 gtk_entry_set_text(GTK_ENTRY(*entry), etext);
695 }
696 gtk_table_attach(GTK_TABLE(table), *entry, 1, 2, y1, y2,
697 GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 5);
698 }
699
700 void
insert_label_entry_button(GtkWidget * table,char * ltext,GtkWidget ** entry,char * etext,GtkWidget * button,int y1,int y2)701 insert_label_entry_button(GtkWidget * table, char * ltext, GtkWidget ** entry, char * etext,
702 GtkWidget * button, int y1, int y2) {
703
704 GtkWidget * label;
705 GtkWidget * hbox;
706
707 label = gtk_label_new(ltext);
708 hbox = gtk_hbox_new(FALSE, 0);
709 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
710 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, y1, y2, GTK_FILL, GTK_FILL, 5, 5);
711
712 hbox = gtk_hbox_new(FALSE, 0);
713 gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, y1, y2,
714 GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 5);
715
716 *entry = gtk_entry_new();
717 gtk_entry_set_max_length(GTK_ENTRY(*entry), MAXLEN-1);
718 if (etext != NULL) {
719 gtk_entry_set_text(GTK_ENTRY(*entry), etext);
720 }
721 gtk_box_pack_start(GTK_BOX(hbox), *entry, TRUE, TRUE, 0);
722
723 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, TRUE, 5);
724 }
725
726 void
insert_label_entry_browse(GtkWidget * table,char * ltext,GtkWidget ** entry,char * etext,int y1,int y2,void (* browse_cb)(GtkButton * button,gpointer data))727 insert_label_entry_browse(GtkWidget * table, char * ltext, GtkWidget ** entry, char * etext,
728 int y1, int y2,
729 void (* browse_cb)(GtkButton * button, gpointer data)) {
730
731 GtkWidget * button = gui_stock_label_button(_("_Browse..."), GTK_STOCK_OPEN);
732 insert_label_entry_button(table, ltext, entry, etext, button, y1, y2);
733 g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(browse_cb), *entry);
734 }
735
736 void
insert_label_progbar_button(GtkWidget * table,char * ltext,GtkWidget ** progbar,GtkWidget * button,int y1,int y2)737 insert_label_progbar_button(GtkWidget * table, char * ltext, GtkWidget ** progbar,
738 GtkWidget * button, int y1, int y2) {
739
740 GtkWidget * label;
741 GtkWidget * hbox;
742
743 label = gtk_label_new(ltext);
744 hbox = gtk_hbox_new(FALSE, 0);
745 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
746 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, y1, y2, GTK_FILL, GTK_FILL, 5, 5);
747
748 hbox = gtk_hbox_new(FALSE, 0);
749 gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, y1, y2,
750 GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 5);
751
752 *progbar = gtk_progress_bar_new();
753 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(*progbar), 0.0f);
754 gtk_progress_bar_set_text(GTK_PROGRESS_BAR(*progbar), "0%");
755 gtk_box_pack_start(GTK_BOX(hbox), *progbar, TRUE, TRUE, 0);
756
757 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, TRUE, 5);
758 }
759
760 void
insert_label_spin(GtkWidget * table,char * ltext,GtkWidget ** spin,int spinval,int y1,int y2)761 insert_label_spin(GtkWidget * table, char * ltext, GtkWidget ** spin, int spinval,
762 int y1, int y2) {
763
764 GtkWidget * label;
765 GtkWidget * hbox;
766
767 label = gtk_label_new(ltext);
768 hbox = gtk_hbox_new(FALSE, 0);
769 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
770 gtk_table_attach(GTK_TABLE(table), hbox, 0, 1, y1, y2, GTK_FILL, GTK_FILL, 5, 5);
771
772 *spin = gtk_spin_button_new_with_range(YEAR_MIN, YEAR_MAX, 1);
773 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*spin), spinval);
774 gtk_table_attach(GTK_TABLE(table), *spin, 1, 2, y1, y2,
775 GTK_EXPAND | GTK_FILL, GTK_FILL, 2, 5);
776 }
777
778 void
insert_label_spin_with_limits(GtkWidget * table,char * ltext,GtkWidget ** spin,double spinval,double min,double max,int y1,int y2)779 insert_label_spin_with_limits(GtkWidget * table, char * ltext, GtkWidget ** spin, double spinval,
780 double min, double max, int y1, int y2) {
781
782
783 insert_label_spin(table, ltext, spin, spinval, y1, y2);
784 gtk_spin_button_set_range(GTK_SPIN_BUTTON(*spin), min, max);
785 gtk_spin_button_set_value(GTK_SPIN_BUTTON(*spin), spinval);
786 }
787
788
789 void
set_option_from_toggle(GtkWidget * widget,int * opt)790 set_option_from_toggle(GtkWidget * widget, int * opt) {
791
792 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
793 *opt = 1;
794 } else {
795 *opt = 0;
796 }
797 }
798
799 void
set_option_from_combo(GtkWidget * widget,int * opt)800 set_option_from_combo(GtkWidget * widget, int * opt) {
801
802 *opt = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
803 }
804
805 void
set_option_from_spin(GtkWidget * widget,int * opt)806 set_option_from_spin(GtkWidget * widget, int * opt) {
807
808 *opt = gtk_spin_button_get_value(GTK_SPIN_BUTTON(widget));
809 }
810
811 void
set_option_from_entry(GtkWidget * widget,char * opt,int n)812 set_option_from_entry(GtkWidget * widget, char * opt, int n) {
813
814 strncpy(opt, gtk_entry_get_text(GTK_ENTRY(widget)), n-1);
815 }
816
817 void
set_option_bit_from_toggle(GtkWidget * toggle,int * opt,int bit)818 set_option_bit_from_toggle(GtkWidget * toggle, int * opt, int bit) {
819
820 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle))) {
821 *opt |= bit;
822 } else {
823 *opt &= ~bit;
824 }
825 }
826
827 /* Functions to traverse leafs of a generic GtkTreeModel
828 * (used by file info dialog's prev/next file feature)
829 */
830 gboolean
tree_model_leaf_iter(GtkTreeModel * model,GtkTreeIter * iter,gboolean last,GtkTreeIter * out)831 tree_model_leaf_iter(GtkTreeModel * model, GtkTreeIter * iter, gboolean last, GtkTreeIter * out) {
832 if (gtk_tree_model_iter_has_child(model, iter)) {
833 GtkTreeIter child_iter;
834 gint nth = 0;
835 if (last) {
836 nth = gtk_tree_model_iter_n_children(model, iter) - 1;
837 }
838 if (!gtk_tree_model_iter_nth_child(model, &child_iter, iter, nth)) {
839 return FALSE;
840 } else {
841 return tree_model_leaf_iter(model, &child_iter, last, out);
842 }
843 } else {
844 *out = *iter;
845 return TRUE;
846 }
847 }
848
849 gboolean
tree_model_next_iter(GtkTreeModel * model,GtkTreeIter * iter,GtkTreeIter * next,int mindepth)850 tree_model_next_iter(GtkTreeModel * model, GtkTreeIter * iter, GtkTreeIter * next, int mindepth) {
851 GtkTreeIter copy = *iter;
852 if (gtk_tree_model_iter_next(model, ©)) {
853 *iter = copy;
854 return tree_model_leaf_iter(model, iter, FALSE, next);
855 } else {
856 GtkTreeIter parent_iter;
857 if (!gtk_tree_model_iter_parent(model, &parent_iter, iter)) {
858 return FALSE;
859 } else {
860 GtkTreePath * path = gtk_tree_model_get_path(model, &parent_iter);
861 if (gtk_tree_path_get_depth(path) <= mindepth) {
862 gtk_tree_path_free(path);
863 return FALSE;
864 }
865 gtk_tree_path_free(path);
866 return tree_model_next_iter(model, &parent_iter, next, mindepth);
867 }
868 }
869 }
870
871 gboolean
tree_model_prev_iter(GtkTreeModel * model,GtkTreeIter * iter,GtkTreeIter * prev,int mindepth)872 tree_model_prev_iter(GtkTreeModel * model, GtkTreeIter * iter, GtkTreeIter * prev, int mindepth) {
873 GtkTreePath * path = gtk_tree_model_get_path(model, iter);
874 if (gtk_tree_path_prev(path)) {
875 if (!gtk_tree_model_get_iter(model, iter, path)) {
876 gtk_tree_path_free(path);
877 return FALSE;
878 } else {
879 gtk_tree_path_free(path);
880 return tree_model_leaf_iter(model, iter, TRUE, prev);
881 }
882 } else {
883 GtkTreeIter parent_iter;
884 gtk_tree_path_free(path);
885 if (!gtk_tree_model_iter_parent(model, &parent_iter, iter)) {
886 return FALSE;
887 } else {
888 path = gtk_tree_model_get_path(model, &parent_iter);
889 if (gtk_tree_path_get_depth(path) <= mindepth) {
890 gtk_tree_path_free(path);
891 return FALSE;
892 }
893 gtk_tree_path_free(path);
894 return tree_model_prev_iter(model, &parent_iter, prev, mindepth);
895 }
896 }
897 }
898
899 // vim: shiftwidth=8:tabstop=8:softtabstop=8:
900
901