~pkgcrosswire/xiphos/main

« back to all changes in this revision

Viewing changes to src/gnome2/utilities.c

  • Committer: Dmitrijs Ledkovs
  • Date: 2010-11-14 00:38:52 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: dmitrij.ledkov@ubuntu.com-20101114003852-sjt227lz4qqi85xj
New upstream release 3.1.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * Xiphos Bible Study Tool
3
3
 * utilities.c - support functions
4
4
 *
5
 
 * Copyright (C) 2000-2009 Xiphos Developer Team
 
5
 * Copyright (C) 2000-2010 Xiphos Developer Team
6
6
 *
7
7
 * This program is free software; you can redistribute it and/or modify
8
8
 * it under the terms of the GNU General Public License as published by
27
27
#include <sys/stat.h>
28
28
#include <unistd.h>
29
29
#include <string.h>
 
30
#include <ctype.h>
30
31
#include <assert.h>
31
32
 
 
33
#include <gdk-pixbuf/gdk-pixbuf.h>
 
34
 
32
35
#include <gtk/gtk.h>
33
36
 
34
37
#include "gui/utilities.h"
50
53
#undef DATADIR
51
54
#include <windows.h>
52
55
#include <shellapi.h>
53
 
#endif /* WIN32 */
 
56
#include <winsock2.h>
 
57
#else
 
58
#include <sys/socket.h>
 
59
#include <netinet/in.h>
 
60
#endif /* !WIN32 */
 
61
#include <errno.h>
54
62
 
55
63
#ifdef USE_GTKMOZEMBED
56
64
#ifdef WIN32
373
381
 
374
382
        for (i = 0; alternative[i] != NULL; i++)
