1 /*
2  * Copyright 2008 Department of Mathematical Sciences, New Mexico State University
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * DEPARTMENT OF MATHEMATICAL SCIENCES OR NEW MEXICO STATE UNIVERSITY BE
18  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
19  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include "gbdfed.h"
24 #include "labcon.h"
25 
26 #ifdef HAVE_XLIB
27 #include <gdk/gdkx.h>
28 #endif
29 
30 /*
31  * These are formats that can appear in the editor for importing/loading and
32  * exporting fonts.
33  */
34 #define BDF_FORMAT     1
35 #define CONSOLE_FORMAT 2
36 #define PKGF_FORMAT    3
37 #define FNT_FORMAT     4
38 #define HBF_FORMAT     5
39 #define OTF_FORMAT     6
40 #define HEX_FORMAT     7
41 #define PSF_FORMAT     8
42 #define PSFUNI_FORMAT  9
43 
44 /*
45  * An array of filters used for the open/import and save dialogs.
46  */
47 static GtkFileFilter *filename_filters[10];
48 
49 /*
50  * This variable is used to track whether the save dialog has been closed
51  * so the guifile_save_as_wait() routine knows when to return to the main
52  * application.
53  */
54 static gboolean save_dialog_done;
55 
56 #ifdef HAVE_FREETYPE
57 
58 #include FT_GLYPH_H
59 #include FT_SFNT_NAMES_H
60 #include FT_TRUETYPE_TABLES_H
61 
62 /*
63  * Globals used for FreeType.
64  */
65 static FT_Library library;
66 static FT_Face face;
67 
68 /*
69  * Globals used for importing OpenType fonts.
70  */
71 static gboolean ftinit = FALSE;
72 static gboolean otf_collection;
73 static gboolean otf_face_open;
74 static gint otf_select_done = 0;
75 static gchar *otf_fullpath;
76 
77 /*
78  * These are the widgets that will be needed for importing OpenType fonts.
79  */
80 static GtkWidget *otf_dialog;
81 static GtkWidget *otf_faces;
82 static GtkWidget *otf_platforms;
83 static GtkWidget *otf_encodings;
84 static GtkWidget *otf_point_size;
85 static GtkWidget *otf_hres;
86 static GtkWidget *otf_vres;
87 
88 /*
89  * List of platform IDs seen that is used when platforms are selected
90  * from OpenType fonts.
91  */
92 static gint16 platforms[32];
93 static gint nplatforms;
94 
95 /*
96  * List of encoding IDs seen that is used when encodings are selected
97  * from OpenType fonts.
98  */
99 static gint16 encodings[34];
100 static gint nencodings;
101 
102 /*
103  * Variables to hold the selected platform and encoding ID's.
104  */
105 static gint16 otf_pid_pos;
106 static gint16 otf_eid_pos;
107 
108 #endif /* HAVE_FREETYPE */
109 
110 #ifdef HAVE_XLIB
111 
112 /*
113  * These are for importing fonts from the X server.
114  */
115 #define _XSRV_MAX_FONTS 32767
116 #define _XSRV_DEFAULT_FILTER "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"
117 
118 static GtkWidget *xsrv_dialog;
119 static GtkWidget *xsrv_filter_text;
120 static GtkWidget *xsrv_selection_text;
121 static GtkWidget *xsrv_font_list;
122 static GtkWidget *xsrv_import;
123 
124 /*
125  * Because the grab dialog is shared amongst the editors, this tracks which
126  * editor has control of the font list.
127  */
128 static guint xsrv_active_editor;
129 
130 #endif /* HAVE_XLIB */
131 
132 /*
133  * Widgets for dealing with exporting PSF fonts.
134  */
135 static GtkWidget *psf_export_frame;
136 static GtkWidget *psf_export_options;
137 
138 /*
139  * Widgets for selecting fonts from a Windows font archive.
140  */
141 static GtkWidget *fnt_dialog;
142 static GtkWidget *fnt_font_list;
143 static GtkWidget *fnt_load_button;
144 
145 /*
146  * This is a list of Windows fonts that have been selected.  It assumes that
147  * the font file will never contain more than 32 fonts.
148  */
149 static gint fnt_selected[32];
150 static gint fnt_selected_count;
151 
152 /*
153  * A structure used to pass data to the load and cancel callbacks when dealing
154  * with FON/FNT fonts.
155  */
156 typedef struct {
157     gchar *file;
158     gchar *dir;
159     gchar *dot;
160     bdffnt_font_t font;
161 } _bdffnt_callback_data_t;
162 
163 /*
164  * This is used in a couple of cases to point at the active editor.
165  */
166 static gbdfed_editor_t *active_editor;
167 
168 static void
make_file_chooser_filters(void)169 make_file_chooser_filters(void)
170 {
171     int i;
172 
173     if (filename_filters[0] != NULL)
174       return;
175 
176     filename_filters[BDF_FORMAT] = gtk_file_filter_new();
177     gtk_file_filter_add_pattern(filename_filters[BDF_FORMAT],
178                                 "*.[Bb][Dd][Ff]");
179 
180     filename_filters[CONSOLE_FORMAT] = gtk_file_filter_new();
181     gtk_file_filter_add_pattern(filename_filters[CONSOLE_FORMAT], "*");
182 
183     filename_filters[PKGF_FORMAT] = gtk_file_filter_new();
184     gtk_file_filter_add_pattern(filename_filters[PKGF_FORMAT],
185                                 "*[PpGg][KkFf]");
186 
187     filename_filters[FNT_FORMAT] = gtk_file_filter_new();
188     gtk_file_filter_add_pattern(filename_filters[FNT_FORMAT],
189                                 "*.[FfEeDd][OoNnXxLl][NnTtEeLl]");
190 
191     filename_filters[HEX_FORMAT] = gtk_file_filter_new();
192     gtk_file_filter_add_pattern(filename_filters[HEX_FORMAT],
193                                 "*.[Hh][Ee][Xx]");
194 
195     filename_filters[PSF_FORMAT] = gtk_file_filter_new();
196     gtk_file_filter_add_pattern(filename_filters[PSF_FORMAT],
197                                 "*.[Ps][Ss][Ff]*");
198 
199     /*
200      * This one is basically for exporting unimap files that belong to PSF
201      * fonts.
202      */
203     filename_filters[PSFUNI_FORMAT] = gtk_file_filter_new();
204     gtk_file_filter_add_pattern(filename_filters[PSFUNI_FORMAT],
205                                 "*.[Uu][Nn][Ii]");
206 
207 #ifdef HAVE_HBF
208     filename_filters[HBF_FORMAT] = gtk_file_filter_new();
209     gtk_file_filter_add_pattern(filename_filters[HBF_FORMAT],
210                                 "*.[Hh][Bb][Ff]");
211 #endif
212 
213 #ifdef HAVE_FREETYPE
214     filename_filters[OTF_FORMAT] = gtk_file_filter_new();
215     gtk_file_filter_add_pattern(filename_filters[OTF_FORMAT],
216                                 "*.[OoTt][Tt][FfCcEe]");
217 #endif /* HAVE_FREETYPE */
218 
219     filename_filters[0] = (GtkFileFilter *) 1;
220 
221     /*
222      * Add a reference to all the filters so they don't cause a delayed crash
223      * when popping up the import dialog multiple times.
224      */
225     for (i = 1; i < 10; i++) {
226         if (filename_filters[i] != NULL)
227           g_object_ref(filename_filters[i]);
228     }
229 }
230 
231 static gboolean
export_font(gchar * filename,gbdfed_editor_t * ed,gboolean copy_filename)232 export_font(gchar *filename, gbdfed_editor_t *ed, gboolean copy_filename)
233 {
234     FILE *out;
235     bdf_font_t *font;
236     gboolean local_font = FALSE;
237     bdf_property_t vanity;
238     FontgridSelectionInfo sinfo;
239 
240     font = fontgrid_get_font(FONTGRID(ed->fgrid));
241 
242     /*
243      * First, attempt to make a backup if they are specified.
244      */
245     if (options.backups) {
246         out = fopen(filename, "rb");
247         if (out != 0) {
248             fclose(out);
249 
250             /*
251              * Attempt to make a backup.
252              */
253             sprintf(buffer2, "%s.bak", filename);
254 
255             /*
256              * %PLATFORM_CHECK%
257              *
258              * Don't return here because we want to save the font even if a
259              * backup can't be made.
260              */
261             if (rename(filename, buffer2))
262               guiutil_error_message(ed->shell,
263                                     "Backups: Unable to make a backup.");
264         }
265     }
266 
267     /*
268      * Try to open the file for writing. Only PSF needs binary.
269      */
270     out = (ed->export_format != PSF_FORMAT) ?
271         fopen(filename, "w") : fopen(filename, "wb");
272 
273     if (out == 0) {
274         if (ed->export_format == BDF_FORMAT)
275           sprintf(buffer2, "Save Font: Unable to write to %s.", filename);
276         else
277           sprintf(buffer2, "Export Font: Unable to write to %s.", filename);
278         guiutil_error_message(ed->shell, buffer2);
279         return FALSE;
280     }
281 
282     switch (ed->export_format) {
283       case BDF_FORMAT:
284         if (!font) {
285             /*
286              * We need to create a font with the default options so it
287              * can be written out as a skeleton.
288              */
289             font = bdf_new_font("unnamed",
290                                 options.font_opts.point_size,
291                                 options.font_opts.resolution_x,
292                                 options.font_opts.resolution_y,
293                                 options.font_opts.font_spacing,
294                                 options.font_opts.bits_per_pixel);
295             local_font = TRUE;
296         }
297 
298         /*
299          * Add a custom property if the font has been
300          */
301         if (font->modified || local_font == TRUE) {
302             sprintf(buffer2, "Edited with gbdfed %s.", GBDFED_VERSION);
303             vanity.name = "_GBDFED_INFO";
304             vanity.format = BDF_ATOM;
305             vanity.value.atom = buffer2;
306             bdf_add_font_property(font, &vanity);
307         }
308         bdf_save_font(out, font, &options.font_opts, 0, 0);
309         if (local_font == TRUE)
310           bdf_free_font(font);
311         break;
312       case HEX_FORMAT:
313         bdf_export_hex(out, font, &options.font_opts, 0, 0);
314         break;
315       case PSF_FORMAT:
316         sinfo.start = sinfo.end = 0;
317         (void) fontgrid_has_selection(FONTGRID(ed->fgrid), &sinfo);
318         if (sinfo.start == sinfo.end) {
319             sinfo.start = font->glyphs[0].encoding;
320             sinfo.end = font->glyphs[font->glyphs_used - 1].encoding;
321         }
322         switch (bdf_export_psf(out, font, &options.font_opts,
323                                sinfo.start, sinfo.end)) {
324           case BDF_OK:
325             buffer1[0] = 0;
326             break;
327           case BDF_BAD_RANGE:
328             sprintf(buffer1, "Export PSF: Invalid range %d-%d.\n",
329                     sinfo.start, sinfo.end);
330             break;
331           case BDF_PSF_CORRUPT_UTF8:
332             strcpy(buffer1,
333                    "Export PSF: Bad UTF-8 encountered in the mappings.");
334             break;
335         }
336         if (buffer1[0] != 0)
337           /*
338            * Something went wrong during the PSF export.
339            */
340           guiutil_error_message(ed->shell, buffer1);
341     }
342 
343     fclose(out);
344 
345     /*
346      * The rest of this only applies to BDF fonts and not PSF or HEX fonts.
347      * PSF and HEX fonts have their own extensions in the save dialog, but
348      * that does not affect the actual file name in the editor.
349      */
350     if (ed->export_format == BDF_FORMAT) {
351 
352         /*
353          * Copy the path and filename into the editor if specified.
354          */
355         if (copy_filename) {
356             if (ed->path)
357               g_free(ed->path);
358             if (ed->file)
359               g_free(ed->file);
360             ed->path = ed->file = 0;
361             ed->file = g_path_get_basename(filename);
362             ed->path = g_path_get_dirname(filename);
363         }
364 
365         /*
366          * Mark the font as being unmodified.
367          */
368         fontgrid_set_font_modified(FONTGRID(ed->fgrid), FALSE);
369 
370         /*
371          * Update the window title accordingly.
372          */
373         if (ed->file)
374           sprintf(buffer1, "%s - %s", g_get_prgname(), ed->file);
375         else
376           sprintf(buffer1, "%s - (unnamed%d)", g_get_prgname(), ed->id);
377 
378         gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
379 
380         /*
381          * Since the font was saved as BDF, it is no longer marked as being
382          * imported.
383          */
384         ed->imported = FALSE;
385     }
386 
387     return TRUE;
388 }
389 
390 static void
really_save_font(guint ed_id)391 really_save_font(guint ed_id)
392 {
393     gbdfed_editor_t *ed = editors + ed_id;
394     gchar *fname;
395     FILE *have;
396 #if (GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 10)
397     GtkRecentManager *recent;
398 #endif
399 
400     fname = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(ed->save_dialog));
401 
402     have = fopen(fname, "rb");
403     if (have != 0) {
404         fclose(have);
405 
406         /*
407          * Check to see if the user wishes to overwrite the existing font.
408          */
409         sprintf(buffer2, "Save Font: %s exists.\nDo you wish to overwrite?",
410                 fname);
411         if (guiutil_yes_or_no(ed->shell, buffer2, TRUE) == FALSE) {
412             g_free(fname);
413             return;
414         }
415     }
416 
417     /*
418      * If the write was successful, hide the dialog.
419      */
420     if (export_font(fname, ed, TRUE)) {
421         save_dialog_done = TRUE;
422         gtk_widget_hide(ed->save_dialog);
423 #if (GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 10)
424         recent = gtk_recent_manager_get_default();
425         sprintf(buffer1, "file://%s", fname);
426         if (gtk_recent_manager_has_item(recent,
427                                         (const gchar *) buffer1) == FALSE)
428           gtk_recent_manager_add_item(recent,
429                                       (const gchar *) buffer1);
430 #endif
431     }
432     g_free(fname);
433 }
434 
435 /*
436  * This callback routine handles errors and updating the progress bar if
437  * one is being used.
438  */
439 static void
handle_import_messages(bdf_callback_struct_t * call_data,void * client_data)440 handle_import_messages(bdf_callback_struct_t *call_data, void *client_data)
441 {
442     if (call_data->reason == BDF_ERROR) {
443         sprintf(buffer1, "Import Font:%d: error: See the font messages.",
444                 call_data->errlineno);
445         guiutil_error_message(GTK_WIDGET(client_data), buffer1);
446     }
447 }
448 
449 /**************************************************************************
450  *
451  * BDF section.
452  *
453  **************************************************************************/
454 
455 static void
load_bdf_font(gbdfed_editor_t * ed,const gchar * fullpath,const gchar * dir,const gchar * file)456 load_bdf_font(gbdfed_editor_t *ed, const gchar *fullpath, const gchar *dir,
457               const gchar *file)
458 {
459     FILE *in;
460     bdf_font_t *font;
461 
462     /*
463      * Check to see if the file can be opened.
464      */
465     if ((in = fopen(fullpath, "rb")) == 0) {
466         sprintf(buffer1, "Import Font: Unable to open %s.", file);
467         guiutil_error_message(ed->shell, buffer1);
468         return;
469     }
470 
471     guiutil_busy_cursor(ed->shell, TRUE);
472     if (ed->open_dialog != NULL)
473       guiutil_busy_cursor(ed->open_dialog, TRUE);
474 
475     font = bdf_load_font(in, &options.font_opts,
476                          handle_import_messages, (void *) ed->shell);
477 
478     guiutil_busy_cursor(ed->shell, FALSE);
479     if (ed->open_dialog != NULL)
480       guiutil_busy_cursor(ed->open_dialog, FALSE);
481 
482     if (font == 0) {
483         fclose(in);
484         sprintf(buffer1, "Import Font: Unable to load %s.", file);
485         guiutil_error_message(ed->shell, buffer1);
486         return;
487     }
488 
489     fclose(in);
490     if (ed->open_dialog != NULL)
491       gtk_widget_hide(ed->open_dialog);
492 
493     /*
494      * Delete the file and path names so they can be updated.
495      */
496     if (ed->file != 0)
497       g_free(ed->file);
498     if (ed->path != 0)
499       g_free(ed->path);
500 
501     ed->file = ed->path = 0;
502 
503     ed->file = strdup(file);
504     ed->path = strdup(dir);
505 
506     /*
507      * Update the window title.
508      */
509     if (font->modified)
510       sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ed->file);
511     else
512       sprintf(buffer1, "%s - %s", g_get_prgname(), ed->file);
513 
514     gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
515 
516     /*
517      * Tell the glyphtest widget to remove references to the current font if
518      * it has any, and redraw.
519      */
520     if (glyphtest != 0)
521       glyphtest_remove_font(GLYPHTEST(glyphtest),
522                             fontgrid_get_font(FONTGRID(ed->fgrid)));
523 
524     fontgrid_set_font(FONTGRID(ed->fgrid), font, -1);
525 
526     /*
527      * Finally, update the font name field.
528      */
529     gtk_entry_set_text(GTK_ENTRY(ed->fontname),
530                        fontgrid_get_font_name(FONTGRID(ed->fgrid)));
531 
532     /*
533      * Make sure the imported flag is cleared in this case.
534      */
535     ed->imported = FALSE;
536 }
537 
538 /**************************************************************************
539  *
540  * Console section.
541  *
542  **************************************************************************/
543 
544 static void
load_console_font(gbdfed_editor_t * ed,gchar * fullpath,gchar * dot,gchar * dir,gchar * file)545 load_console_font(gbdfed_editor_t *ed, gchar *fullpath, gchar *dot,
546                   gchar *dir, gchar *file)
547 {
548     FILE *in;
549     gbdfed_editor_t *ep;
550     gint i, j, nfonts, len;
551     gchar *np;
552     bdf_font_t *fonts[3];
553 
554     /*
555      * Check to see if the file can be opened.
556      */
557     if ((in = fopen(fullpath, "rb")) == 0) {
558         sprintf(buffer1, "Import Font: Unable to open %s.", fullpath);
559         guiutil_error_message(ed->shell, buffer1);
560         return;
561     }
562 
563     guiutil_busy_cursor(ed->shell, TRUE);
564     guiutil_busy_cursor(ed->open_dialog, TRUE);
565 
566     i = bdf_load_console_font(in, &options.font_opts, 0, 0, fonts, &nfonts);
567 
568     guiutil_busy_cursor(ed->shell, FALSE);
569     guiutil_busy_cursor(ed->open_dialog, FALSE);
570 
571     fclose(in);
572 
573     if (i != BDF_OK) {
574         /*
575          * Free up any font structures that happened to be loaded.
576          */
577         for (j = 0; j < nfonts; j++)
578           bdf_free_font(fonts[j]);
579 
580         sprintf(buffer1, "Import Font: %s not a console font.", fullpath);
581         guiutil_error_message(ed->shell, buffer1);
582         return;
583     }
584 
585     gtk_widget_hide(ed->open_dialog);
586 
587     /*
588      * Handle creation of the editors.  In the case of some console fonts,
589      * there are three different sizes contained in the font.
590      */
591     for (i = 0; i < nfonts; i++) {
592         if (i)
593           ep = editors + gbdfed_make_editor(0, FALSE);
594         else {
595             ep = ed;
596 
597             /*
598              * Erase the existing file and directory name in the "root"
599              * editor.
600              */
601             if (ep->file)
602               g_free(ep->file);
603             if (ep->path)
604               g_free(ep->path);
605             ep->file = ep->path = 0;
606 
607             /*
608              * Tell the glyphtest widget to remove references to the current
609              * font, if it has any, and redraw.
610              */
611             if (glyphtest != 0)
612               glyphtest_remove_font(GLYPHTEST(glyphtest),
613                                     fontgrid_get_font(FONTGRID(ep->fgrid)));
614         }
615 
616         /*
617          * Make an XLFD name for the font using the filename.  Run through the
618          * file name and change all occurences of '-' to '_' to avoid problems
619          * with '-' being the XLFD field separator.
620          */
621         for (j = 0, np = file; np < dot; np++, j++)
622           buffer2[j] = (*np != '-') ? *np : '_';
623         buffer2[j] = 0;
624 
625         fonts[i]->name =
626             bdf_make_xlfd_name(fonts[i], "Unknown", buffer2);
627         bdf_update_properties_from_name(fonts[i]);
628 
629         len = (gint) (dot - file);
630 
631         /*
632          * Create the default name for the font file.
633          */
634         if (nfonts == 3) {
635             switch (i) {
636               case 0:
637                 sprintf(buffer1, "%.*s-16.bdf", len, file);
638                 break;
639               case 1:
640                 sprintf(buffer1, "%.*s-14.bdf", len, file);
641                 break;
642               case 2:
643                 sprintf(buffer1, "%.*s-08.bdf", len, file);
644                 break;
645             }
646         } else
647           sprintf(buffer1, "%.*s.bdf", len, file);
648 
649         /*
650          * Set the filename for the editor.
651          */
652         ep->file = strdup(buffer1);
653         ep->path = strdup(dir);
654 
655         /*
656          * Set the new editor title.
657          */
658         sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ep->file);
659         gtk_window_set_title(GTK_WINDOW(ep->shell), buffer1);
660 
661         /*
662          * Change the font in the editor.
663          */
664         fontgrid_set_font(FONTGRID(ep->fgrid), fonts[i], -1);
665 
666         /*
667          * Indicate the font was imported.
668          */
669         ed->imported = TRUE;
670 
671         /*
672          * Update the XLFD name.
673          */
674         gtk_entry_set_text(GTK_ENTRY(ep->fontname),
675                            fontgrid_get_font_name(FONTGRID(ep->fgrid)));
676     }
677 }
678 
679 /**************************************************************************
680  *
681  * PK/GF section.
682  *
683  **************************************************************************/
684 
685 static void
load_pkgf_font(gbdfed_editor_t * ed,gchar * fullpath,gchar * dot,gchar * dir,gchar * file)686 load_pkgf_font(gbdfed_editor_t *ed, gchar *fullpath, gchar *dot,
687                gchar *dir, gchar *file)
688 {
689     FILE *in;
690     gint i;
691     gchar *np;
692     bdf_font_t *font;
693 
694     /*
695      * Check to see if the file can be opened.
696      */
697     if ((in = fopen(fullpath, "rb")) == 0) {
698         sprintf(buffer1, "Import Font: Unable to open %s.", file);
699         guiutil_error_message(ed->shell, buffer1);
700         return;
701     }
702 
703     guiutil_busy_cursor(ed->shell, TRUE);
704     guiutil_busy_cursor(ed->open_dialog, TRUE);
705 
706     i = bdf_load_mf_font(in, &options.font_opts, 0, 0, &font);
707 
708     guiutil_busy_cursor(ed->shell, FALSE);
709     guiutil_busy_cursor(ed->open_dialog, FALSE);
710 
711     fclose(in);
712 
713     if (i != BDF_OK) {
714         sprintf(buffer1, "Import Font: %s not a PK or GF font.", fullpath);
715         guiutil_error_message(ed->shell, buffer1);
716         return;
717     }
718 
719     gtk_widget_hide(ed->open_dialog);
720 
721     /*
722      * Make an XLFD name for the font using the filename.  Run through the
723      * file name and change all occurences of '-' to '_' to avoid problems
724      * with '-' being the XLFD field separator.
725      */
726     for (i = 0, np = file; np < dot; np++, i++)
727       buffer2[i] = (*np != '-') ? *np : '_';
728     buffer2[i] = 0;
729 
730     font->name = bdf_make_xlfd_name(font, "Unknown", buffer2);
731     bdf_update_properties_from_name(font);
732 
733     /*
734      * Now set up a file name.
735      */
736     sprintf(buffer1, "%.*s.bdf", (int) (dot - file), file);
737 
738     /*
739      * Delete the file and path names so they can be updated.
740      */
741     if (ed->file != 0)
742       g_free(ed->file);
743     if (ed->path != 0)
744       g_free(ed->path);
745 
746     ed->file = strdup(buffer1);
747     ed->path = strdup(dir);
748 
749     /*
750      * Update the window title.
751      */
752     sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ed->file);
753     gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
754 
755     /*
756      * Tell the glyphtest widget to remove references to the current font if
757      * it has any, and redraw.
758      */
759     if (glyphtest != 0)
760       glyphtest_remove_font(GLYPHTEST(glyphtest),
761                             fontgrid_get_font(FONTGRID(ed->fgrid)));
762 
763     fontgrid_set_font(FONTGRID(ed->fgrid), font, -1);
764 
765     /*
766      * Indicate the font was imported.
767      */
768     ed->imported = TRUE;
769 
770     /*
771      * Finally, update the font name field.
772      */
773     gtk_entry_set_text(GTK_ENTRY(ed->fontname),
774                        fontgrid_get_font_name(FONTGRID(ed->fgrid)));
775 }
776 
777 /**************************************************************************
778  *
779  * FNT section.
780  *
781  **************************************************************************/
782 
783 /*
784  * Toggles the "Ok" button on or off depending if there was a selection or
785  * not.
786  */
787 static void
fnt_check_load_button(GtkWidget * w,gpointer data)788 fnt_check_load_button(GtkWidget *w, gpointer data)
789 {
790     GtkTreeSelection *sel = GTK_TREE_SELECTION(data);
791 
792     if (gtk_tree_selection_count_selected_rows(sel) == 0)
793       gtk_widget_set_sensitive(fnt_load_button, FALSE);
794     else
795       gtk_widget_set_sensitive(fnt_load_button, TRUE);
796 }
797 
798 static void
fnt_unselect_all(GtkWidget * w,gpointer data)799 fnt_unselect_all(GtkWidget *w, gpointer data)
800 {
801     GtkTreeSelection *sel = GTK_TREE_SELECTION(data);
802 
803     gtk_tree_selection_unselect_all(sel);
804 
805     /*
806      * Disable the Ok button since everything is unselected.
807      */
808     gtk_widget_set_sensitive(fnt_load_button, FALSE);
809 }
810 
811 static void
fnt_select_all(GtkWidget * w,gpointer data)812 fnt_select_all(GtkWidget *w, gpointer data)
813 {
814     GtkTreeSelection *sel = GTK_TREE_SELECTION(data);
815 
816     gtk_tree_selection_select_all(sel);
817 
818     /*
819      * Enable the Ok button since everything is unselected.
820      */
821     gtk_widget_set_sensitive(fnt_load_button, TRUE);
822 }
823 
824 static void
fnt_foreach_selected(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)825 fnt_foreach_selected(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
826                      gpointer data)
827 {
828     gint *id;
829 
830     id = gtk_tree_path_get_indices(path);
831     fnt_selected[fnt_selected_count++] = *id;
832 }
833 
834 static void
fnt_load_selected_fonts(GtkWidget * w,gpointer data)835 fnt_load_selected_fonts(GtkWidget *w, gpointer data)
836 {
837     gbdfed_editor_t *ep, *ed = editors + GPOINTER_TO_UINT(data);
838     GtkTreeSelection *sel =
839         gtk_tree_view_get_selection(GTK_TREE_VIEW(fnt_font_list));
840     gint i, nfonts;
841     gboolean loaded;
842     bdf_font_t **fonts;
843     _bdffnt_callback_data_t *cdata;
844 
845     fnt_selected_count = 0;
846 
847     if ((cdata = g_object_get_data(G_OBJECT(w),
848                                    "bdffnt_callback_data")) == NULL) {
849         /*
850          * Big problem.  Should never happen.
851          */
852         guiutil_error_message(editors[0].shell,
853                               "BIG PROBLEM PASSING OPEN FON/FNT FONT!!!!");
854         return;
855     }
856 
857     /*
858      * This collects all the selected indices from the list and puts them in
859      * the global fnt_selected array.
860      */
861     gtk_tree_selection_selected_foreach(sel, fnt_foreach_selected, NULL);
862 
863     /*
864      * CHANGE - maybe.
865      */
866     if (fnt_selected_count == 0)
867       return;
868 
869     /*
870      * Hide the dialog that allowed selection of the fonts in the file.
871      */
872     gtk_widget_hide(fnt_dialog);
873 
874     guiutil_busy_cursor(ed->shell, TRUE);
875     guiutil_busy_cursor(ed->open_dialog, TRUE);
876 
877     fonts = (bdf_font_t **)
878         g_malloc(sizeof(bdf_font_t *) * fnt_selected_count);
879     for (loaded = TRUE, nfonts = 0;
880          nfonts < fnt_selected_count && loaded == TRUE;
881          nfonts++) {
882         /*
883          * If the current font can't be loaded, then assume the rest are
884          * not available either.
885          */
886         if (bdffnt_load_font(cdata->font, fnt_selected[nfonts],
887                              0, 0, &fonts[nfonts]) != 0) {
888             /*
889              * It is easier to get the font name from the font than it is
890              * from the list store.
891              */
892             (void) bdffnt_get_facename(cdata->font, fnt_selected[nfonts], 0,
893                                        (unsigned char *) buffer1);
894             sprintf(buffer2, "Import Font: Unable to load %s from %s.",
895                     buffer1, cdata->file);
896             guiutil_error_message(ed->shell, buffer2);
897 
898             guiutil_busy_cursor(ed->shell, FALSE);
899             guiutil_busy_cursor(ed->open_dialog, FALSE);
900 
901             loaded = FALSE;
902         }
903     }
904 
905     guiutil_busy_cursor(ed->shell, FALSE);
906     guiutil_busy_cursor(ed->open_dialog, FALSE);
907 
908     /*
909      * If no fonts were loaded, then simply return with the open dialog still
910      * up, giving the user a chance to load another font.
911      */
912     if (nfonts == 0) {
913         g_free(fonts);
914         return;
915     }
916 
917     /*
918      * Hide the open dialog.
919      */
920     gtk_widget_hide(ed->open_dialog);
921 
922     /*
923      * Create the editors for the fonts that did get loaded.
924      */
925     for (i = 0; i < nfonts; i++) {
926         if (i)
927           ep = editors + gbdfed_make_editor(0, FALSE);
928         else {
929             ep = ed;
930 
931             /*
932              * Erase the existing file and directory name in the "root"
933              * editor.
934              */
935             if (ep->file)
936               g_free(ep->file);
937             if (ep->path)
938               g_free(ep->path);
939             ep->file = ep->path = 0;
940 
941             /*
942              * Tell the glyphtest widget to remove references to the current
943              * font, if it has any, and redraw.
944              */
945             if (glyphtest != 0)
946               glyphtest_remove_font(GLYPHTEST(glyphtest),
947                                     fontgrid_get_font(FONTGRID(ep->fgrid)));
948         }
949 
950         /*
951          * Make the BDF file name for the font.
952          */
953         sprintf(buffer1, "%.*s%d.bdf", (int) (cdata->dot - cdata->file),
954                 cdata->file, fonts[i]->point_size);
955 
956         ep->file = strdup(buffer1);
957         ep->path = strdup(cdata->dir);
958 
959         /*
960          * Set the new editor title.
961          */
962         sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ep->file);
963         gtk_window_set_title(GTK_WINDOW(ep->shell), buffer1);
964 
965         /*
966          * Change the font in the editor.
967          */
968         fontgrid_set_font(FONTGRID(ep->fgrid), fonts[i], -1);
969 
970         /*
971          * Indicate the font was imported.
972          */
973         ep->imported = TRUE;
974 
975         /*
976          * Update the XLFD name.
977          */
978         gtk_entry_set_text(GTK_ENTRY(ep->fontname),
979                            fontgrid_get_font_name(FONTGRID(ep->fgrid)));
980     }
981 
982     g_free(cdata->file);
983     g_free(cdata->dir);
984     bdffnt_close_font(cdata->font);
985 
986     g_free(fonts);
987 }
988 
989 static void
fnt_cancel(GtkWidget * w,gpointer data)990 fnt_cancel(GtkWidget *w, gpointer data)
991 {
992     _bdffnt_callback_data_t *cdata;
993 
994     /*
995      * If the load callback stole the data already, this will be NULL.
996      */
997     if ((cdata = g_object_get_data(G_OBJECT(w),
998                                    "bdffnt_callback_data")) == NULL) {
999         /*
1000          * Big problem.  Should never happen.
1001          */
1002         guiutil_error_message(editors[0].shell,
1003                               "BIG PROBLEM PASSING OPEN FON/FNT FONT!!!!");
1004         return;
1005     }
1006 
1007     g_free(cdata->file);
1008     g_free(cdata->dir);
1009     bdffnt_close_font(cdata->font);
1010 
1011     gtk_widget_hide(fnt_dialog);
1012 }
1013 
1014 static void
fnt_row_activate(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)1015 fnt_row_activate(GtkTreeView *view, GtkTreePath *path, GtkTreeViewColumn *col,
1016                  gpointer data)
1017 {
1018     fnt_load_selected_fonts(GTK_WIDGET(view), data);
1019 }
1020 
1021 static void
load_windows_font(gbdfed_editor_t * ed,gchar * fullpath,gchar * dot,gchar * dir,gchar * file)1022 load_windows_font(gbdfed_editor_t *ed, gchar *fullpath, gchar *dot,
1023                   gchar *dir, gchar *file)
1024 {
1025     gint i, nfonts;
1026     bdffnt_font_t fnt;
1027     bdf_font_t *font;
1028     _bdffnt_callback_data_t *cdata;
1029     GtkWidget *button, *vbox, *hbox, *swin;
1030     GtkListStore *store;
1031     GtkTreeViewColumn *column;
1032     GtkCellRenderer *cell_renderer;
1033     GtkTreeSelection *sel;
1034     GtkTreePath *tpath;
1035     GtkTreeIter iter;
1036 
1037     if (bdffnt_open_font(fullpath, &fnt) <= 0) {
1038         sprintf(buffer1, "Import Font: Unable to open %s.", file);
1039         guiutil_error_message(ed->shell, buffer1);
1040         g_free(dir);
1041         return;
1042     }
1043 
1044     nfonts = bdffnt_font_count(fnt);
1045 
1046     if (nfonts == 1) {
1047         guiutil_busy_cursor(ed->shell, TRUE);
1048         guiutil_busy_cursor(ed->open_dialog, TRUE);
1049 
1050         if (bdffnt_load_font(fnt, 0, 0, 0, &font) != 0) {
1051             sprintf(buffer1, "Import Font: Unable to load %s.", file);
1052             guiutil_error_message(ed->shell, buffer1);
1053             g_free(dir);
1054 
1055             guiutil_busy_cursor(ed->shell, FALSE);
1056             guiutil_busy_cursor(ed->open_dialog, FALSE);
1057 
1058             return;
1059         }
1060 
1061         guiutil_busy_cursor(ed->shell, FALSE);
1062         guiutil_busy_cursor(ed->open_dialog, FALSE);
1063 
1064         gtk_widget_hide(ed->open_dialog);
1065 
1066         /*
1067          * Now set up a file name.
1068          */
1069         sprintf(buffer1, "%.*s.bdf", (int) (dot - file), file);
1070 
1071         /*
1072          * Delete the file and path names so they can be updated.
1073          */
1074         if (ed->file != 0)
1075           g_free(ed->file);
1076         if (ed->path != 0)
1077           g_free(ed->path);
1078 
1079         ed->file = strdup(buffer1);
1080         ed->path = strdup(dir);
1081 
1082         /*
1083          * Update the window title.
1084          */
1085         sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ed->file);
1086         gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
1087 
1088         /*
1089          * Tell the glyphtest widget to remove references to the current font
1090          * if it has any, and redraw.
1091          */
1092         if (glyphtest != 0)
1093           glyphtest_remove_font(GLYPHTEST(glyphtest),
1094                                 fontgrid_get_font(FONTGRID(ed->fgrid)));
1095 
1096         fontgrid_set_font(FONTGRID(ed->fgrid), font, -1);
1097 
1098         /*
1099          * Indicate the font was imported.
1100          */
1101         ed->imported = TRUE;
1102 
1103         /*
1104          * Finally, update the font name field.
1105          */
1106         gtk_entry_set_text(GTK_ENTRY(ed->fontname),
1107                            fontgrid_get_font_name(FONTGRID(ed->fgrid)));
1108         return;
1109     }
1110 
1111     /*
1112      * More than one font was found.  Present the dialog to choose the fonts.
1113      */
1114     if (fnt_dialog == 0) {
1115         /*
1116          * Create a structure that will hold data needed by a couple callback
1117          * routines.
1118          */
1119         cdata = g_malloc(sizeof(_bdffnt_callback_data_t));
1120         cdata->file = strdup(file);
1121         cdata->dir = strdup(dir);
1122         cdata->dot = cdata->file + (dot - file);
1123         cdata->font = fnt;
1124 
1125         fnt_dialog = gtk_dialog_new();
1126         gtk_window_set_title(GTK_WINDOW(fnt_dialog), "Windows Font Selection");
1127 
1128         g_object_set_data(G_OBJECT(fnt_dialog), "bdffnt_callback_data",
1129                           (gpointer) cdata);
1130 
1131         (void) g_signal_connect(G_OBJECT(fnt_dialog), "delete_event",
1132                                 G_CALLBACK(fnt_cancel), 0);
1133 
1134         vbox = GTK_DIALOG(fnt_dialog)->vbox;
1135         hbox = GTK_DIALOG(fnt_dialog)->action_area;
1136 
1137         swin = gtk_scrolled_window_new(0, 0);
1138         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
1139                                        GTK_POLICY_AUTOMATIC,
1140                                        GTK_POLICY_ALWAYS);
1141 
1142         store = gtk_list_store_new(1, G_TYPE_STRING);
1143         fnt_font_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1144         g_object_unref(store);
1145 
1146         g_object_set_data(G_OBJECT(fnt_font_list), "bdffnt_callback_data",
1147                           (gpointer) cdata);
1148 
1149         gtk_widget_set_size_request(fnt_font_list, -1, 160);
1150 
1151         cell_renderer = gtk_cell_renderer_text_new();
1152         column = gtk_tree_view_column_new_with_attributes("Fonts: 0",
1153                                                           cell_renderer,
1154                                                           "text", 0,
1155                                                           NULL);
1156 
1157         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1158         gtk_tree_view_append_column(GTK_TREE_VIEW(fnt_font_list), column);
1159         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(fnt_font_list));
1160 
1161         (void) g_signal_connect(G_OBJECT(sel), "changed",
1162                                 G_CALLBACK(fnt_check_load_button),
1163                                 (gpointer) sel);
1164 
1165         gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
1166 
1167         (void) g_signal_connect(G_OBJECT(fnt_font_list), "row_activated",
1168                                 G_CALLBACK(fnt_row_activate),
1169                                 GUINT_TO_POINTER(ed->id));
1170 
1171         gtk_container_add(GTK_CONTAINER(swin), fnt_font_list);
1172 
1173         gtk_box_pack_start(GTK_BOX(vbox), swin, FALSE, FALSE, 0);
1174 
1175         button = gtk_button_new_with_label("Select All");
1176 
1177         (void) g_signal_connect(G_OBJECT(button), "clicked",
1178                                 G_CALLBACK(fnt_select_all),
1179                                 (gpointer) sel);
1180 
1181         gtk_container_add(GTK_CONTAINER(hbox), button);
1182 
1183         button = gtk_button_new_from_stock(GTK_STOCK_CLEAR);
1184 
1185         (void) g_signal_connect(G_OBJECT(button), "clicked",
1186                                 G_CALLBACK(fnt_unselect_all),
1187                                 (gpointer) sel);
1188 
1189         gtk_container_add(GTK_CONTAINER(hbox), button);
1190 
1191         button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1192 
1193         (void) g_signal_connect(G_OBJECT(button), "clicked",
1194                                 G_CALLBACK(fnt_cancel),
1195                                 GUINT_TO_POINTER(ed->id));
1196 
1197         gtk_container_add(GTK_CONTAINER(hbox), button);
1198 
1199         fnt_load_button = gtk_button_new_from_stock(GTK_STOCK_OK);
1200 
1201         /*
1202          * Here we store a bunch of data to the buttons that are necessary to
1203          * load FON/FNT fonts in the callback.
1204          */
1205         g_object_set_data(G_OBJECT(fnt_load_button), "bdffnt_callback_data",
1206                           (gpointer) cdata);
1207         g_object_set_data(G_OBJECT(button), "bdffnt_callback_data",
1208                           (gpointer) cdata);
1209 
1210         (void) g_signal_connect(G_OBJECT(fnt_load_button), "clicked",
1211                                 G_CALLBACK(fnt_load_selected_fonts),
1212                                 GUINT_TO_POINTER(ed->id));
1213 
1214         gtk_container_add(GTK_CONTAINER(hbox), fnt_load_button);
1215 
1216         gtk_widget_show_all(vbox);
1217         gtk_widget_show_all(hbox);
1218     } else {
1219         /*
1220          * Fill the CDATA item in with the latest info.
1221          */
1222         cdata = g_object_get_data(G_OBJECT(fnt_load_button),
1223                                   "bdffnt_callback_data");
1224         cdata->file = strdup(file);
1225         cdata->dir = strdup(dir);
1226         cdata->dot = cdata->file + (dot - file);
1227         cdata->font = fnt;
1228     }
1229 
1230     store =
1231         GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(fnt_font_list)));
1232     column = gtk_tree_view_get_column(GTK_TREE_VIEW(fnt_font_list), 0);
1233     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(fnt_font_list));
1234 
1235     /*
1236      * Set the number of fonts.
1237      */
1238     sprintf(buffer1, "Fonts: %d", nfonts);
1239     gtk_tree_view_column_set_title(column, buffer1);
1240 
1241     /*
1242      * Clear the list and add the font names.
1243      */
1244     gtk_list_store_clear(store);
1245     for (i = 0; i < nfonts; i++) {
1246         (void) bdffnt_get_facename(fnt, i, 0, (unsigned char *) buffer1);
1247         gtk_list_store_append(store, &iter);
1248         gtk_list_store_set(store, &iter, 0, buffer1, -1);
1249     }
1250 
1251     /*
1252      * Force the first one to be selected by default.
1253      */
1254     tpath = gtk_tree_path_new_from_indices(0, -1);
1255     gtk_tree_selection_select_path(sel, tpath);
1256 
1257     /*
1258      * Show the dialog and wait until the selection is done.
1259      */
1260     guiutil_show_dialog_centered(fnt_dialog, ed->shell);
1261 
1262     /*
1263      * Force the user to interact with this dialog before doing anything else.
1264      */
1265     gtk_window_set_modal(GTK_WINDOW(fnt_dialog), TRUE);
1266 }
1267 
1268 /**************************************************************************
1269  *
1270  * OTF section.
1271  *
1272  **************************************************************************/
1273 
1274 #ifdef HAVE_FREETYPE
1275 
1276 static void
choose_otf_encoding(GtkTreeSelection * selection,gpointer data)1277 choose_otf_encoding(GtkTreeSelection *selection, gpointer data)
1278 {
1279     gint *rows;
1280     GtkTreeModel *model;
1281     GtkTreeIter iter;
1282     GtkTreePath *tpath;
1283 
1284     /*
1285      * Get the row of the current selection.
1286      */
1287     if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
1288       return;
1289     tpath = gtk_tree_model_get_path(model, &iter);
1290     rows = gtk_tree_path_get_indices(tpath);
1291     otf_eid_pos = (gint16) rows[0];
1292 }
1293 
1294 static void
choose_otf_platform(GtkTreeSelection * selection,gpointer data)1295 choose_otf_platform(GtkTreeSelection *selection, gpointer data)
1296 {
1297     gchar *name;
1298     gint i, ncmaps, sel, *rows;
1299     gint16 pid, eid, lasteid;
1300     GtkTreeModel *model;
1301     GtkListStore *store;
1302     GtkTreeIter iter;
1303     GtkTreePath *tpath;
1304     GtkTreeView *tview;
1305 
1306     /*
1307      * Get the row of the current selection.
1308      */
1309     if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
1310       return;
1311     tpath = gtk_tree_model_get_path(model, &iter);
1312     rows = gtk_tree_path_get_indices(tpath);
1313     otf_pid_pos = (gint16) rows[0];
1314 
1315     /*
1316      * Clear the encoding list.
1317      */
1318     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(otf_encodings)));
1319     gtk_list_store_clear(store);
1320 
1321     /*
1322      * Collect the list of encoding IDs and put their names in the encoding
1323      * list.
1324      */
1325     nencodings = 0;
1326     ncmaps = face->num_charmaps;
1327     for (lasteid = -1, sel = i = 0; i < ncmaps; i++) {
1328         pid = face->charmaps[i]->platform_id;
1329         eid = face->charmaps[i]->encoding_id;
1330         if (pid == platforms[otf_pid_pos] && eid != lasteid) {
1331             name = bdfotf_encoding_name(pid, eid);
1332             if (strcmp(name, "ISO10646") == 0)
1333               sel = nencodings;
1334             gtk_list_store_append(store, &iter);
1335             gtk_list_store_set(store, &iter, 0, name, -1);
1336             encodings[nencodings++] = eid;
1337             lasteid = eid;
1338         }
1339     }
1340 
1341     /*
1342      * Default the selection to the ISO10646 encoding.
1343      */
1344     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(otf_encodings));
1345     tpath = gtk_tree_path_new_from_indices(sel, -1);
1346     gtk_tree_selection_select_path(selection, tpath);
1347 
1348     /*
1349      * Make sure the encoding is made visible.
1350      */
1351     tview = gtk_tree_selection_get_tree_view(selection);
1352     gtk_tree_view_scroll_to_cell(tview, tpath, NULL, TRUE, 0.5, 0.5);
1353 }
1354 
1355 static void
choose_otf(GtkTreeSelection * selection,gpointer data)1356 choose_otf(GtkTreeSelection *selection, gpointer data)
1357 {
1358     gchar *name;
1359     gint i, ncmaps, sel, row, *rows;
1360     gint16 pid, eid, lastpid;
1361     GtkTreeModel *model;
1362     GtkListStore *store;
1363     GtkTreeIter iter;
1364     GtkTreePath *tpath;
1365     GtkTreeView *tview;
1366     GValue val;
1367 
1368     /*
1369      * This is called after the list is cleared as well, so return if there is
1370      * no selection.
1371      */
1372     if (gtk_tree_selection_get_selected(selection, &model, &iter) == FALSE)
1373       return;
1374 
1375     /*
1376      * Get the name of the face currently selected and it's index.  This is
1377      * way more complicated than it should be.
1378      */
1379     (void) memset((char *) &val, 0, sizeof(GValue));
1380     tpath = gtk_tree_model_get_path(model, &iter);
1381     rows = gtk_tree_path_get_indices(tpath);
1382     row = rows[0];
1383 
1384     /*
1385      * Clear the platform list before trying to open the new face.
1386      */
1387     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(otf_platforms)));
1388     gtk_list_store_clear(store);
1389 
1390     if (otf_collection) {
1391         if (otf_face_open)
1392           FT_Done_Face(face);
1393         if (FT_New_Face(library, otf_fullpath, row, &face)) {
1394             otf_face_open = FALSE;
1395             gtk_tree_selection_get_selected(selection, &model, &iter);
1396             gtk_tree_model_get_value(model, &iter, 0, &val);
1397             name = (gchar *) g_value_get_string(&val);
1398             sprintf(buffer1,
1399                     "Import Font: Unable to open OpenType collection %s.",
1400                     name);
1401             g_value_unset(&val);
1402             guiutil_error_message(active_editor->shell, buffer1);
1403             return;
1404         }
1405         otf_face_open = TRUE;
1406     }
1407 
1408     /*
1409      * Collect the list of platform IDs and put their names in the platform
1410      * list.
1411      */
1412     nplatforms = 0;
1413     ncmaps = face->num_charmaps;
1414     for (lastpid = -1, sel = i = 0; i < ncmaps; i++) {
1415         pid = face->charmaps[i]->platform_id;
1416         eid = face->charmaps[i]->encoding_id;
1417         if (pid != lastpid) {
1418             /*
1419              * Add the platform name to the list.  If the name happens to be
1420              * Microsoft, select it as the default.
1421              */
1422             name = bdfotf_platform_name(pid);
1423             if (strcmp(name, "Microsoft") == 0)
1424               sel = nplatforms;
1425             gtk_list_store_append(store, &iter);
1426             gtk_list_store_set(store, &iter, 0, name, -1);
1427             platforms[nplatforms++] = pid;
1428             lastpid = pid;
1429         }
1430     }
1431 
1432     /*
1433      * Select the default platform, which is hard-coded to be Microsoft at the
1434      * moment.
1435      */
1436     selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(otf_platforms));
1437     tpath = gtk_tree_path_new_from_indices(sel, -1);
1438     gtk_tree_selection_select_path(selection, tpath);
1439 
1440     /*
1441      * Make sure the platform is made visible.
1442      */
1443     tview = gtk_tree_selection_get_tree_view(selection);
1444     gtk_tree_view_scroll_to_cell(tview, tpath, NULL, TRUE, 0.5, 0.5);
1445 }
1446 
1447 static void
otf_dialog_done(GtkWidget * w,gpointer data)1448 otf_dialog_done(GtkWidget *w, gpointer data)
1449 {
1450     otf_select_done = GPOINTER_TO_INT(data);
1451     gtk_widget_hide(otf_dialog);
1452 }
1453 
1454 static void
otf_reset_metrics(GtkWidget * w,gpointer data)1455 otf_reset_metrics(GtkWidget *w, gpointer data)
1456 {
1457     gtk_spin_button_set_value(GTK_SPIN_BUTTON(otf_point_size),
1458                               (gfloat) options.font_opts.point_size);
1459     gtk_spin_button_set_value(GTK_SPIN_BUTTON(otf_hres),
1460                               (gfloat) options.font_opts.resolution_x);
1461     gtk_spin_button_set_value(GTK_SPIN_BUTTON(otf_vres),
1462                               (gfloat) options.font_opts.resolution_y);
1463 }
1464 
1465 /*
1466  * Synchronize the vertical resolution with the horizontal resolution.
1467  */
1468 static void
otf_sync_res(GtkWidget * w,GdkEventFocus * ev,gpointer data)1469 otf_sync_res(GtkWidget *w, GdkEventFocus *ev, gpointer data)
1470 {
1471     gfloat v;
1472     GtkSpinButton *b;
1473 
1474     b = GTK_SPIN_BUTTON(data);
1475     v = (gfloat) gtk_spin_button_get_value(b);
1476 
1477     if (v != (gfloat) gtk_spin_button_get_value(GTK_SPIN_BUTTON(w)))
1478       gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), v);
1479 }
1480 
1481 static void
make_otf_import_dialog(void)1482 make_otf_import_dialog(void)
1483 {
1484     GtkWidget *label, *vbox, *hbox, *button, *table, *swin;
1485     GtkAdjustment *adj;
1486     GtkListStore *store;
1487     GtkTreeViewColumn *column;
1488     GtkCellRenderer *cell_renderer;
1489     GtkTreeSelection *sel;
1490     GList *fchain;
1491 
1492     otf_dialog = gtk_dialog_new();
1493     gtk_window_set_title(GTK_WINDOW(otf_dialog), "OpenType Selection");
1494 
1495     (void) g_signal_connect(G_OBJECT(otf_dialog), "delete_event",
1496                             G_CALLBACK(gtk_widget_hide), 0);
1497 
1498     vbox = GTK_DIALOG(otf_dialog)->vbox;
1499 
1500     swin = gtk_scrolled_window_new(0, 0);
1501     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
1502                                    GTK_POLICY_AUTOMATIC,
1503                                    GTK_POLICY_ALWAYS);
1504 
1505     store = gtk_list_store_new(1, G_TYPE_STRING);
1506     otf_faces = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1507     g_object_unref(store);
1508 
1509     cell_renderer = gtk_cell_renderer_text_new();
1510     column = gtk_tree_view_column_new_with_attributes ("Faces",
1511                                                        cell_renderer,
1512                                                        "text", 0,
1513                                                        NULL);
1514 
1515     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1516     gtk_tree_view_append_column (GTK_TREE_VIEW(otf_faces), column);
1517 
1518     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(otf_faces));
1519     gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
1520 
1521     (void) g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(choose_otf),
1522                             NULL);
1523 
1524     /*
1525      * Set the size of the list explicitly to make enough space for
1526      * approximately five entries.
1527      */
1528     gtk_widget_set_size_request(otf_faces, -1, 100);
1529 
1530     gtk_container_add(GTK_CONTAINER(swin), otf_faces);
1531 
1532     gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
1533 
1534     /*
1535      * Create a table to hold the other two lists.
1536      */
1537     table = gtk_table_new(1, 2, TRUE);
1538 
1539     swin = gtk_scrolled_window_new(0, 0);
1540     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
1541                                    GTK_POLICY_AUTOMATIC,
1542                                    GTK_POLICY_ALWAYS);
1543 
1544     store = gtk_list_store_new(1, G_TYPE_STRING);
1545     otf_platforms = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1546     g_object_unref(store);
1547 
1548     cell_renderer = gtk_cell_renderer_text_new();
1549     column = gtk_tree_view_column_new_with_attributes("Platforms",
1550                                                       cell_renderer,
1551                                                       "text", 0,
1552                                                       NULL);
1553 
1554     gtk_widget_set_size_request(otf_platforms, 200, 70);
1555 
1556     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1557     gtk_tree_view_append_column(GTK_TREE_VIEW(otf_platforms), column);
1558 
1559     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(otf_platforms));
1560     gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
1561 
1562     (void) g_signal_connect(G_OBJECT(sel), "changed",
1563                             G_CALLBACK(choose_otf_platform), NULL);
1564 
1565     gtk_container_add(GTK_CONTAINER(swin), otf_platforms);
1566 
1567     /*
1568      * Attach the platform list to the table.
1569      */
1570     gtk_table_attach(GTK_TABLE(table), swin, 0, 1, 0, 1,
1571                      GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1572 
1573     swin = gtk_scrolled_window_new(0, 0);
1574     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
1575                                    GTK_POLICY_AUTOMATIC,
1576                                    GTK_POLICY_ALWAYS);
1577 
1578     store = gtk_list_store_new(1, G_TYPE_STRING);
1579     otf_encodings = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
1580     g_object_unref(store);
1581 
1582     cell_renderer = gtk_cell_renderer_text_new();
1583     column = gtk_tree_view_column_new_with_attributes("Encodings",
1584                                                       cell_renderer,
1585                                                       "text", 0,
1586                                                       NULL);
1587 
1588     gtk_widget_set_size_request(otf_encodings, 200, 70);
1589 
1590     gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
1591     gtk_tree_view_append_column(GTK_TREE_VIEW(otf_encodings), column);
1592 
1593     sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(otf_encodings));
1594     gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
1595 
1596     (void) g_signal_connect(G_OBJECT(sel), "changed",
1597                             G_CALLBACK(choose_otf_encoding), NULL);
1598 
1599     gtk_container_add(GTK_CONTAINER(swin), otf_encodings);
1600 
1601     /*
1602      * Attach the encodings list to the table.
1603      */
1604     gtk_table_attach(GTK_TABLE(table), swin, 1, 2, 0, 1,
1605                      GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 0, 0);
1606 
1607     gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0);
1608 
1609     /*
1610      * Make a table that will contain the point size and resolution
1611      * spin buttons.
1612      */
1613     table = gtk_table_new(3, 3, FALSE);
1614 
1615     /*
1616      * Make the spin button labels.
1617      */
1618     label = gtk_label_new("Point Size:");
1619     gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1620     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1, GTK_FILL, GTK_FILL,
1621                      5, 5);
1622     label = gtk_label_new("Horizontal Resolution:");
1623     gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1624     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2, GTK_FILL, GTK_FILL,
1625                      5, 5);
1626     label = gtk_label_new("Vertical Resolution:");
1627     gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1628     gtk_table_attach(GTK_TABLE(table), label, 0, 1, 2, 3, GTK_FILL, GTK_FILL,
1629                      5, 5);
1630 
1631     /*
1632      * Make the spin buttons.
1633      */
1634     adj = (GtkAdjustment *) gtk_adjustment_new(0.0, 4.0, 256.0, 1.0, 2.0, 0.0);
1635     otf_point_size = gtk_spin_button_new(adj, 1.0, 0);
1636     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(otf_point_size), TRUE);
1637     gtk_widget_set_size_request(otf_point_size, 100, -1);
1638     gtk_spin_button_set_value(GTK_SPIN_BUTTON(otf_point_size),
1639                               (gfloat) options.font_opts.point_size);
1640     gtk_table_attach(GTK_TABLE(table), otf_point_size, 1, 2, 0, 1,
1641                      GTK_FILL, GTK_FILL, 5, 5);
1642 
1643     adj = (GtkAdjustment *) gtk_adjustment_new(0.0, 72.0, 1200.0,
1644                                                1.0, 10.0, 0.0);
1645     otf_hres = gtk_spin_button_new(adj, 1.0, 0);
1646     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(otf_hres), TRUE);
1647     gtk_widget_set_size_request(otf_hres, 100, -1);
1648     gtk_spin_button_set_value(GTK_SPIN_BUTTON(otf_hres),
1649                               (gfloat) options.font_opts.resolution_x);
1650     gtk_table_attach(GTK_TABLE(table), otf_hres, 1, 2, 1, 2,
1651                      GTK_FILL, GTK_FILL, 5, 5);
1652 
1653     adj = (GtkAdjustment *) gtk_adjustment_new(0.0, 72.0, 1200.0,
1654                                                1.0, 10.0, 0.0);
1655     otf_vres = gtk_spin_button_new(adj, 1.0, 0);
1656     gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(otf_vres), TRUE);
1657     gtk_widget_set_size_request(otf_vres, 100, -1);
1658     gtk_spin_button_set_value(GTK_SPIN_BUTTON(otf_vres),
1659                               (gfloat) options.font_opts.resolution_y);
1660     (void) g_signal_connect(G_OBJECT(otf_vres), "focus-in-event",
1661                             G_CALLBACK(otf_sync_res),
1662                             (gpointer) otf_hres);
1663     (void) g_signal_connect(G_OBJECT(otf_hres), "focus-in-event",
1664                             G_CALLBACK(otf_sync_res),
1665                             (gpointer) otf_vres);
1666     gtk_table_attach(GTK_TABLE(table), otf_vres, 1, 2, 2, 3,
1667                      GTK_FILL, GTK_FILL, 5, 5);
1668 
1669     /*
1670      * Make the reset button.
1671      */
1672     label = gtk_button_new_with_label("Reset");
1673     (void) g_signal_connect(G_OBJECT(label), "clicked",
1674                             G_CALLBACK(otf_reset_metrics), 0);
1675     gtk_table_attach(GTK_TABLE(table), label, 2, 3, 1, 2, GTK_FILL, GTK_FILL,
1676                      10, 0);
1677 
1678     /*
1679      * Do some fiddling to adjust the focus chain so the Reset button is at
1680      * the end instead of in the middle.
1681      */
1682     fchain = g_list_append(NULL, (gpointer) otf_point_size);
1683     fchain = g_list_append(fchain, (gpointer) otf_hres);
1684     fchain = g_list_append(fchain, (gpointer) otf_vres);
1685     fchain = g_list_append(fchain, (gpointer) label);
1686     gtk_container_set_focus_chain(GTK_CONTAINER(table), fchain);
1687     g_list_free(fchain);
1688 
1689     gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, FALSE, 10);
1690 
1691     /*
1692      * Add the buttons at the bottom of the dialog.
1693      */
1694     hbox = GTK_DIALOG(otf_dialog)->action_area;
1695 
1696     button = gtk_button_new_from_stock(GTK_STOCK_CANCEL);
1697     gtk_container_add(GTK_CONTAINER(hbox), button);
1698     (void) g_signal_connect(G_OBJECT(button), "clicked",
1699                             G_CALLBACK(otf_dialog_done),
1700                             GINT_TO_POINTER(-1));
1701     button = gtk_button_new_from_stock(GTK_STOCK_OK);
1702     gtk_container_add(GTK_CONTAINER(hbox), button);
1703     (void) g_signal_connect(G_OBJECT(button), "clicked",
1704                             G_CALLBACK(otf_dialog_done),
1705                             GINT_TO_POINTER(1));
1706 
1707     gtk_widget_show_all(vbox);
1708     gtk_widget_show_all(hbox);
1709 }
1710 
1711 static void
load_otf_font(gbdfed_editor_t * ed,gchar * fullpath,gchar * dot,gchar * dir,gchar * file)1712 load_otf_font(gbdfed_editor_t *ed, gchar *fullpath, gchar *dot,
1713               gchar *dir, gchar *file)
1714 {
1715     gint i, res;
1716     gint32 psize, hres, vres;
1717     gchar *np;
1718     bdf_font_t *font;
1719     bdf_property_t prop;
1720     GtkListStore *store;
1721     GtkTreeIter iter;
1722 
1723     active_editor = ed;
1724     otf_fullpath = fullpath;
1725 
1726     /*
1727      * Determine if this is an OT collection or just a normal font.
1728      */
1729     np = dot + strlen(dot) - 1;
1730     otf_collection = (*np == 'c' || *np == 'C') ? TRUE : FALSE;
1731 
1732     /*
1733      * Initialize the FreeType engine once.
1734      */
1735     if (!ftinit) {
1736         if (FT_Init_FreeType(&library) != 0) {
1737             strcpy(buffer1,
1738                    "Import Font: Unable to initialize the FreeType engine.");
1739             guiutil_error_message(ed->shell, buffer1);
1740             return;
1741         }
1742         ftinit = TRUE;
1743     }
1744 
1745     /*
1746      * Attempt to open the font or collection.
1747      */
1748     if (FT_New_Face(library, fullpath, 0, &face)) {
1749         if (!otf_collection)
1750           sprintf(buffer1, "Import Font: Unable to open OpenType font '%s'.",
1751                   file);
1752         else
1753           sprintf(buffer1,
1754                   "Import Font: Unable to open OpenType collection '%s'.",
1755                   file);
1756         guiutil_error_message(ed->shell, buffer1);
1757         return;
1758     }
1759 
1760     /*
1761      * Construct the dialog that will display various choices that will be
1762      * needed when loading the font.
1763      */
1764     if (otf_dialog == 0)
1765       make_otf_import_dialog();
1766 
1767     /*
1768      * Clear the lists and reset the values.
1769      */
1770     store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(otf_faces)));
1771     gtk_list_store_clear(store);
1772 
1773     otf_face_open = TRUE;
1774     otf_collection = face->num_faces;
1775     np = buffer1;
1776 
1777     if (otf_collection == 1) {
1778         if (bdfotf_get_english_string(face, BDFOTF_FULLNAME_STRING,
1779                                       0, buffer1) == 0)
1780           (void) strcpy(buffer1, "Unknown");
1781         gtk_list_store_append(store, &iter);
1782         gtk_list_store_set(store, &iter, 0, buffer1, -1);
1783     } else {
1784         otf_face_open = FALSE;
1785         FT_Done_Face(face);
1786         for (i = 0; i < otf_collection; i++) {
1787             if (!FT_New_Face(library, fullpath, i, &face)) {
1788                 if (bdfotf_get_english_string(face, BDFOTF_FULLNAME_STRING,
1789                                               0, buffer1) == 0)
1790                   sprintf(buffer1, "Unknown%d", i);
1791 
1792                 gtk_list_store_append(store, &iter);
1793                 gtk_list_store_set(store, &iter, 0, buffer1, -1);
1794 
1795                 FT_Done_Face(face);
1796             }
1797         }
1798     }
1799 
1800     guiutil_show_dialog_centered(otf_dialog, ed->shell);
1801 
1802     /*
1803      * Force the user to interact with this dialog before doing anything else.
1804      */
1805     gtk_window_set_modal(GTK_WINDOW(otf_dialog), TRUE);
1806 
1807     otf_select_done = 0;
1808     while (otf_select_done == 0)
1809       gtk_main_iteration();
1810 
1811     /*
1812      * Reinitialize various globals when we are done.
1813      */
1814     active_editor = 0;
1815     otf_fullpath = 0;
1816 
1817     if (otf_select_done < 0) {
1818         if (otf_face_open)
1819           FT_Done_Face(face);
1820         otf_face_open = FALSE;
1821         return;
1822     }
1823 
1824     /*
1825      * Get the requested point size and resolutions.
1826      */
1827     psize = (gint32)
1828         gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(otf_point_size));
1829     hres = (gint32)
1830         gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(otf_hres));
1831     vres = (gint32)
1832         gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(otf_vres));
1833 
1834     guiutil_busy_cursor(ed->shell, TRUE);
1835     guiutil_busy_cursor(ed->open_dialog, TRUE);
1836 
1837     /*
1838      * Actually store the resolution and point size to the options so they
1839      * will be used for other imports.  The setup dialog will unfortunately
1840      * assume this are the default values.  May fix later so setup knows the
1841      * values changed.
1842      */
1843     options.font_opts.point_size = psize;
1844     options.font_opts.resolution_x = hres;
1845     options.font_opts.resolution_y = vres;
1846 
1847     /*
1848      * Actually load the font.
1849      */
1850     res = bdfotf_load_font(face, platforms[otf_pid_pos],
1851                            encodings[otf_eid_pos], &options.font_opts,
1852                            0, 0, &font);
1853 
1854     guiutil_busy_cursor(ed->shell, FALSE);
1855     guiutil_busy_cursor(ed->open_dialog, FALSE);
1856 
1857     FT_Done_Face(face);
1858     otf_face_open = FALSE;
1859 
1860     if (!res) {
1861         /*
1862          * Make an error message.
1863          */
1864         sprintf(buffer1, "Import Font: Unable to load OpenType font %s.",
1865                 file);
1866         guiutil_error_message(ed->shell, buffer1);
1867         return;
1868     }
1869 
1870     /*
1871      * Hide the open dialog.
1872      */
1873     gtk_widget_hide(ed->open_dialog);
1874 
1875     /*
1876      * Add the _OTF_FONTFILE property using the original filename.
1877      */
1878     prop.name = "_OTF_FONTFILE";
1879     prop.format = BDF_ATOM;
1880     prop.value.atom = file;
1881     bdf_add_font_property(font, &prop);
1882 
1883     /*
1884      * Now set up a file name.
1885      */
1886     sprintf(buffer1, "%.*s.bdf", dot - file, file);
1887 
1888     /*
1889      * Delete the file and path names so they can be updated.
1890      */
1891     if (ed->file != 0)
1892       g_free(ed->file);
1893     if (ed->path != 0)
1894       g_free(ed->path);
1895 
1896     ed->file = strdup(buffer1);
1897     ed->path = strdup(dir);
1898 
1899     /*
1900      * Update the window title.
1901      */
1902     sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ed->file);
1903     gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
1904 
1905     /*
1906      * Tell the glyphtest widget to remove references to
1907      * the current font if it has any, and redraw.
1908      */
1909     if (glyphtest != 0)
1910       glyphtest_remove_font(GLYPHTEST(glyphtest),
1911                             fontgrid_get_font(FONTGRID(ed->fgrid)));
1912 
1913     fontgrid_set_font(FONTGRID(ed->fgrid), font, -1);
1914 
1915     /*
1916      * Indicate the font was imported.
1917      */
1918     ed->imported = TRUE;
1919 
1920     /*
1921      * Finally, update the font name field.
1922      */
1923     gtk_entry_set_text(GTK_ENTRY(ed->fontname),
1924                        fontgrid_get_font_name(FONTGRID(ed->fgrid)));
1925 }
1926 
1927 #endif /* HAVE_FREETYPE */
1928 
1929 #ifdef HAVE_HBF
1930 
1931 /**************************************************************************
1932  *
1933  * HBF section.
1934  *
1935  **************************************************************************/
1936 
1937 static void
load_hbf_font(gbdfed_editor_t * ed,gchar * fullpath,gchar * dot,gchar * dir,gchar * file)1938 load_hbf_font(gbdfed_editor_t *ed, gchar *fullpath, gchar *dot,
1939               gchar *dir, gchar *file)
1940 {
1941     bdf_font_t *font;
1942 
1943     guiutil_busy_cursor(ed->shell, TRUE);
1944     guiutil_busy_cursor(ed->open_dialog, TRUE);
1945 
1946     font = bdf_load_hbf_font(fullpath, &options.font_opts, 0, 0);
1947 
1948     guiutil_busy_cursor(ed->shell, FALSE);
1949     guiutil_busy_cursor(ed->open_dialog, FALSE);
1950 
1951     /*
1952      * Check to see if the file can be opened.
1953      */
1954     if (font == 0) {
1955         g_free(dir);
1956         sprintf(buffer1, "Import Font: Unable to import %s.", file);
1957         guiutil_error_message(ed->shell, buffer1);
1958         return;
1959     }
1960 
1961     gtk_widget_hide(ed->open_dialog);
1962 
1963     /*
1964      * Now set up a file name.
1965      */
1966     sprintf(buffer1, "%.*s.bdf", (int) (dot - file), file);
1967 
1968     /*
1969      * Delete the file and path names so they can be updated.
1970      */
1971     if (ed->file != 0)
1972       g_free(ed->file);
1973     if (ed->path != 0)
1974       g_free(ed->path);
1975 
1976     ed->file = strdup(buffer1);
1977     ed->path = dir;
1978 
1979     /*
1980      * Update the window title.
1981      */
1982     sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ed->file);
1983     gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
1984 
1985     /*
1986      * Tell the glyphtest widget to remove references to
1987      * the current font if it has any, and redraw.
1988      */
1989     if (glyphtest != 0)
1990       glyphtest_remove_font(GLYPHTEST(glyphtest),
1991                             fontgrid_get_font(FONTGRID(ed->fgrid)));
1992 
1993     fontgrid_set_font(FONTGRID(ed->fgrid), font, -1);
1994 
1995     /*
1996      * Indicate the font was imported.
1997      */
1998     ed->imported = TRUE;
1999 
2000     /*
2001      * Finally, update the font name field.
2002      */
2003     gtk_entry_set_text(GTK_ENTRY(ed->fontname),
2004                        fontgrid_get_font_name(FONTGRID(ed->fgrid)));
2005 }
2006 
2007 #endif
2008 
2009 /*
2010  * This routine actually does the work of opening the font.
2011  */
2012 static void
really_open_font(guint ed_id)2013 really_open_font(guint ed_id)
2014 {
2015     gbdfed_editor_t *ed = editors + ed_id;
2016     gchar *filename, *path, *file, *dot;
2017     GtkFileChooser *fs;
2018 #if (GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 10)
2019     GtkRecentManager *recent;
2020 #endif
2021 
2022     fs = GTK_FILE_CHOOSER(ed->open_dialog);
2023     filename = gtk_file_chooser_get_filename(fs);
2024 
2025     /*
2026      * Split the filename into path and file, locate the extension position in
2027      * the file name, and make a version of the name with no '-' characters
2028      * which are field separators in XLFD font names.
2029      */
2030     file = g_path_get_basename(filename);
2031     path = g_path_get_dirname(filename);
2032     if ((dot = strrchr(file, '.')) == 0)
2033       dot = file + strlen(file);
2034 
2035     /*
2036      * If the last character of the filename is a slash, no file name was
2037      * provided.
2038      */
2039     if (filename[strlen(filename) - 1] == G_DIR_SEPARATOR) {
2040         guiutil_error_message(ed->shell,
2041                               "Import Font: No file name provided.");
2042         if (path)
2043           g_free(path);
2044         if (file)
2045           g_free(file);
2046         g_free(filename);
2047         return;
2048     }
2049 
2050 #if (GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 10)
2051     recent = gtk_recent_manager_get_default();
2052     sprintf(buffer1, "file://%s", filename);
2053     if (gtk_recent_manager_has_item(recent,
2054                                     (const gchar *) buffer1) == FALSE)
2055       gtk_recent_manager_add_item(recent,
2056                                   (const gchar *) buffer1);
2057 #endif
2058 
2059     switch (ed->import_format) {
2060       case BDF_FORMAT:
2061         load_bdf_font(ed, (const gchar *) filename, (const gchar *) path,
2062                       (const gchar *) file);
2063         break;
2064       case CONSOLE_FORMAT:
2065         load_console_font(ed, filename, dot, path, file);
2066         break;
2067       case PKGF_FORMAT:
2068         load_pkgf_font(ed, filename, dot, path, file);
2069         break;
2070       case FNT_FORMAT:
2071         load_windows_font(ed, filename, dot, path, file);
2072         break;
2073 #ifdef HAVE_HBF
2074       case HBF_FORMAT:
2075         load_hbf_font(ed, filename, dot, path, file);
2076         break;
2077 #endif
2078 #ifdef HAVE_FREETYPE
2079       case OTF_FORMAT:
2080         load_otf_font(ed, filename, dot, path, file);
2081         break;
2082 #endif /* HAVE_FREETYPE */
2083     }
2084 
2085     if (path)
2086       g_free(path);
2087     if (file)
2088       g_free(file);
2089 
2090     g_free(filename);
2091 
2092     /*
2093      * In case the editor list changed, set the pointer to the editor again.
2094      */
2095     ed = editors + ed_id;
2096 
2097     /*
2098      * Force the editor's info to be updated for the new font.  This causes
2099      * it to change if it is already visible.
2100      */
2101     guiedit_update_font_info(ed);
2102 }
2103 
2104 static gchar *
make_file_dialog_title(guint type,gboolean save)2105 make_file_dialog_title(guint type, gboolean save)
2106 {
2107     gchar *title = 0;
2108 
2109     switch (type) {
2110       case BDF_FORMAT: title = "BDF"; break;
2111       case CONSOLE_FORMAT: title = "Console"; break;
2112       case PKGF_FORMAT: title = "PK/GF"; break;
2113       case FNT_FORMAT: title = "Windows"; break;
2114 #ifdef HAVE_HBF
2115       case HBF_FORMAT: title = "HBF"; break;
2116 #endif
2117       case OTF_FORMAT: title = "TrueType"; break;
2118       case PSF_FORMAT: title = "PSF"; break;
2119       case HEX_FORMAT: title = "HEX"; break;
2120     }
2121 
2122     if (save) {
2123         if (type == BDF_FORMAT)
2124           sprintf(buffer1, "Save %s Font", title);
2125         else
2126           sprintf(buffer1, "Export %s Font", title);
2127     } else
2128       sprintf(buffer1, "Open %s Font", title);
2129 
2130     return buffer1;
2131 }
2132 
2133 static void
handle_open_response(GtkDialog * d,gint response,gpointer data)2134 handle_open_response(GtkDialog *d, gint response, gpointer data)
2135 {
2136     switch (response) {
2137       case GTK_RESPONSE_ACCEPT:
2138         really_open_font(GPOINTER_TO_UINT(data));
2139         break;
2140       case GTK_RESPONSE_CANCEL:
2141         gtk_widget_hide(GTK_WIDGET(d));
2142         break;
2143     }
2144 }
2145 
2146 static void
update_open_dialog(gbdfed_editor_t * ed,guint type)2147 update_open_dialog(gbdfed_editor_t *ed, guint type)
2148 {
2149     GtkFileChooser *fs;
2150 
2151     if (ed->open_dialog == 0) {
2152         /*
2153          * Create the file chooser filters if they haven't already been
2154          * created.
2155          */
2156         make_file_chooser_filters();
2157 
2158         ed->open_dialog =
2159             gtk_file_chooser_dialog_new(make_file_dialog_title(type, FALSE),
2160                                         GTK_WINDOW(ed->shell),
2161                                         GTK_FILE_CHOOSER_ACTION_OPEN,
2162                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2163                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
2164                                         NULL);
2165 
2166         (void) g_signal_connect(G_OBJECT(ed->open_dialog), "response",
2167                                 G_CALLBACK(handle_open_response),
2168                                 GUINT_TO_POINTER(ed->id));
2169         (void) g_signal_connect(G_OBJECT(ed->open_dialog), "delete_event",
2170                                 G_CALLBACK(gtk_widget_hide), 0);
2171     } else if (ed->import_format != type)
2172       gtk_window_set_title(GTK_WINDOW(ed->open_dialog),
2173                            make_file_dialog_title(type, FALSE));
2174     fs = GTK_FILE_CHOOSER(ed->open_dialog);
2175 
2176     /*
2177      * Set the file filter.
2178      */
2179     gtk_file_chooser_set_filter(fs, filename_filters[type]);
2180 
2181     ed->import_format = type;
2182 
2183     /*
2184      * Set the initial path as a file if it exists.  This is necessary to
2185      * force the open to occur in the directory where this font was last
2186      * saved, which might be different than the directory that is currently in
2187      * the open file selection dialog.
2188      */
2189     if (ed->path != 0 && ed->path[0] == G_DIR_SEPARATOR)
2190       gtk_file_chooser_set_current_folder(fs, ed->path);
2191 }
2192 
2193 static void
hide_save_dialog(GtkWidget * w,gpointer data)2194 hide_save_dialog(GtkWidget *w, gpointer data)
2195 {
2196     gtk_widget_hide(w);
2197     save_dialog_done = TRUE;
2198 }
2199 
2200 static void
set_psf_option(GtkWidget * w,gpointer data)2201 set_psf_option(GtkWidget *w, gpointer data)
2202 {
2203     guint flags = 0;
2204     gint dotpos;
2205     gchar *fname, *dot, *slash, *suff = 0;
2206     GtkFileChooser *fs;
2207 
2208     switch (gtk_combo_box_get_active(GTK_COMBO_BOX(w))) {
2209       case 0:
2210         flags = BDF_PSF_UNIMAP|BDF_PSF_FONT;
2211         break;
2212       case 1:
2213         flags = BDF_PSF_FONT;
2214         break;
2215       case 2:
2216         flags = BDF_PSF_UNIMAP;
2217         break;
2218     }
2219 
2220     if (flags == BDF_PSF_UNIMAP)
2221       /*
2222        * Have to change to the .uni suffix.
2223        */
2224       suff = ".uni";
2225     else if (options.font_opts.psf_flags == BDF_PSF_UNIMAP)
2226       /*
2227        * Have to change back to the .psfu suffix.
2228        */
2229       suff = ".psfu";
2230 
2231     options.font_opts.psf_flags = flags;
2232 
2233     if (suff) {
2234         /*
2235          * Change the suffix on the filename in the entry area.
2236          */
2237         fs = GTK_FILE_CHOOSER(g_object_get_data(G_OBJECT(w),
2238                                                   "file-selection-dialog"));
2239         fname = gtk_file_chooser_get_filename(fs);
2240 
2241         slash = fname;
2242         if ((dot = (gchar *) strrchr(fname, '.')) != 0) {
2243             if ((slash = (gchar *) strrchr(fname, G_DIR_SEPARATOR)) == 0)
2244               slash = fname;
2245             dotpos = (gint) (dot - slash) - 1;
2246 
2247             /*
2248              * Copy the new extension in.
2249              */
2250             (void) strcpy(dot, suff);
2251         } else
2252           dotpos = -1;
2253 
2254         if (*slash == G_DIR_SEPARATOR)
2255           *slash++ = 0;
2256 
2257         gtk_file_chooser_set_current_name(fs, slash);
2258         g_free(fname);
2259     }
2260 }
2261 
2262 static void
handle_save_response(GtkDialog * d,gint response,gpointer data)2263 handle_save_response(GtkDialog *d, gint response, gpointer data)
2264 {
2265     switch (response) {
2266       case GTK_RESPONSE_ACCEPT:
2267         really_save_font(GPOINTER_TO_UINT(data));
2268         break;
2269       case GTK_RESPONSE_CANCEL:
2270         gtk_widget_hide(GTK_WIDGET(d));
2271         break;
2272     }
2273 }
2274 
2275 static void
update_save_dialog(gbdfed_editor_t * ed,guint type)2276 update_save_dialog(gbdfed_editor_t *ed, guint type)
2277 {
2278     GtkWidget *vbox;
2279     gchar *dot, *slash;
2280     gint dotpos;
2281 
2282     if (ed->save_dialog == 0) {
2283         /*
2284          * Create the file chooser filters if they haven't already been
2285          * created.
2286          */
2287         make_file_chooser_filters();
2288 
2289         ed->save_dialog =
2290             gtk_file_chooser_dialog_new(make_file_dialog_title(type, TRUE),
2291                                         GTK_WINDOW(ed->shell),
2292                                         GTK_FILE_CHOOSER_ACTION_SAVE,
2293                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2294                                         GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
2295                                         NULL);
2296 
2297         vbox = GTK_DIALOG(ed->save_dialog)->vbox;
2298 
2299         psf_export_options = gtk_combo_box_new_text();
2300         /*
2301          * Since the flags have to be set in the save dialog, attach the
2302          * save dialog to the object so we can set the bits appropriately.
2303          */
2304         g_object_set_data(G_OBJECT(psf_export_options),
2305                           "file-selection-dialog",
2306                           (gpointer) ed->save_dialog);
2307         (void) g_signal_connect(G_OBJECT(psf_export_options), "changed",
2308                                 G_CALLBACK(set_psf_option), 0);
2309         gtk_combo_box_append_text(GTK_COMBO_BOX(psf_export_options),
2310                                   "Font and Unicode Map");
2311         gtk_combo_box_append_text(GTK_COMBO_BOX(psf_export_options),
2312                                   "Font Only");
2313         gtk_combo_box_append_text(GTK_COMBO_BOX(psf_export_options),
2314                                   "Unicode Map Only");
2315         gtk_combo_box_set_active(GTK_COMBO_BOX(psf_export_options), 0);
2316 
2317         psf_export_frame = labcon_new_label_defaults("PSF Export Options:",
2318                                                      psf_export_options, 0);
2319 
2320         (void) g_signal_connect(G_OBJECT(ed->save_dialog), "delete_event",
2321                                 G_CALLBACK(hide_save_dialog), 0);
2322 
2323         (void) g_signal_connect(G_OBJECT(ed->save_dialog), "response",
2324                                 G_CALLBACK(handle_save_response),
2325                                 GUINT_TO_POINTER(ed->id));
2326 
2327         gtk_widget_show_all(psf_export_frame);
2328         gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(ed->save_dialog),
2329                                           psf_export_frame);
2330     } else if (ed->export_format != type)
2331       gtk_window_set_title(GTK_WINDOW(ed->save_dialog),
2332                            make_file_dialog_title(type, TRUE));
2333 
2334     /*
2335      * Set the file filter.
2336      */
2337     gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(ed->save_dialog),
2338                                 filename_filters[type]);
2339 
2340 
2341     ed->export_format = type;
2342 
2343     /*
2344      * Show or hide the PSF exporting options.
2345      */
2346     if (type == PSF_FORMAT)
2347       gtk_widget_show(psf_export_frame);
2348     else
2349       gtk_widget_hide(psf_export_frame);
2350 
2351     /*
2352      * Use the current path and filename as the default.  This is done in case
2353      * the font was loaded from some directory other than the current default
2354      * in the file selection dialog for saving.
2355      */
2356     if (ed->file != 0)
2357       sprintf(buffer1, "%s", ed->file);
2358     else
2359       sprintf(buffer1, "unnamed%d.bdf", ed->id);
2360 
2361     if ((dot = (gchar *) strrchr(buffer1, '.'))) {
2362         if ((slash = (gchar *) strrchr(buffer1, G_DIR_SEPARATOR)) == 0)
2363           slash = buffer1;
2364         dotpos = (gint) (dot - slash) - 1;
2365 
2366         /*
2367          * If a PSF or HEX font is being exported, change the extension
2368          * here.
2369          */
2370         if (type == PSF_FORMAT)
2371           (void) strcpy(dot, ".psfu");
2372         else if (type == HEX_FORMAT)
2373           (void) strcpy(dot, ".hex");
2374 
2375     } else
2376       dotpos = -1;
2377 
2378     gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(ed->save_dialog),
2379                                       buffer1);
2380     if (ed->path != 0 && ed->path[0] == G_DIR_SEPARATOR)
2381       gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(ed->save_dialog),
2382                                           ed->path);
2383 #if 0
2384     gtk_editable_set_position(GTK_EDITABLE(fs->selection_entry), dotpos);
2385     gtk_editable_select_region(GTK_EDITABLE(fs->selection_entry), 0, dotpos);
2386 #endif
2387 }
2388 
2389 void
guifile_import_bdf_font(GtkWidget * w,gpointer data)2390 guifile_import_bdf_font(GtkWidget *w, gpointer data)
2391 {
2392     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2393 
2394     if (fontgrid_get_font_modified(FONTGRID(ed->fgrid))) {
2395         if (ed->file == 0)
2396           sprintf(buffer1, "Save Font: (unnamed%d) modified.  Save?", ed->id);
2397         else
2398           sprintf(buffer1, "Save Font: %s modified.  Save?", ed->file);
2399         if (guiutil_yes_or_no(ed->shell, buffer1, TRUE)) {
2400             /*
2401              * If the current file was imported, then make sure to use the
2402              * Save As... dialog instead of just saving under the name that
2403              * was constructed when importing.  The user won't know what the
2404              * default BDF file name of imported fonts look like.
2405              */
2406             if (ed->imported)
2407               guifile_save_as_wait(w, data);
2408             else
2409               guifile_save(w, data);
2410             return;
2411         }
2412     }
2413 
2414     update_open_dialog(ed, BDF_FORMAT);
2415 
2416     guiutil_show_dialog_centered(ed->open_dialog, ed->shell);
2417 }
2418 
2419 void
guifile_import_console_font(GtkWidget * w,gpointer data)2420 guifile_import_console_font(GtkWidget *w, gpointer data)
2421 {
2422     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2423 
2424     if (fontgrid_get_font_modified(FONTGRID(ed->fgrid))) {
2425         if (ed->file == 0)
2426           sprintf(buffer1, "Save Font: (unnamed%d) modified.  Save?", ed->id);
2427         else
2428           sprintf(buffer1, "Save Font: %s modified.  Save?", ed->file);
2429         if (guiutil_yes_or_no(ed->shell, buffer1, TRUE)) {
2430             /*
2431              * If the current file was imported, then make sure to use the
2432              * Save As... dialog instead of just saving under the name that
2433              * was constructed when importing.  The user won't know what the
2434              * default BDF file name of imported fonts look like.
2435              */
2436             if (ed->imported)
2437               guifile_save_as_wait(w, data);
2438             else
2439               guifile_save(w, data);
2440             return;
2441         }
2442     }
2443 
2444     update_open_dialog(ed, CONSOLE_FORMAT);
2445 
2446     guiutil_show_dialog_centered(ed->open_dialog, ed->shell);
2447 }
2448 
2449 void
guifile_import_pkgf_font(GtkWidget * w,gpointer data)2450 guifile_import_pkgf_font(GtkWidget *w, gpointer data)
2451 {
2452     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2453 
2454     if (fontgrid_get_font_modified(FONTGRID(ed->fgrid))) {
2455         if (ed->file == 0)
2456           sprintf(buffer1, "Save Font: (unnamed%d) modified.  Save?", ed->id);
2457         else
2458           sprintf(buffer1, "Save Font: %s modified.  Save?", ed->file);
2459         if (guiutil_yes_or_no(ed->shell, buffer1, TRUE)) {
2460             /*
2461              * If the current file was imported, then make sure to use the
2462              * Save As... dialog instead of just saving under the name that
2463              * was constructed when importing.  The user won't know what the
2464              * default BDF file name of imported fonts look like.
2465              */
2466             if (ed->imported)
2467               guifile_save_as_wait(w, data);
2468             else
2469               guifile_save(w, data);
2470             return;
2471         }
2472     }
2473 
2474     update_open_dialog(ed, PKGF_FORMAT);
2475 
2476     guiutil_show_dialog_centered(ed->open_dialog, ed->shell);
2477 }
2478 
2479 void
guifile_import_windows_font(GtkWidget * w,gpointer data)2480 guifile_import_windows_font(GtkWidget *w, gpointer data)
2481 {
2482     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2483 
2484     if (fontgrid_get_font_modified(FONTGRID(ed->fgrid))) {
2485         if (ed->file == 0)
2486           sprintf(buffer1, "Save Font: (unnamed%d) modified.  Save?", ed->id);
2487         else
2488           sprintf(buffer1, "Save Font: %s modified.  Save?", ed->file);
2489         if (guiutil_yes_or_no(ed->shell, buffer1, TRUE)) {
2490             /*
2491              * If the current file was imported, then make sure to use the
2492              * Save As... dialog instead of just saving under the name that
2493              * was constructed when importing.  The user won't know what the
2494              * default BDF file name of imported fonts look like.
2495              */
2496             if (ed->imported)
2497               guifile_save_as_wait(w, data);
2498             else
2499               guifile_save(w, data);
2500             return;
2501         }
2502     }
2503 
2504     update_open_dialog(ed, FNT_FORMAT);
2505 
2506     guiutil_show_dialog_centered(ed->open_dialog, ed->shell);
2507 }
2508 
2509 #ifdef HAVE_HBF
2510 
2511 void
guifile_import_hbf_font(GtkWidget * w,gpointer data)2512 guifile_import_hbf_font(GtkWidget *w, gpointer data)
2513 {
2514     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2515 
2516     if (fontgrid_get_font_modified(FONTGRID(ed->fgrid))) {
2517         if (ed->file == 0)
2518           sprintf(buffer1, "Save Font: (unnamed%d) modified.  Save?", ed->id);
2519         else
2520           sprintf(buffer1, "Save Font: %s modified.  Save?", ed->file);
2521         if (guiutil_yes_or_no(ed->shell, buffer1, TRUE)) {
2522             /*
2523              * If the current file was imported, then make sure to use the
2524              * Save As... dialog instead of just saving under the name that
2525              * was constructed when importing.  The user won't know what the
2526              * default BDF file name of imported fonts look like.
2527              */
2528             if (ed->imported)
2529               guifile_save_as_wait(w, data);
2530             else
2531               guifile_save(w, data);
2532             return;
2533         }
2534     }
2535 
2536     update_open_dialog(ed, HBF_FORMAT);
2537 
2538     guiutil_show_dialog_centered(ed->open_dialog, ed->shell);
2539 }
2540 
2541 #endif
2542 
2543 #ifdef HAVE_FREETYPE
2544 
2545 void
guifile_import_otf_font(GtkWidget * w,gpointer data)2546 guifile_import_otf_font(GtkWidget *w, gpointer data)
2547 {
2548     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2549 
2550     if (fontgrid_get_font_modified(FONTGRID(ed->fgrid))) {
2551         if (ed->file == 0)
2552           sprintf(buffer1, "Save Font: (unnamed%d) modified.  Save?", ed->id);
2553         else
2554           sprintf(buffer1, "Save Font: %s modified.  Save?", ed->file);
2555         if (guiutil_yes_or_no(ed->shell, buffer1, TRUE)) {
2556             /*
2557              * If the current file was imported, then make sure to use the
2558              * Save As... dialog instead of just saving under the name that
2559              * was constructed when importing.  The user won't know what the
2560              * default BDF file name of imported fonts look like.
2561              */
2562             if (ed->imported)
2563               guifile_save_as_wait(w, data);
2564             else
2565               guifile_save(w, data);
2566             return;
2567         }
2568     }
2569 
2570     update_open_dialog(ed, OTF_FORMAT);
2571 
2572     guiutil_show_dialog_centered(ed->open_dialog, ed->shell);
2573 }
2574 
2575 #endif /* HAVE_FREETYPE */
2576 
2577 /**************************************************************************
2578  *
2579  * X server section.
2580  *
2581  **************************************************************************/
2582 
2583 #ifdef HAVE_XLIB
2584 /*
2585  * Only compile this in if it is being built for machine running X.
2586  */
2587 
2588 static void
xsrv_filter(GtkWidget * w,gpointer data)2589 xsrv_filter(GtkWidget *w, gpointer data)
2590 {
2591     gchar *pattern, **fonts;
2592     gint i, nfonts;
2593     GtkListStore *store;
2594     GtkTreeViewColumn *col;
2595     GtkTreeIter iter;
2596 
2597     pattern = (gchar *) gtk_entry_get_text(GTK_ENTRY(xsrv_filter_text));
2598 
2599     fonts = XListFonts(GDK_DISPLAY(), pattern, _XSRV_MAX_FONTS, &nfonts);
2600 
2601     store =
2602         GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(xsrv_font_list)));
2603     col = gtk_tree_view_get_column(GTK_TREE_VIEW(xsrv_font_list), 0);
2604 
2605     /*
2606      * Update the label on the font list with the number of fonts.
2607      */
2608     sprintf(buffer1, "Font List: %d", nfonts);
2609     gtk_tree_view_column_set_title(col, buffer1);
2610 
2611     gtk_list_store_clear(store);
2612     for (i = 0; i < nfonts; i++) {
2613         gtk_list_store_append(store, &iter);
2614         gtk_list_store_set(store, &iter, 0, fonts[i], -1);
2615     }
2616 
2617     XFreeFontNames(fonts);
2618 }
2619 
2620 static void
xsrv_xlfd_filter(GtkWidget * w,gpointer data)2621 xsrv_xlfd_filter(GtkWidget *w, gpointer data)
2622 {
2623     gtk_entry_set_text(GTK_ENTRY(xsrv_filter_text), _XSRV_DEFAULT_FILTER);
2624     gtk_widget_activate(xsrv_filter_text);
2625 }
2626 
2627 static void
xsrv_select_font(GtkTreeSelection * sel,gpointer data)2628 xsrv_select_font(GtkTreeSelection *sel, gpointer data)
2629 {
2630     gchar *name;
2631     GtkTreeModel *model;
2632     GtkTreeIter iter;
2633 
2634     if (gtk_tree_selection_get_selected(sel, &model, &iter)) {
2635         gtk_tree_model_get (model, &iter, 0, &name, -1);
2636         gtk_entry_set_text(GTK_ENTRY(xsrv_selection_text), name);
2637         g_free(name);
2638     }
2639 }
2640 
2641 static void
xsrv_clear_selection_text(GtkWidget * w,gpointer data)2642 xsrv_clear_selection_text(GtkWidget *w, gpointer data)
2643 {
2644     gtk_entry_set_text(GTK_ENTRY(xsrv_selection_text), "");
2645 }
2646 
2647 static void
xsrv_import_font(GtkWidget * w,gpointer data)2648 xsrv_import_font(GtkWidget *w, gpointer data)
2649 {
2650     gbdfed_editor_t *ed = editors + xsrv_active_editor;
2651     XFontStruct *xfont;
2652     bdf_font_t *font;
2653     gchar *name;
2654 
2655     name = (gchar *) gtk_entry_get_text(GTK_ENTRY(xsrv_selection_text));
2656     if (strcmp(name, "") == 0) {
2657         guiutil_error_message(ed->shell,
2658                               "Import Font: No font name provided.");
2659         return;
2660     }
2661 
2662     guiutil_busy_cursor(ed->shell, TRUE);
2663     guiutil_busy_cursor(xsrv_dialog, TRUE);
2664     if ((xfont = XLoadQueryFont(GDK_DISPLAY(), name)) == 0) {
2665         guiutil_busy_cursor(ed->shell, FALSE);
2666         guiutil_busy_cursor(xsrv_dialog, FALSE);
2667         sprintf(buffer1, "Import Font: Unable to load server font %s.",
2668                 name);
2669         guiutil_error_message(ed->shell, buffer1);
2670         return;
2671     }
2672 
2673     font = bdf_load_server_font(GDK_DISPLAY(), xfont, name,
2674                                 &options.font_opts, 0, 0);
2675     guiutil_busy_cursor(ed->shell, FALSE);
2676     guiutil_busy_cursor(xsrv_dialog, FALSE);
2677     XFreeFont(GDK_DISPLAY(), xfont);
2678 
2679     if (font == 0) {
2680         sprintf(buffer1, "Import Font: Unable to import server font %s.",
2681                 name);
2682         guiutil_error_message(ed->shell, buffer1);
2683         return;
2684     }
2685 
2686     /*
2687      * Close the dialog.
2688      */
2689     gtk_widget_hide(xsrv_dialog);
2690 
2691     if (ed->file != 0)
2692       g_free(ed->file);
2693     if (ed->path != 0)
2694       g_free(ed->path);
2695     ed->file = ed->path = 0;
2696 
2697     sprintf(buffer1, "%s - unnamed%d [modified]", g_get_prgname(),
2698             ed->id);
2699     gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
2700 
2701     /*
2702      * Tell the glyphtest widget to remove references to
2703      * the current font if it has any, and redraw.
2704      */
2705     if (glyphtest != 0)
2706       glyphtest_remove_font(GLYPHTEST(glyphtest),
2707                             fontgrid_get_font(FONTGRID(ed->fgrid)));
2708 
2709     fontgrid_set_font(FONTGRID(ed->fgrid), font, -1);
2710 
2711     /*
2712      * Indicate the font was imported.
2713      */
2714     ed->imported = TRUE;
2715 
2716     /*
2717      * Finally, update the font name field.
2718      */
2719     gtk_entry_set_text(GTK_ENTRY(ed->fontname),
2720                        fontgrid_get_font_name(FONTGRID(ed->fgrid)));
2721 }
2722 
2723 static void
xsrv_activate_font(GtkTreeView * view,GtkTreePath * path,GtkTreeViewColumn * col,gpointer data)2724 xsrv_activate_font(GtkTreeView *view, GtkTreePath *path,
2725                    GtkTreeViewColumn *col, gpointer data)
2726 {
2727     xsrv_import_font(GTK_WIDGET(view), data);
2728 }
2729 
2730 void
guifile_import_xserver_font(GtkWidget * w,gpointer data)2731 guifile_import_xserver_font(GtkWidget *w, gpointer data)
2732 {
2733     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2734     GtkWidget *label, *hbox, *vbox, *text, *swin, *button;
2735     gchar *name, **fonts;
2736     gint i, nfonts;
2737     GtkListStore *store;
2738     GtkTreeViewColumn *column;
2739     GtkCellRenderer *cell_renderer;
2740     GtkTreeSelection *sel;
2741     GtkTreeIter iter;
2742 
2743     if (fontgrid_get_font_modified(FONTGRID(ed->fgrid))) {
2744         if (ed->file == 0)
2745           sprintf(buffer1, "Save Font: (unnamed%d) modified.  Save?", ed->id);
2746         else
2747           sprintf(buffer1, "Save Font: %s modified.  Save?", ed->file);
2748         if (guiutil_yes_or_no(ed->shell, buffer1, TRUE)) {
2749             /*
2750              * If the current file was imported, then make sure to use the
2751              * Save As... dialog instead of just saving under the name that
2752              * was constructed when importing.  The user won't know what the
2753              * default BDF file name of imported fonts look like.
2754              */
2755             if (ed->imported)
2756               guifile_save_as_wait(w, data);
2757             else
2758               guifile_save(w, data);
2759             return;
2760         }
2761     }
2762 
2763     xsrv_active_editor = ed->id;
2764 
2765     if (xsrv_dialog == 0) {
2766         xsrv_dialog = gtk_dialog_new();
2767         gtk_window_set_title(GTK_WINDOW(xsrv_dialog),
2768                              "X Server Font Selection");
2769         (void) g_signal_connect(G_OBJECT(xsrv_dialog), "delete_event",
2770                                 G_CALLBACK(gtk_widget_hide), 0);
2771 
2772         vbox = GTK_DIALOG(xsrv_dialog)->vbox;
2773         hbox = GTK_DIALOG(xsrv_dialog)->action_area;
2774 
2775         label = gtk_label_new("Filter");
2776         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
2777         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
2778 
2779         text = xsrv_filter_text = gtk_entry_new();
2780         gtk_entry_set_text(GTK_ENTRY(text), _XSRV_DEFAULT_FILTER);
2781         (void) g_signal_connect(G_OBJECT(text), "activate",
2782                                 G_CALLBACK(xsrv_filter), 0);
2783         gtk_box_pack_start(GTK_BOX(vbox), text, TRUE, TRUE, 0);
2784 
2785         swin = gtk_scrolled_window_new(0, 0);
2786         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
2787                                        GTK_POLICY_AUTOMATIC,
2788                                        GTK_POLICY_ALWAYS);
2789 
2790         store = gtk_list_store_new(1, G_TYPE_STRING);
2791         xsrv_font_list = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
2792         g_object_unref(store);
2793 
2794         (void) g_signal_connect(G_OBJECT(xsrv_font_list), "row_activated",
2795                                 G_CALLBACK(xsrv_activate_font),
2796                                 GUINT_TO_POINTER(ed->id));
2797 
2798         cell_renderer = gtk_cell_renderer_text_new();
2799         column = gtk_tree_view_column_new_with_attributes ("Fonts Found: 0",
2800                                                            cell_renderer,
2801                                                            "text", 0,
2802                                                            NULL);
2803 
2804         gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_AUTOSIZE);
2805         gtk_tree_view_append_column (GTK_TREE_VIEW(xsrv_font_list), column);
2806 
2807         /*
2808          * Force the list to have a certain width and height.
2809          */
2810         gtk_widget_set_size_request(xsrv_font_list, 550, 200);
2811 
2812         sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(xsrv_font_list));
2813         gtk_tree_selection_set_mode(sel, GTK_SELECTION_BROWSE);
2814 
2815         (void) g_signal_connect(G_OBJECT(sel), "changed",
2816                                 G_CALLBACK(xsrv_select_font), NULL);
2817 
2818         gtk_container_add(GTK_CONTAINER(swin), xsrv_font_list);
2819 
2820         gtk_box_pack_start(GTK_BOX(vbox), swin, TRUE, TRUE, 0);
2821 
2822         label = gtk_label_new("Selection");
2823         gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
2824         gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
2825 
2826         text = xsrv_selection_text = gtk_entry_new();
2827         (void) g_signal_connect(G_OBJECT(text), "activate",
2828                                 G_CALLBACK(xsrv_import_font),
2829                                 GUINT_TO_POINTER(ed->id));
2830         gtk_box_pack_start(GTK_BOX(vbox), text, TRUE, TRUE, 0);
2831 
2832         /*
2833          * Now add the buttons.
2834          */
2835         button = xsrv_import = gtk_button_new_with_label("Import");
2836         (void) g_signal_connect(G_OBJECT(button), "clicked",
2837                                 G_CALLBACK(xsrv_import_font),
2838                                 GUINT_TO_POINTER(ed->id));
2839         gtk_container_add(GTK_CONTAINER(hbox), button);
2840 
2841         button = xsrv_import = gtk_button_new_with_label("Clear Selection");
2842         (void) g_signal_connect(G_OBJECT(button), "clicked",
2843                                 G_CALLBACK(xsrv_clear_selection_text), 0);
2844         gtk_container_add(GTK_CONTAINER(hbox), button);
2845 
2846         button = gtk_button_new_with_label("Filter");
2847         (void) g_signal_connect(G_OBJECT(button), "clicked",
2848                                 G_CALLBACK(xsrv_filter), 0);
2849         gtk_container_add(GTK_CONTAINER(hbox), button);
2850 
2851         button = gtk_button_new_with_label("XLFD Filter");
2852         (void) g_signal_connect(G_OBJECT(button), "clicked",
2853                                 G_CALLBACK(xsrv_xlfd_filter), 0);
2854         gtk_container_add(GTK_CONTAINER(hbox), button);
2855 
2856         button = gtk_button_new_with_label("Cancel");
2857         (void) g_signal_connect_object(G_OBJECT(button), "clicked",
2858                                        G_CALLBACK(gtk_widget_hide),
2859                                        (gpointer) xsrv_dialog,
2860                                        G_CONNECT_SWAPPED);
2861         gtk_container_add(GTK_CONTAINER(hbox), button);
2862 
2863         gtk_widget_show_all(vbox);
2864         gtk_widget_show_all(hbox);
2865     }
2866 
2867     store =
2868         GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(xsrv_font_list)));
2869     column = gtk_tree_view_get_column(GTK_TREE_VIEW(xsrv_font_list), 0);
2870 
2871     /*
2872      * Load the list of fonts using the current filter pattern.  This needs to
2873      * be done each time in case the list of font paths has changed between
2874      * calls.
2875      */
2876     name = (gchar *) gtk_entry_get_text(GTK_ENTRY(xsrv_filter_text));
2877     fonts = XListFonts(GDK_DISPLAY(), name, _XSRV_MAX_FONTS, &nfonts);
2878 
2879     /*
2880      * Update the label on the font list with the number of fonts.
2881      */
2882     sprintf(buffer1, "Fonts Found: %d", nfonts);
2883     gtk_tree_view_column_set_title(column, buffer1);
2884 
2885     gtk_list_store_clear(store);
2886     for (i = 0; i < nfonts; i++) {
2887         gtk_list_store_append(store, &iter);
2888         gtk_list_store_set(store, &iter, 0, fonts[i], -1);
2889     }
2890 
2891     XFreeFontNames(fonts);
2892 
2893     /*
2894      * Show the dialog.
2895      */
2896     guiutil_show_dialog_centered(xsrv_dialog, ed->shell);
2897 
2898 }
2899 
2900 #endif /* HAVE_XLIB */
2901 
2902 void
guifile_export_psf_font(GtkWidget * w,gpointer data)2903 guifile_export_psf_font(GtkWidget *w, gpointer data)
2904 {
2905     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2906     bdf_font_t *font;
2907 
2908     font = fontgrid_get_font(FONTGRID(ed->fgrid));
2909 
2910     /*
2911      * Only character cell and mono width fonts can be exported as PSF2.
2912      */
2913     if (font->spacing == BDF_PROPORTIONAL) {
2914         sprintf(buffer2,
2915                 "Export Font: Font cannot be saved as PSF because %s ",
2916                 "the font has proportional width.");
2917         guiutil_error_message(ed->shell, buffer2);
2918         return;
2919     }
2920 
2921     update_save_dialog(ed, PSF_FORMAT);
2922 
2923     guiutil_show_dialog_centered(ed->save_dialog, ed->shell);
2924 }
2925 
2926 void
guifile_export_hex_font(GtkWidget * w,gpointer data)2927 guifile_export_hex_font(GtkWidget *w, gpointer data)
2928 {
2929     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2930 
2931     /*
2932      * No check is done for a "valid" HEX font because it actually pads the
2933      * output font into bitmaps of two sizes, the wider size twice as wide
2934      * as the narrower size.
2935      */
2936 
2937     update_save_dialog(ed, HEX_FORMAT);
2938 
2939     guiutil_show_dialog_centered(ed->save_dialog, ed->shell);
2940 }
2941 
2942 void
guifile_save_as(GtkWidget * w,gpointer data)2943 guifile_save_as(GtkWidget *w, gpointer data)
2944 {
2945     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2946 
2947     update_save_dialog(ed, BDF_FORMAT);
2948 
2949     guiutil_show_dialog_centered(ed->save_dialog, ed->shell);
2950 }
2951 
2952 void
guifile_save_as_wait(GtkWidget * w,gpointer data)2953 guifile_save_as_wait(GtkWidget *w, gpointer data)
2954 {
2955     save_dialog_done = FALSE;
2956 
2957     guifile_save_as(w, data);
2958     while (save_dialog_done == FALSE)
2959       gtk_main_iteration();
2960 }
2961 
2962 void
guifile_save(GtkWidget * w,gpointer data)2963 guifile_save(GtkWidget *w, gpointer data)
2964 {
2965     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
2966 
2967     /*
2968      * If this is a new font, then we need to show the file selection dialog.
2969      * Otherwise, simply write the font out.
2970      */
2971     if (ed->path == 0 && ed->file == 0) {
2972         guifile_save_as(w, data);
2973         return;
2974     }
2975 
2976     ed->export_format = BDF_FORMAT;
2977     sprintf(buffer1, "%s/%s", ed->path, ed->file);
2978     export_font(buffer1, ed, FALSE);
2979 }
2980 
2981 void
guifile_new_editor(GtkWidget * w,gpointer data)2982 guifile_new_editor(GtkWidget *w, gpointer data)
2983 {
2984     guint n;
2985 
2986     n = gbdfed_make_editor(0, FALSE);
2987 
2988     gtk_widget_show_all(editors[n].shell);
2989 }
2990 
2991 /*
2992  * A routine to load a BDF font directly.
2993  */
2994 void
guifile_load_bdf_font(gbdfed_editor_t * ed,const gchar * fullpath)2995 guifile_load_bdf_font(gbdfed_editor_t *ed, const gchar *fullpath)
2996 {
2997     gchar *dir, *file;
2998 
2999     if (fullpath == NULL)
3000       return;
3001 
3002     file = g_path_get_basename(fullpath);
3003     dir = g_path_get_dirname(fullpath);
3004     load_bdf_font(ed, fullpath, dir, file);
3005     if (dir != NULL)
3006       g_free(dir);
3007     if (file != NULL)
3008       g_free(file);
3009 }
3010