375
383
        {
376
 
                if (file == NULL &&  g_file_test (alternative[i], G_FILE_TEST_EXISTS))
 
384
                if (file == NULL &&  g_file_test (alternative[i], G_FILE_TEST_IS_REGULAR))
377
385
                {
378
386
                        file = alternative[i];
379
387
                }
556
564
 *   void
557
565
 */
558
566
 
559
 
void gui_load_module_tree(GtkWidget * tree)
 
567
void gui_load_module_tree(GtkWidget * tree, gboolean limited)
560
568
{
561
569
        GtkTreeStore *store;
562
570
        GtkTreeIter text;
563
571
        GtkTreeIter commentary;
564
572
        GtkTreeIter dictionary;
 
573
        GtkTreeIter glossary;
565
574
        GtkTreeIter devotional;
566
575
        GtkTreeIter book;
567
576
        GtkTreeIter map;
568
577
        GtkTreeIter image;
 
578
        GtkTreeIter cult;
569
579
        GtkTreeIter prayerlist;
570
580
        GList *tmp = NULL;
571
581
        GList *tmp2 = NULL;
582
592
        gtk_tree_store_append(store, &commentary, NULL);
583
593
        gtk_tree_store_set(store, &commentary, 0, _("Commentaries"), -1);
584
594
 
585
 
        /*  Dictionaries folders */
586
 
        gtk_tree_store_append(store, &dictionary, NULL);
587
 
        gtk_tree_store_set(store, &dictionary, 0, _("Dictionaries"), -1);
588
 
 
589
 
        /*  Devotionals folders */
590
 
        gtk_tree_store_append(store, &devotional, NULL);
591
 
        gtk_tree_store_set(store, &devotional, 0, _("Daily Devotionals"), -1);
592
 
 
593
 
        /*  General Books folders */
594
 
        gtk_tree_store_append(store, &book, NULL);
595
 
        gtk_tree_store_set(store, &book, 0, _("General Books"), -1);
596
 
 
597
 
        /*  Maps folders */
598
 
        gtk_tree_store_append(store, &map, NULL);
599
 
        gtk_tree_store_set(store, &map, 0, _("Maps"), -1);
600
 
 
601
 
        /*  Images folders */
602
 
        gtk_tree_store_append(store, &image, NULL);
603
 
        gtk_tree_store_set(store, &image, 0, _("Images"), -1);
604
 
 
605
 
        /*  Prayer lists folder */
606
 
        if (settings.prayerlist) {
607
 
                gtk_tree_store_append(store, &prayerlist, NULL);
608
 
                gtk_tree_store_set(store, &prayerlist, 0, _("Prayer List/Journal"), -1);
 
595
        if (!limited) {
 
596
                /*  Dictionaries folders */
 
597
                gtk_tree_store_append(store, &dictionary, NULL);
 
598
                gtk_tree_store_set(store, &dictionary, 0, _("Dictionaries"), -1);
 
599
 
 
600
                /*  Glossaries folders */
 
601
                gtk_tree_store_append(store, &glossary, NULL);
 
602
                gtk_tree_store_set(store, &glossary, 0, _("Glossaries"), -1);
 
603
 
 
604
                /*  Devotionals folders */
 
605
                gtk_tree_store_append(store, &devotional, NULL);
 
606
                gtk_tree_store_set(store, &devotional, 0, _("Daily Devotionals"), -1);
 
607
 
 
608
                /*  General Books folders */
 
609
                gtk_tree_store_append(store, &book, NULL);
 
610
                gtk_tree_store_set(store, &book, 0, _("General Books"), -1);
 
611
 
 
612
                /*  Maps folders */
 
613
                gtk_tree_store_append(store, &map, NULL);
 
614
                gtk_tree_store_set(store, &map, 0, _("Maps"), -1);
 
615
 
 
616
                /*  Images folders */
 
617
                gtk_tree_store_append(store, &image, NULL);
 
618
                gtk_tree_store_set(store, &image, 0, _("Images"), -1);
 
619
 
 
620
                /*  Cult folders */
 
621
                gtk_tree_store_append(store, &cult, NULL);
 
622
                gtk_tree_store_set(store, &cult, 0, _("Cult/Unorthodox"), -1);
 
623
 
 
624
                /*  Prayer lists folder */
 
625
                if (settings.prayerlist) {
 
626
                        gtk_tree_store_append(store, &prayerlist, NULL);
 
627
                        gtk_tree_store_set(store, &prayerlist, 0, _("Prayer List/Journal"), -1);
 
628
                }
609
629
        }
610
630
 
611
631
        tmp = mod_mgr_list_local_modules(settings.path_to_mods, TRUE);
612
632
 
613
633
        language_make_list(tmp, store,
614
634
                           text, commentary, map, image,
615
 
                           devotional, dictionary, book,
 
635
                           devotional, dictionary, glossary, book, cult,
616
636
                           NULL, NULL,
617
 
                           language_add_folders);
 
637
                           language_add_folders, limited);
618
638
 
619
639
        tmp2 = tmp;
620
640
        while (tmp2 != NULL) {
621
641
                info = (MOD_MGR *) tmp2->data;
622
642
 
623
 
                // see comment on similar code in src/main/sidebar.cc.
 
643
                /* see comment on similar code in src/main/sidebar.cc. */
624
644
 
625
 
                if (info->type[0] == 'B') {
 
645
                if ((info->type[0] == 'B') && !info->is_cult) {
626
646
                        add_module_to_language_folder(GTK_TREE_MODEL(store),
627
647
                                                      text, info->language,
628
648
                                                      info->name);
629
649
                }
630
 
                else if (info->type[0] == 'C') {
 
650
                else if ((info->type[0] == 'C') && !info->is_cult) {
631
651
                        add_module_to_language_folder(GTK_TREE_MODEL(store),
632
652
                                                      commentary, info->language,
633
653
                                                      info->name);
634
654
                }
635
 
                else if (info->is_maps) {
636
 
                        add_module_to_language_folder(GTK_TREE_MODEL(store),
637
 
                                                      map, info->language,
638
 
                                                      info->name);
639
 
                }
640
 
                else if (info->is_images) {
641
 
                        add_module_to_language_folder(GTK_TREE_MODEL(store),
642
 
                                                      image, info->language,
643
 
                                                      info->name);
644
 
                }
645
 
                else if (info->is_devotional) {
646
 
                        add_module_to_language_folder(GTK_TREE_MODEL(store),
647
 
                                                      devotional, info->language,
648
 
                                                      info->name);
649
 
                }
650
 
                else if (info->type[0] == 'L') {
651
 
                        add_module_to_language_folder(GTK_TREE_MODEL(store),
652
 
                                                      dictionary, info->language,
653
 
                                                      info->name);
654
 
                }
655
 
                else if (info->type[0] == 'G') {
656
 
                        gchar *gstype = main_get_mod_config_entry(info->name, "GSType");
657
 
                        if ((gstype == NULL) || strcmp(gstype, "PrayerList")) {
658
 
                                add_module_to_language_folder(GTK_TREE_MODEL(store),
659
 
                                                              book, info->language,
660
 
                                                              info->name);
661
 
                        }
662
 
                }
663
 
                else {
664
 
                        GS_warning(("mod `%s' unknown type `%s'",
665
 
                                    info->name, info->type));
 
655
                else if (!limited) {
 
656
                        if (info->is_cult) {
 
657
                                add_module_to_language_folder(GTK_TREE_MODEL(store),
 
658
                                                              cult, info->language,
 
659
                                                              info->name);
 
660
                        }
 
661
                        else if (info->is_maps) {
 
662
                                add_module_to_language_folder(GTK_TREE_MODEL(store),
 
663
                                                              map, info->language,
 
664
                                                              info->name);
 
665
                        }
 
666
                        else if (info->is_images) {
 
667
                                add_module_to_language_folder(GTK_TREE_MODEL(store),
 
668
                                                              image, info->language,
 
669
                                                              info->name);
 
670
                        }
 
671
                        else if (info->is_devotional) {
 
672
                                add_module_to_language_folder(GTK_TREE_MODEL(store),
 
673
                                                              devotional, info->language,
 
674
                                                              info->name);
 
675
                        }
 
676
                        else if (info->is_glossary) {
 
677
                                add_module_to_language_folder(GTK_TREE_MODEL(store),
 
678
                                                              glossary, info->language,
 
679
                                                              info->name);
 
680
                        }
 
681
                        else if (info->type[0] == 'L') {
 
682
                                add_module_to_language_folder(GTK_TREE_MODEL(store),
 
683
                                                              dictionary, info->language,
 
684
                                                              info->name);
 
685
                        }
 
686
                        else if (info->type[0] == 'G') {
 
687
                                gchar *gstype = main_get_mod_config_entry(info->name, "GSType");
 
688
                                if ((gstype == NULL) || strcmp(gstype, "PrayerList")) {
 
689
                                        add_module_to_language_folder(GTK_TREE_MODEL(store),
 
690
                                                                      book, info->language,
 
691
                                                                      info->name);
 
692
                                }
 
693
                        }
 
694
                        else {
 
695
                                GS_warning(("mod `%s' unknown type `%s'",
 
696
                                            info->name, info->type));
 
697
                        }
666
698
                }
667
699
 
668
700
                g_free(info->name);
676
708
        g_list_free(tmp);
677
709
 
678
710
        /* prayer list folders */
679
 
        if (settings.prayerlist) {
 
711
        if (!limited && settings.prayerlist) {
680
712
                tmp = get_list(PRAYER_LIST);
681
713
                while (tmp != NULL) {
682
714
                        add_module_to_prayerlist_folder(GTK_TREE_MODEL(store),
710
742
MOD_FONT *get_font(gchar * mod_name)
711
743
{
712
744
        MOD_FONT *mf;
713
 
        gchar file[250];
714
 
 
715
 
        sprintf(file, "%s/fonts.conf", settings.gSwordDir);
716
 
 
717
 
        mf = g_new(MOD_FONT, 1);
 
745
        static gchar *file = NULL;
 
746
 
 
747
        if (file == NULL)
 
748
                file = g_strdup_printf("%s/fonts.conf", settings.gSwordDir); /* not freed */
 
749
 
 
750
        mf = g_new0(MOD_FONT, 1);
718
751
        mf->mod_name = mod_name;
719
 
        mf->old_font = NULL;
720
 
        mf->old_gdk_font = NULL;
721
 
        mf->old_font_size = NULL;
722
 
        mf->new_font = NULL;
723
 
        mf->new_gdk_font = NULL;
724
 
        mf->new_font_size = NULL;
725
 
        mf->no_font = 0;
726
752
 
727
753
        mf->old_font = get_conf_file_item(file, mod_name, "Font");
728
754
        mf->old_gdk_font = get_conf_file_item(file, mod_name, "GdkFont");
729
755
        mf->old_font_size = get_conf_file_item(file, mod_name, "Fontsize");
 
756
 
730
757
        if ((mf->old_font == NULL) ||
731
758
            !strcmp(mf->old_font, "none")) {
732
 
                gchar *preferred_font =
733
 
                    main_get_mod_config_entry(mod_name, "Font");
734
 
 
735
 
                if (mf->old_font)
736
 
                        g_free(mf->old_font);
737
 
                if (preferred_font && (*preferred_font != '\0')) {
738
 
                        mf->old_font = g_strdup(preferred_font);
739
 
                } else {
740
 
                        mf->old_font = g_strdup("none");
 
759
                /* in absence of selected font, module can name its preference */
 
760
                gchar *preferred_font = main_get_mod_config_entry(mod_name, "Font");
 
761
                gchar *preferred_font_size = main_get_mod_config_entry(mod_name, "Fontsize");
 
762
 
 
763
                /* in absence of module preference, user can specify language pref */
 
764
                gchar *lang = main_get_mod_config_entry(mod_name, "Lang");
 
765
                gchar *lang_lang = g_strdup_printf("Language:%s",
 
766
                                                   (lang ? lang : ""));
 
767
                gchar *lang_font = get_conf_file_item(file, lang_lang, "Font");
 
768
                gchar *lang_size = get_conf_file_item(file, lang_lang, "Fontsize");
 
769
 
 
770
                g_free(mf->old_font);
 
771
 
 
772
                if (preferred_font && (*preferred_font != '\0'))
 
773
                        mf->old_font = preferred_font;
 
774
                else {
 
775
                        g_free(preferred_font);
 
776
                        /* next try: fallback to per-language choice */
 
777
                        if (lang_font && (*lang_font != '\0'))
 
778
                                mf->old_font = lang_font;
 
779
                        else {
 
780
                                /* nothing ever specified: utter default */
 
781
                                g_free(lang_font);
 
782
                                mf->old_font = g_strdup("none");
 
783
                        }
741
784
                }
742
 
        }
743
 
 
744
 
        if ((mf->old_font_size == NULL) ||
745
 
            !strcmp(mf->old_font_size, "+0")) {
746
 
                gchar *preferred_font_size =
747
 
                    main_get_mod_config_entry(mod_name, "Fontsize");
748
 
 
749
 
                if (mf->old_font_size)
 
785
 
 
786
                if ((mf->old_font_size == NULL) ||
 
787
                    !strcmp(mf->old_font_size, "+0")) {
750
788
                        g_free(mf->old_font_size);
751
 
                if (preferred_font_size && (*preferred_font_size != '\0')) {
752
 
                        mf->old_font_size = g_strdup(preferred_font_size);
753
 
                } else {
754
 
                        mf->old_font_size = g_strdup("+0");
 
789
 
 
790
                        if (preferred_font_size && (*preferred_font_size != '\0'))
 
791
                                mf->old_font_size = preferred_font_size;
 
792
                        else {
 
793
                                g_free(preferred_font_size);
 
794
                                if (lang_size && (*lang_size != '\0'))
 
795
                                        mf->old_font_size = lang_size;
 
796
                                else {
 
797
                                        g_free(lang_size);
 
798
                                        mf->old_font_size = g_strdup("+0");
 
799
                                }
 
800
                        }
755
801
                }
 
802
 
 
803
                g_free(lang);
756
804
        }
757
805
 
758
806
        return mf;
780
828
        if (mf->old_font) g_free(mf->old_font);
781
829
        if (mf->old_gdk_font) g_free(mf->old_gdk_font);
782
830
        if (mf->old_font_size) g_free(mf->old_font_size);
783
 
        //mf->new_font = NULL;
784
 
        //mf->new_gdk_font = NULL;
785
 
        //mf->new_font_size = NULL;
786
 
        //mf->no_font = 0;
787
831
        g_free(mf);
788
832
}
 
833
 
789
834
/******************************************************************************
790
835
 * Name
791
836
 *   remove_linefeeds
1043
1088
                   GtkTreeIter image,
1044
1089
                   GtkTreeIter devotional,
1045
1090
                   GtkTreeIter dictionary,
 
1091
                   GtkTreeIter glossary,
1046
1092
                   GtkTreeIter book,
 
1093
                   GtkTreeIter cult,
1047
1094
                   GtkTreeIter *update,
1048
1095
                   GtkTreeIter *uninstalled,
1049
 
                   void (*add)(GtkTreeModel *, GtkTreeIter, gchar **))
 
1096
                   void (*add)(GtkTreeModel *, GtkTreeIter, gchar **),
 
1097
                   gboolean limited)
1050
1098
{
1051
1099
        MOD_MGR *info;
1052
1100
        int i;
1071
1119
                }
1072
1120
 
1073
1121
                /* modtype analysis identical to add_to_folder calls. */
1074
 
                if (info->type[0] == 'B')
 
1122
                if (info->is_cult)
 
1123
                        language_add(info->language, LANGSET_CULT);
 
1124
                else if (info->type[0] == 'B')
1075
1125
                        language_add(info->language, LANGSET_BIBLE);
1076
1126
                else if (info->type[0] == 'C')
1077
1127
                        language_add(info->language, LANGSET_COMMENTARY);
1081
1131
                        language_add(info->language, LANGSET_IMAGE);
1082
1132
                else if (info->is_devotional)
1083
1133
                        language_add(info->language, LANGSET_DEVOTIONAL);
 
1134
                else if (info->is_glossary)
 
1135
                        language_add(info->language, LANGSET_GLOSSARY);
1084
1136
                else if (info->type[0] == 'L')
1085
1137
                        language_add(info->language, LANGSET_DICTIONARY);
1086
1138
                else if ((info->type[0] == 'G') &&
1103
1155
               language_get_type(LANGSET_BIBLE));
1104
1156
        (*add)(GTK_TREE_MODEL(store), commentary,
1105
1157
               language_get_type(LANGSET_COMMENTARY));
1106
 
        (*add)(GTK_TREE_MODEL(store), map,
1107
 
               language_get_type(LANGSET_MAP));
1108
 
        (*add)(GTK_TREE_MODEL(store), image,
1109
 
               language_get_type(LANGSET_IMAGE));
1110
 
        (*add)(GTK_TREE_MODEL(store), devotional,
1111
 
               language_get_type(LANGSET_DEVOTIONAL));
1112
 
        (*add)(GTK_TREE_MODEL(store), dictionary,
1113
 
               language_get_type(LANGSET_DICTIONARY));
1114
 
        (*add)(GTK_TREE_MODEL(store), book,
1115
 
               language_get_type(LANGSET_GENBOOK));
1116
 
        if ((update != NULL) && (uninstalled != NULL)) {
1117
 
                (*add)(GTK_TREE_MODEL(store), *update,
1118
 
                       language_get_type(LANGSET_UPDATE));
1119
 
                (*add)(GTK_TREE_MODEL(store), *uninstalled,
1120
 
                       language_get_type(LANGSET_UNINSTALLED));
1121
 
        }
1122
 
}
 
1158
        if (!limited) {
 
1159
                (*add)(GTK_TREE_MODEL(store), map,
 
1160
                       language_get_type(LANGSET_MAP));
 
1161
                (*add)(GTK_TREE_MODEL(store), image,
 
1162
                       language_get_type(LANGSET_IMAGE));
 
1163
                (*add)(GTK_TREE_MODEL(store), cult,
 
1164
                       language_get_type(LANGSET_CULT));
 
1165
                (*add)(GTK_TREE_MODEL(store), devotional,
 
1166
                       language_get_type(LANGSET_DEVOTIONAL));
 
1167
                (*add)(GTK_TREE_MODEL(store), glossary,
 
1168
                       language_get_type(LANGSET_GLOSSARY));
 
1169
                (*add)(GTK_TREE_MODEL(store), dictionary,
 
1170
                       language_get_type(LANGSET_DICTIONARY));
 
1171
                (*add)(GTK_TREE_MODEL(store), book,
 
1172
                       language_get_type(LANGSET_GENBOOK));
 
1173
                if ((update != NULL) && (uninstalled != NULL)) {
 
1174
                        (*add)(GTK_TREE_MODEL(store), *update,
 
1175
                               language_get_type(LANGSET_UPDATE));
 
1176
                        (*add)(GTK_TREE_MODEL(store), *uninstalled,
 
1177
                               language_get_type(LANGSET_UNINSTALLED));
 
1178
                }
 
1179
        }
 
1180
}
 
1181
 
 
1182
/******************************************************************************
 
1183
 * Name
 
1184
 *
 
1185
 *
 
1186
 * Synopsis
 
1187
 *   #include "gui/search_dialog.h"
 
1188
 *
 
1189
 *
 
1190
 *
 
1191
 * Description
 
1192
 *
 
1193
 *
 
1194
 * Return value
 
1195
 *
 
1196
 */
 
1197
 
 
1198
gchar *get_modlist_string(GList * mods)
 
1199
{
 
1200
        gchar *rv;
 
1201
        GString *str = g_string_new("");
 
1202
        GList *orig_mods = mods;
 
1203
 
 
1204
        while (mods != NULL) {
 
1205
                str = g_string_append(str, (gchar *) mods->data);
 
1206
                g_free(mods->data);
 
1207
                mods = g_list_next(mods);
 
1208
                if (mods != NULL)
 
1209
                        str = g_string_append_c(str, ',');
 
1210
        }
 
1211
        g_list_free(orig_mods);
 
1212
 
 
1213
        rv = g_strdup(str->str);
 
1214
        g_string_free(str, TRUE);
 
1215
        return rv;
 
1216
}
 
1217
 
 
1218
 
 
1219
 
 
1220
/******************************************************************************
 
1221
 * Name
 
1222
 *   get_current_list
 
1223
 *
 
1224
 * Synopsis
 
1225
 *   #include "gui/search_dialog.h"
 
1226
 *
 
1227
 *   GList *get_current_list(GtkTreeView *treeview)
 
1228
 *
 
1229
 * Description
 
1230
 *
 
1231
 *
 
1232
 * Return value
 
1233
 *   GList *
 
1234
 */
 
1235
 
 
1236
GList *get_current_list(GtkTreeView *treeview)
 
1237
{
 
1238
        GList *items = NULL;
 
1239
        gchar *buf;
 
1240
        GtkTreeModel *model;
 
1241
        GtkTreeIter iter;
 
1242
 
 
1243
        model = gtk_tree_view_get_model(treeview);
 
1244
        if (gtk_tree_model_get_iter_first(model, &iter)) {
 
1245
                do {
 
1246
                        gtk_tree_model_get(model, &iter, 1, &buf, -1);
 
1247
                        items =
 
1248
                            g_list_append(items,
 
1249
                                          (gchar *) g_strdup(buf));
 
1250
 
 
1251
                } while (gtk_tree_model_iter_next(model, &iter));
 
1252
        }
 
1253
        return items;
 
1254
}
 
1255
 
1123
1256
 
1124
1257
/*
1125
1258
 * caller must free the returned string.
1174
1307
//
1175
1308
// utility function to write out HTML.
1176
1309
//
 
1310
#ifdef min
 
1311
#undef min
 
1312
#endif
1177
1313
#define min(x,y)        ((x) < (y) ? (x) : (y))
1178
1314
 
1179
1315
void
1202
1338
                gtk_html_set_editable(html, FALSE);
1203
1339
#endif
1204
1340
 
 
1341
#ifdef USE_GTKMOZEMBED
 
1342
        // EVIL EVIL EVIL EVIL.
 
1343
        // crazy nonsense with xulrunner 1.9.2.3, failure to jump to anchor.
 
1344
        // force the issue by stuffing a javascript snippet inside <head></head>.
 
1345
        // there are forms of evil so dark that they should not be contemplated.
 
1346
        if (anchor || settings.special_anchor) {
 
1347
                gchar *buf;
 
1348
 
 
1349
                // first, scribble out everything up to the closing </head>.
 
1350
                buf = strstr(text, "</head>");  // yes, lowercase.
 
1351
                assert(buf != NULL);    // don't be so stupid as not to include <head></head>.
 
1352
                offset = buf - text;
 
1353
                gecko_html_write(html, text, offset);
 
1354
                len -= offset;
 
1355
 
 
1356
                // now write the javascript snippet.
 
1357
                buf = g_strdup_printf(
 
1358
                    "<script type=\"text/javascript\" language=\"javascript\">"
 
1359
                    " window.onload = function () { window.location.hash = \"%s\"; }"
 
1360
                    " </script>", (settings.special_anchor
 
1361
                                   ? settings.special_anchor
 
1362
                                   : anchor));
 
1363
                gecko_html_write(html, buf, strlen(buf));
 
1364
                g_free(buf);
 
1365
        }
 
1366
#endif /* USE_GTKMOZEMBED */
 
1367
 
1205
1368
        // html widgets are uptight about being handed
1206
1369
        // huge quantities of text -- producer/consumer problem,
1207
1370
        // and we mustn't overload the receiver.  10k chunks.
1436
1599
 
1437
1600
}
1438
1601
 
 
1602
//
 
1603
// Read aloud some text, i.e. the current verse.
 
1604
// Text is cleaned of '"', <tokens>, "&symbols;", and *n/*x strings,
 
1605
// then scribbled out the local static socket with (SayText "...").
 
1606
// Non-zero verse param is prefixed onto supplied text.
 
1607
//
 
1608
 
 
1609
#ifndef INVALID_SOCKET
 
1610
# define INVALID_SOCKET -1
 
1611
#endif
 
1612
 
 
1613
void
 
1614
ReadAloud(unsigned int verse, const char *suppliedtext)
 
1615
{
 
1616
        static int tts_socket = INVALID_SOCKET; // no initial connection.
 
1617
        static int use_counter = -2;    // to shortcircuit early uses.
 
1618
 
 
1619
        if (settings.readaloud ||       // read anything, or
 
1620
            (verse == 0)) {             // read what's handed us.
 
1621
                gchar *s, *t;
 
1622
 
 
1623
                // setup for communication.
 
1624
                if (tts_socket < 0) {
 
1625
                        struct sockaddr_in service;
 
1626
 
 
1627
                        if ((tts_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
 
1628
                                char msg[256];
 
1629
                                sprintf(msg, "ReadAloud disabled:\nsocket failed, %s",
 
1630
                                        strerror(errno));
 
1631
                                settings.readaloud = 0;
 
1632
                                gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
 
1633
                                                               (widgets.readaloud_item),
 
1634
                                                               settings.readaloud);
 
1635
                                gui_generic_warning(msg);
 
1636
                                return;
 
1637
                        }
 
1638
 
 
1639
                        // festival's port (1314) on localhost (127.0.0.1).
 
1640
                        memset(&service, 0, sizeof service);
 
1641
                        service.sin_family = AF_INET;
 
1642
                        service.sin_port = htons(1314);
 
1643
                        service.sin_addr.s_addr = htonl(0x7f000001);
 
1644
                        if (connect(tts_socket, (const struct sockaddr *)&service,
 
1645
                                    sizeof(service)) != 0) {
 
1646
                                StartFestival();
 
1647
#ifdef WIN32
 
1648
                                Sleep(2); // give festival a moment to init.
 
1649
#else
 
1650
                                sleep(2); // give festival a moment to init.
 
1651
#endif
 
1652
                                if (connect(tts_socket, (const struct sockaddr *)&service,
 
1653
                                            sizeof(service)) != 0) {
 
1654
                                        // it still didn't work -- missing.
 
1655
                                        char msg[256];
 
1656
                                        sprintf(msg, "%s\n%s, %s",
 
1657
                                                "TTS \"festival\" not started -- perhaps not installed",
 
1658
                                                "TTS connect failed", strerror(errno));
 
1659
                                        StopFestival(&tts_socket);
 
1660
                                        settings.readaloud = 0;
 
1661
                                        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
 
1662
                                                                       (widgets.readaloud_item),
 
1663
                                                                       settings.readaloud);
 
1664
                                        gui_generic_warning(msg);
 
1665
                                        return;
 
1666
                                }
 
1667
                        }
 
1668
                }
 
1669
 
 
1670
                // avoid speaking the first *2* times.
 
1671
                // (2 Display() calls are made during startup.)
 
1672
                // though speaking may be intended, startup speech is annoying.
 
1673
                if (verse && (++use_counter < 1))
 
1674
                        return;
 
1675
 
 
1676
                GString *text = g_string_new(NULL);
 
1677
                if (verse != 0)
 
1678
                        g_string_printf(text, "%d. ...  %s", verse, suppliedtext);
 
1679
                        // use of ". ..." is to induce proper pauses.
 
1680
                else
 
1681
                        g_string_printf(text, "%s", suppliedtext);
 
1682
                GS_message(("ReadAloud: dirty: %s\n", text->str));
 
1683
 
 
1684
                // clean: no <span> surrounding strongs/morph.
 
1685
                // i wish there was a regexp form of strstr().
 
1686
                for (s = strstr(text->str, "<span class=\"strongs\">");
 
1687
                     s;
 
1688
                     s = strstr(s, "<span class=\"strongs\">")) {
 
1689
                        if ((t = strstr(s, "</span>"))) {
 
1690
                                t += 6;
 
1691
                                while (s <= t)
 
1692
                                        *(s++) = ' ';
 
1693
                        } else {
 
1694
                                GS_message(("ReadAloud: Unmatched <span strong></span> in %s\n", s));
 
1695
                                goto out;
 
1696
                        }
 
1697
                }
 
1698
                for (s = strstr(text->str, "<span class=\"morph\">");
 
1699
                     s;
 
1700
                     s = strstr(s, "<span class=\"morph\">")) {
 
1701
                        if ((t = strstr(s, "</span>"))) {
 
1702
                                t += 6;
 
1703
                                while (s <= t)
 
1704
                                        *(s++) = ' ';
 
1705
                        } else {
 
1706
                                GS_message(("ReadAloud: Unmatched <span morph></span> in %s\n", s));
 
1707
                                goto out;
 
1708
                        }
 
1709
                }
 
1710
 
 
1711
                // clean: no quotes (conflict w/festival syntax).
 
1712
                for (s = strchr(text->str, '"'); s; s = strchr(s, '"'))
 
1713
                        *s = ' ';
 
1714
 
 
1715
                // clean: no <tokens>.
 
1716
                for (s = strchr(text->str, '<'); s; s = strchr(s, '<')) {
 
1717
                        if ((t = strchr(s, '>'))) {
 
1718
                                while (s <= t)
 
1719
                                        *(s++) = ' ';
 
1720
                        } else {
 
1721
                                GS_message(("ReadAloud: Unmatched <> in %s\n", s));
 
1722
                                goto out;
 
1723
                        }
 
1724
                }
 
1725
 
 
1726
                // clean: no &lt;...&gt; sequences.  (Strong's ref, "<1234>".)
 
1727
                for (s = strstr(text->str, "&lt;"); s; s = strstr(s, "&lt;")) {
 
1728
                        if ((t = strstr(s, "&gt;"))) {
 
1729
                                t += 3;
 
1730
                                while (s <= t)
 
1731
                                        *(s++) = ' ';
 
1732
                        } else {
 
1733
                                GS_message(("ReadAloud: Unmatched &lt;&gt; in %s\n", s));
 
1734
                                goto out;
 
1735
                        }
 
1736
                }
 
1737
 
 
1738
                // clean: no other &symbols;.
 
1739
                for (s = strchr(text->str, '&'); s; s = strchr(s, '&')) {
 
1740
                        if ((t = strchr(s, ';'))) {
 
1741
                                while (s <= t)
 
1742
                                        *(s++) = ' ';
 
1743
                        } else {
 
1744
                                GS_message(("ReadAloud: Incomplete &xxx; in %s\n", s));
 
1745
                                goto out;
 
1746
                        }
 
1747
                }
 
1748
 
 
1749
                // clean: no note/xref strings.
 
1750
                for (s = strstr(text->str, "*n"); s; s = strstr(s, "*n")) {
 
1751
                        *(s++) = ' ';
 
1752
                        *(s++) = ' ';
 
1753
                        while (isdigit(*s)) *(s++) = ' ';
 
1754
                }
 
1755
                for (s = strstr(text->str, "*u"); s; s = strstr(s, "*u")) {
 
1756
                        *(s++) = ' ';
 
1757
                        *(s++) = ' ';
 
1758
                }
 
1759
                for (s = strstr(text->str, "*x"); s; s = strstr(s, "*x")) {
 
1760
                        *(s++) = ' ';
 
1761
                        *(s++) = ' ';
 
1762
                        while (isdigit(*s)) *(s++) = ' ';
 
1763
                }
 
1764
 
 
1765
                // festival *pronounces* brackets and asterisks -- idiots.
 
1766
                for (s = strchr(text->str, '['); s; s = strchr(s, '['))
 
1767
                        *s = ' ';
 
1768
                for (s = strchr(text->str, ']'); s; s = strchr(s, ']'))
 
1769
                        *s = ' ';
 
1770
                for (s = strchr(text->str, '*'); s; s = strchr(s, '*'))
 
1771
                        *s = ' ';
 
1772
                // in case it isn't obvious, i'd really like a  standard
 
1773
                // function that walks a string for multiple individual chars.
 
1774
 
 
1775
                // walk the string, looking for dislocated "LORD" as "L<spaces>ORD".
 
1776
                // this occurs in "smallcaps" use in many bibles.
 
1777
                for (s = strchr(text->str, 'L'); s; s = strchr(s+1, 'L')) {
 
1778
                        gchar *begin = s++;
 
1779
                        while (*s == ' ')
 
1780
                                ++s;
 
1781
                        if (!strncmp(s, "ORD", 3)) {
 
1782
                                *begin = ' ';
 
1783
                                *(s-1) = 'L';
 
1784
                        }
 
1785
                }
 
1786
                // same song, second verse: G<spaces>OD.
 
1787
                for (s = strchr(text->str, 'G'); s; s = strchr(s+1, 'G')) {
 
1788
                        gchar *begin = s++;
 
1789
                        while (*s == ' ')
 
1790
                                ++s;
 
1791
                        if (!strncmp(s, "OD", 2)) {
 
1792
                                *begin = ' ';
 
1793
                                *(s-1) = 'G';
 
1794
                        }
 
1795
                }
 
1796
 
 
1797
                GS_message(("ReadAloud: clean: %s\n", text->str));
 
1798
                // scribble clean text to the socket.
 
1799
                if (FestivalSpeak(text->str, strlen(text->str), tts_socket) == FALSE)
 
1800
                {
 
1801
                        char msg[256];
 
1802
                        sprintf(msg, "TTS disappeared?\nTTS write failed: %s",
 
1803
                                strerror(errno));
 
1804
                        StopFestival(&tts_socket);
 
1805
                        settings.readaloud = 0;
 
1806
                        gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM
 
1807
                                                       (widgets.readaloud_item),
 
1808
                                                       settings.readaloud);
 
1809
                        gui_generic_warning(msg);
 
1810
                }
 
1811
 
 
1812
        out:
 
1813
                g_string_free(text, TRUE);
 
1814
                return;
 
1815
 
 
1816
        } else {
 
1817
 
 
1818
                // Reading aloud is disabled.
 
1819
                // If we had been reading, shut it down.
 
1820
                if (tts_socket >= 0) {
 
1821
                        StopFestival(&tts_socket);
 
1822
                }
 
1823
                use_counter++;
 
1824
                return;
 
1825
        }
 
1826
}
 
1827
 
 
1828
//
 
1829
// starts festival in a async process
 
1830
//
 
1831
void
 
1832
StartFestival(void)
 
1833
{
 
1834
#ifdef WIN32
 
1835
        //on windows, we will ship festival directly under Xiphos
 
1836
        gchar *festival_args[5];
 
1837
        gchar *festival_com = g_win32_get_package_installation_directory_of_module(NULL);
 
1838
        festival_com = g_strconcat(festival_com, "\0", NULL);
 
1839
        gchar *festival_lib = g_build_filename(festival_com, "festival\\lib\0");
 
1840
        festival_com = g_build_filename(festival_com, "festival\\festival.exe\0");
 
1841
        festival_args[0] = festival_com;
 
1842
        festival_args[1] = g_strdup("--libdir");
 
1843
        festival_args[2] = festival_lib;
 
1844
        festival_args[3] = g_strdup("--server");
 
1845
        festival_args[4] = NULL;
 
1846
#else
 
1847
        gchar *festival_args[3];
 
1848
        festival_args[0] = g_strdup("festival");
 
1849
        festival_args[1] = g_strdup("--server");
 
1850
        festival_args[2] = NULL;
 
1851
#endif
 
1852
        g_spawn_async ( NULL,
 
1853
                        festival_args,
 
1854
                        NULL,
 
1855
                        G_SPAWN_SEARCH_PATH,
 
1856
                        NULL,
 
1857
                        NULL,
 
1858
                        NULL,
 
1859
                        NULL);
 
1860
}
 
1861
 
 
1862
//
 
1863
// shuts down Festival
 
1864
//
 
1865
void
 
1866
StopFestival(int *tts_socket)
 
1867
{
 
1868
#ifdef WIN32
 
1869
        closesocket(*tts_socket);
 
1870
#else
 
1871
        shutdown(*tts_socket, SHUT_RDWR);
 
1872
        close(*tts_socket);
 
1873
#endif
 
1874
        *tts_socket = INVALID_SOCKET;
 
1875
}
 
1876
 
 
1877
//
 
1878
// tells Festival to say the given text
 
1879
//
 
1880
gboolean
 
1881
FestivalSpeak(gchar *text, int length, int tts_socket)
 
1882
{
 
1883
#ifdef WIN32
 
1884
        if ((send(tts_socket, "(SayText \"", 10, MSG_DONTROUTE) == INVALID_SOCKET)  ||
 
1885
            (send(tts_socket, text, length, MSG_DONTROUTE) == INVALID_SOCKET) ||
 
1886
            (send(tts_socket, "\")\r\n", 4, MSG_DONTROUTE) == INVALID_SOCKET ))
 
1887
                return FALSE;
 
1888
#else
 
1889
        if ((write(tts_socket, "(SayText \"", 10) < 0)  ||
 
1890
            (write(tts_socket, text, length ) < 0) ||
 
1891
            (write(tts_socket, "\")\r\n", 4) < 0))
 
1892
                return FALSE;
 
1893
#endif
 
1894
        return TRUE;
 
1895
}
 
1896
 
 
1897
#ifndef HAVE_STRCASESTR
 
1898
/*
 
1899
 * strcasestr() turns out to be nonstandard extension, but we need it.
 
1900
 */
 
1901
const char *
 
1902
strcasestr(const char *haystack, const char *needle)
 
1903
{
 
1904
        char *lower_haystack = g_strdup(haystack);
 
1905
        char *lower_needle = g_strdup(needle);
 
1906
        char *s;
 
1907
 
 
1908
        for (s = lower_haystack; *s; ++s)
 
1909
                if (isupper(*s))
 
1910
                        *s = tolower(*s);
 
1911
        for (s = lower_needle; *s; ++s)
 
1912
                if (isupper(*s))
 
1913
                        *s = tolower(*s);
 
1914
 
 
1915
        s = strstr(lower_haystack, lower_needle);
 
1916
        if (s)
 
1917
                s = (char *)haystack + (s - lower_haystack);
 
1918
 
 
1919
        g_free(lower_haystack);
 
1920
        g_free(lower_needle);
 
1921
        return s;
 
1922
}
 
1923
#endif /* !HAVE_STRCASESTR */
 
1924
 
 
1925
int
 
1926
ImageDimensions(const char *path, int *x, int *y)
 
1927
{
 
1928
 
 
1929
        if (gdk_pixbuf_get_file_info (path, x, y))
 
1930
                return 0;
 
1931
        else
 
1932
                return -1;
 
1933
}
 
1934
 
 
1935
#define IMGSRC_STRING   "<img src=\""
 
1936
#define IMGSRC_LENGTH   10              // strlen(IMGSRC_STRING)
 
1937
const char *strcasestr(const char *haystack, const char *needle);
 
1938
 
 
1939
const char *
 
1940
AnalyzeForImageSize(const char *origtext,
 
1941
                    GdkWindow *window)
 
1942
{
 
1943
        static GString *resized;
 
1944
        static gint resized_init = FALSE;
 
1945
 
 
1946
        const char *trail;      // "trail" trails behind ...
 
1947
        char *path;             // ... the current "path".
 
1948
        char *end;              // "end" is the path's end.
 
1949
        char buf[32];           // for preparing new width+height spec.
 
1950
        gint image_x, image_y, window_x, window_y = -999;
 
1951
        int image_retval;
 
1952
        gboolean no_warning_yet = TRUE;
 
1953
 
 
1954
        if (!resized_init) {
 
1955
                resized = g_string_new("");
 
1956
                resized_init = TRUE;
 
1957
        }
 
1958
 
 
1959
        // performance tweak:
 
1960
        // image content is by no means common. therefore, spend an extra
 
1961
        // search call to determine whether any of the rest is needed,
 
1962
        // most especially to stop copying large blocks of text w/no images.
 
1963
        if ((path = (char *)strcasestr(origtext, IMGSRC_STRING)) == NULL)
 
1964
                return origtext;
 
1965
 
 
1966
        for (resized = g_string_assign(resized, ""), trail = origtext
 
1967
                 /* and path was initialized just above */ ;
 
1968
             path;
 
1969
             path = (char *)strcasestr(path, IMGSRC_STRING)) {
 
1970
 
 
1971
                if (window_y == -999) {
 
1972
                        /* we have images, but we don't know bounds yet */
 
1973
 
 
1974
                        gdk_drawable_get_size(window, &window_x, &window_y);
 
1975
                        if ((window_x > 200) || (window_y > 200)) {
 
1976
                                window_x -= 23;
 
1977
                                window_y -= 23;
 
1978
                        } else {
 
1979
                                window_x = (window_x * 93)/100;
 
1980
                                window_y = (window_y * 93)/100;
 
1981
                        }
 
1982
                }
 
1983
 
 
1984
                /* add the working segment, with annotation added */
 
1985
                /* to keep us from matching IMGSRC_STRING again. */
 
1986
                path += IMGSRC_LENGTH;
 
1987
                resized = g_string_append_len(resized, trail, path-trail-5);
 
1988
                resized = g_string_append(resized, "resized=\"yes\" ");
 
1989
                resized = g_string_append_len(resized, path-5, 5);
 
1990
 
 
1991
                // some modules play fast-n-loose with proper file spec.
 
1992
                if (strncmp(path, "file://", 7) == 0) {
 
1993
                        path += 7;
 
1994
                        resized = g_string_append(resized, "file://");
 
1995
                } else if (strncmp(path, "file:", 5) == 0) {
 
1996
                        path += 5;
 
1997
                        resized = g_string_append(resized, "file:");
 
1998
                } else
 
1999
                        continue;       // no file spec there -- odd.
 
2000
 
 
2001
                // getting this far means we have a valid img src and file.
 
2002
                // find closing '"' to determine pathname end.
 
2003
                if ((end = strchr(path, '"')) == 0)
 
2004
                        continue;
 
2005
 
 
2006
                *end = '\0';
 
2007
                resized = g_string_append(resized, path);
 
2008
                image_retval = ImageDimensions(path, &image_x, &image_y);
 
2009
                *end = '"';
 
2010
 
 
2011
                resized = g_string_append_c(resized, '"');
 
2012
                path = end+1;
 
2013
                trail = path;
 
2014
 
 
2015
                if (image_retval != 0) {
 
2016
                        if (no_warning_yet) {
 
2017
                                gui_generic_warning(
 
2018
                                    _("An image file's size could not be determined.\n"
 
2019
                                      "Xiphos cannot resize images to fit window."));
 
2020
                                // settings.imageresize = 0;
 
2021
                                no_warning_yet = FALSE;
 
2022
                        }
 
2023
                        continue;
 
2024
                }
 
2025
 
 
2026
                // knowing image size & window size, adjust to fit.
 
2027
                if (image_x > window_x) {
 
2028
                        float proportion = (float)window_x / (float)image_x;
 
2029
                        image_x = window_x;
 
2030
                        image_y = (int)((float)image_y * proportion);
 
2031
                }
 
2032
                if (image_y > window_y) {
 
2033
                        float proportion = (float)window_y / (float)image_y;
 
2034
                        image_y = window_y;
 
2035
                        image_x = (int)((float)image_x * proportion);
 
2036
                }
 
2037
                sprintf(buf, " width=\"%d\" height=\"%d\"", image_x, image_y);
 
2038
                resized = g_string_append(resized, buf);
 
2039
        }
 
2040
 
 
2041
        resized = g_string_append(resized, trail);      // remainder of text appended.
 
2042
        return resized->str;
 
2043
}
 
2044
 
1439
2045
/******   end of file   ******/