]> git.karo-electronics.de Git - gbdfed.git/blob - gbdfed.c
Initial import of upstream V1.6 from
[gbdfed.git] / gbdfed.c
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 /**************************************************************************
27  *
28  * Application globals.
29  *
30  **************************************************************************/
31
32 gchar buffer1[BUFSIZ];
33 gchar buffer2[BUFSIZ];
34 gbdfed_options_t options;
35
36 /*
37  * The list of editors that exist.
38  */
39 gbdfed_editor_t *editors;
40 guint num_editors;
41
42 /**************************************************************************
43  *
44  * Forward declarations and local variables.
45  *
46  **************************************************************************/
47
48 /*
49  * These are formats that can appear in the editor for importing/loading and
50  * exporting fonts.
51  */
52 #define XMBDFED_BDF_FORMAT     1
53 #define XMBDFED_CONSOLE_FORMAT 2
54 #define XMBDFED_PKGF_FORMAT    3
55 #define XMBDFED_FNT_FORMAT     4
56 #define XMBDFED_HBF_FORMAT     5
57 #define XMBDFED_TTF_FORMAT     6
58 #define XMBDFED_PSF_FORMAT     7
59 #define XMBDFED_HEX_FORMAT     8
60
61 /**************************************************************************
62  *
63  * Application icons.
64  *
65  **************************************************************************/
66
67 static const gchar *gbdfed_16x16[] = {
68 /* width height num_colors chars_per_pixel */
69 "    16    16        5            1",
70 /* colors */
71 ". c #dcdcdc",
72 "# c #ff0000",
73 "a c #ffffff",
74 "b c #000000",
75 "c c #b2c0dc",
76 /* pixels */
77 "..#.............",
78 "a.#.a.a.a.a.a.a.",
79 "..#.............",
80 "a.#bbba.a.a.a.b.",
81 "..#.bbb......b..",
82 "a.#.abbba.a.b.a.",
83 "..#...bbb..b....",
84 "a.#.a.abb.b.a.a.",
85 "..#....b.bb.....",
86 "a.#.a.b.abbba.a.",
87 "..#..b....bbb...",
88 "a.#.b.a.a.abbba.",
89 "..#b........bbb.",
90 "################",
91 "..#.............",
92 "c.#.c.c.c.c.c.c."
93 };
94
95 static const gchar *gbdfed_32x32[] = {
96 /* width height num_colors chars_per_pixel */
97 "    32    32        4            1",
98 /* colors */
99 ". c #d9d9d9",
100 "# c #ffffff",
101 "a c #ff0000",
102 "b c #000000",
103 /* pixels */
104 ".##a##.##.##.##.##.##.##.##.##.#",
105 ".##a##.##.##.##.##.##.##.##.##.#",
106 "...a............................",
107 ".##a##.##.##.##.##.##.##.##.##.#",
108 ".##a##.##.##.##.##.##.##.##.##.#",
109 "...a............................",
110 ".##abb.bb.bb.##.##.##.##.##.bb.#",
111 ".##abb.bb.bb.##.##.##.##.##.bb.#",
112 "...a............................",
113 ".##a##.bb.bb.bb.##.##.##.bb.##.#",
114 ".##a##.bb.bb.bb.##.##.##.bb.##.#",
115 "...a............................",
116 ".##a##.##.bb.bb.bb.##.bb.##.##.#",
117 ".##a##.##.bb.bb.bb.##.bb.##.##.#",
118 "...a............................",
119 ".##a##.##.##.bb.##.bb.##.##.##.#",
120 ".##a##.##.##.bb.##.bb.##.##.##.#",
121 "...a............................",
122 ".##a##.##.bb.##.bb.bb.bb.##.##.#",
123 ".##a##.##.bb.##.bb.bb.bb.##.##.#",
124 "...a............................",
125 ".##a##.bb.##.##.##.bb.bb.bb.##.#",
126 ".##a##.bb.##.##.##.bb.bb.bb.##.#",
127 "...a............................",
128 ".##abb.##.##.##.##.##.bb.bb.bb.#",
129 ".##abb.##.##.##.##.##.bb.bb.bb.#",
130 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
131 ".##a##.##.##.##.##.##.##.##.##.#",
132 ".##a##.##.##.##.##.##.##.##.##.#",
133 "...a............................",
134 ".##a##.##.##.##.##.##.##.##.##.#",
135 ".##a##.##.##.##.##.##.##.##.##.#"
136 };
137
138 static const gchar *gbdfed_48x48[] = {
139 /* width height num_colors chars_per_pixel */
140 "    48    48        4            1",
141 /* colors */
142 ". c #dcdcdc",
143 "# c #ff0000",
144 "a c #ffffff",
145 "b c #000000",
146 /* pixels */
147 "....#...........................................",
148 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa",
149 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa",
150 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa..aa.aaa.aaa",
151 "....#...........................................",
152 ".aaa#bbb.bbb.bbb.aaa.aaa.aaa.aaa.aaa.aaa.aaa.bbb",
153 ".aaa#bbb.bbb.bbb.aaa.aaa.aaa.aaa.aaa.aaa.aaa.bbb",
154 ".aaa#bbb.bbb.bbb.aaa.aaa.aaa.aaa.aaa.aaa.aaa.bbb",
155 "....#...........................................",
156 ".aaa#aaa.bbb.bbb.bbb.aaa.aaa.aaa.aaa.aaa.bbb.aaa",
157 ".aaa#aaa.bbb.bbb.bbb.aaa.aaa.aaa.aaa.aaa.bbb.aaa",
158 ".aaa#aaa.bbb.bbb.bbb.aaa.aaa.aaa.aaa.aaa.bbb.aaa",
159 "....#...........................................",
160 ".aaa#aaa.aaa.bbb.bbb.bbb.aaa.aaa.aaa.bbb.aaa.aaa",
161 ".aaa#aaa.aaa.bbb.bbb.bbb.aaa.aaa.aaa.bbb.aaa.aaa",
162 ".aaa#aaa.aaa.bbb.bbb.bbb.aaa.aaa.aaa.bbb.aaa.aaa",
163 "....#...........................................",
164 ".aaa#aaa.aaa.aaa.bbb.bbb.bbb.aaa.bbb.aaa.aaa.aaa",
165 ".aaa#aaa.aaa.aaa.bbb.bbb.bbb.aaa.bbb.aaa.aaa.aaa",
166 ".aaa#aaa.aaa.aaa.bbb.bbb.bbb.aaa.bbb.aaa.aaa.aaa",
167 "....#...........................................",
168 ".aaa#aaa.aaa.aaa.aaa.bbb.aaa.bbb.aaa.aaa.aaa.aaa",
169 ".aaa#aaa.aaa.aaa.aaa.bbb.aaa.bbb.aaa.aaa.aaa.aaa",
170 ".aaa#aaa.aaa.aaa.aaa.bbb.aaa.bbb.aaa.aaa.aaa.aaa",
171 "....#...........................................",
172 ".aaa#aaa.aaa.aaa.bbb.aaa.bbb.bbb.bbb.aaa.aaa.aaa",
173 ".aaa#aaa.aaa.aaa.bbb.aaa.bbb.bbb.bbb.aaa.aaa.aaa",
174 ".aaa#aaa.aaa.aaa.bbb.aaa.bbb.bbb.bbb.aaa.aaa.aaa",
175 "....#...........................................",
176 ".aaa#aaa.aaa.bbb.aaa.aaa.aaa.bbb.bbb.bbb.aaa.aaa",
177 ".aaa#aaa.aaa.bbb.aaa.aaa.aaa.bbb.bbb.bbb.aaa.aaa",
178 ".aaa#aaa.aaa.bbb.aaa.aaa.aaa.bbb.bbb.bbb.aaa.aaa",
179 "....#...........................................",
180 ".aaa#aaa.bbb.aaa.aaa.aaa.aaa.aaa.bbb.bbb.bbb.aaa",
181 ".aaa#aaa.bbb.aaa.aaa.aaa.aaa.aaa.bbb.bbb.bbb.aaa",
182 ".aaa#aaa.bbb.aaa.aaa.aaa.aaa.aaa.bbb.bbb.bbb.aaa",
183 "....#...........................................",
184 ".aaa#bbb.aaa.aaa.aaa.aaa.aaa.aaa.aaa.bbb.bbb.bbb",
185 ".aaa#bbb.aaa.aaa.aaa.aaa.aaa.aaa.aaa.bbb.bbb.bbb",
186 ".aaa#bbb.aaa.aaa.aaa.aaa.aaa.aaa.aaa.bbb.bbb.bbb",
187 "################################################",
188 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa",
189 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa",
190 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa",
191 "....#...........................................",
192 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa",
193 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa",
194 ".aaa#aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa.aaa"
195 };
196
197 static gboolean icons_set = FALSE;
198
199 /**************************************************************************
200  *
201  * GTK signal handlers.
202  *
203  **************************************************************************/
204
205 static gboolean
206 quit_application(GtkWidget *w, GdkEvent *ev, gpointer data)
207 {
208     guint i, modified;
209
210     for (i = modified = 0; i < num_editors; i++) {
211         if (fontgrid_get_font_modified(FONTGRID(editors[i].fgrid)))
212           modified++;
213     }
214
215     if (modified) {
216         if (modified == 1)
217           sprintf(buffer1, "Save Font: One font was modified.  Save?");
218         else
219           sprintf(buffer1, "Save Font: %d fonts were modified.  Save?",
220                   modified);
221         if (guiutil_yes_or_no(editors[0].shell, buffer1, TRUE)) {
222
223             /*
224              * Go through each editor and ask if the font should be saved if
225              * it has been modified.
226              */
227             for (i = 0; i < num_editors; i++) {
228                 if (fontgrid_get_font_modified(FONTGRID(editors[i].fgrid))) {
229                     /*
230                      * Ask if this font should be saved.
231                      */
232                     if (editors[i].file)
233                       sprintf(buffer1, "Save Font: Save %s?", editors[i].file);
234                     else
235                       sprintf(buffer1, "Save Font: Save unnamed%d.bdf?", i);
236
237                     /*
238                      * Always ask this question using the shell window of the
239                      * first editor so the dialog box doesn't move around.
240                      */
241                     if (guiutil_yes_or_no(editors[0].shell, buffer1, TRUE))
242                       guifile_save_as_wait(w, GUINT_TO_POINTER(i));
243                 }
244             }
245         }
246     }
247
248     /*
249      * Ask if the user really wants to exit if their preferences specify this
250      * question should be asked.
251      */
252     if (options.really_exit &&
253         !guiutil_yes_or_no(editors[0].shell, "Really Quit?", TRUE))
254       return TRUE;
255
256     /*
257      * Call all the cleanup routines in case something really needs to be
258      * deallocated.
259      */
260     guigedit_cleanup();
261     guiedit_preference_cleanup();
262     guiutil_cursor_cleanup();
263     guihelp_cleanup();
264
265     bdf_cleanup();
266     gtk_main_quit();
267     exit(0);
268 }
269
270 static void
271 show_editor(GtkWidget *w, gpointer data)
272 {
273     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
274
275     /*
276      * Nothing seems to force the original window to the top of the stack
277      * on the screen, but this supposedly does everything necessary.
278      */
279     gtk_widget_show_all(ed->shell);
280     gtk_window_present(GTK_WINDOW(ed->shell));
281 }
282
283 static void
284 goto_other_page(GtkWidget *w, gpointer editor)
285 {
286     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
287     gint32 opage;
288     FontgridPageInfo pi;
289
290     fontgrid_get_page_info(FONTGRID(ed->fgrid), &pi);
291
292     if (!pi.unencoded_page) {
293         opage = ed->last_pageno;
294         ed->last_pageno = pi.current_page;
295     } else {
296         opage = ed->last_upageno;
297         ed->last_upageno = pi.current_page;
298     }
299
300     if (opage != -1 && opage != pi.current_page)
301       fontgrid_goto_page(FONTGRID(ed->fgrid), opage);
302 }
303
304 static void
305 toggle_encoding_view(GtkWidget *w, gpointer editor)
306 {
307     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
308     gchar *label;
309     GtkLabel *lw;
310
311     if (fontgrid_viewing_unencoded(FONTGRID(ed->fgrid)))
312       label = "Unencoded";
313     else
314       label = "Encoded";
315     lw = GTK_LABEL(GTK_BIN(ed->view_unencoded)->child);
316     gtk_label_set_text(lw, label);
317
318     fontgrid_switch_encoding_view(FONTGRID(ed->fgrid));
319 }
320
321 static void
322 toggle_view_orientation(GtkWidget *w, gpointer editor)
323 {
324     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
325     gchar *label;
326     GtkLabel *lw;
327
328     if (fontgrid_get_orientation(FONTGRID(ed->fgrid)) ==
329         GTK_ORIENTATION_VERTICAL) {
330         fontgrid_set_orientation(FONTGRID(ed->fgrid),
331                                  GTK_ORIENTATION_HORIZONTAL);
332         label = "Vertical View";
333     } else {
334         fontgrid_set_orientation(FONTGRID(ed->fgrid),
335                                  GTK_ORIENTATION_VERTICAL);
336         label = "Horizontal View";
337     }
338     lw = GTK_LABEL(GTK_BIN(ed->view_orientation)->child);
339     gtk_label_set_text(lw, label);
340 }
341
342 static void
343 set_code_base(GtkWidget *w, gpointer editor)
344 {
345     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
346     gint base;
347
348     if (w == ed->view_oct)
349       base = 8;
350     else if (w == ed->view_dec)
351       base = 10;
352     else
353       base = 16;
354
355     fontgrid_set_code_base(FONTGRID(ed->fgrid), base);
356
357     /*
358      * Make sure the font info editor is updated when the code base
359      * changes.
360      */
361     guiedit_update_code_base(ed);
362     guigedit_set_code_base(base);
363 }
364
365 static void
366 page_change(GtkWidget *w, gpointer pinfo, gpointer editor)
367 {
368     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
369     FontgridPageInfo *pi = (FontgridPageInfo *) pinfo;
370     gchar *label;
371     GtkLabel *lw;
372
373     if (pi->previous_page < 0) {
374         gtk_widget_set_sensitive(ed->prev, FALSE);
375         gtk_widget_set_sensitive(ed->first, FALSE);
376     } else {
377         gtk_widget_set_sensitive(ed->prev, TRUE);
378         gtk_widget_set_sensitive(ed->first, TRUE);
379     }
380
381     if (pi->next_page < 0) {
382         gtk_widget_set_sensitive(ed->next, FALSE);
383         gtk_widget_set_sensitive(ed->last, FALSE);
384     } else {
385         gtk_widget_set_sensitive(ed->next, TRUE);
386         gtk_widget_set_sensitive(ed->last, TRUE);
387     }
388
389     /*
390      * Update the page number field with the current page.
391      */
392     sprintf(buffer1, "%d", pi->current_page);
393     gtk_entry_set_text(GTK_ENTRY(ed->pageno), buffer1);
394     gtk_editable_set_position(GTK_EDITABLE(ed->pageno), -1);
395
396     /*
397      * Finally, modify the label on the Encoded/Unencoded view menu item.
398      */
399     label = (pi->unencoded_page) ? "Encoded" : "Unencoded";
400     lw = GTK_LABEL(GTK_BIN(ed->view_unencoded)->child);
401     gtk_label_set_text(lw, label);
402 }
403
404 static void
405 first_page(GtkWidget *w, gpointer editor)
406 {
407     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
408
409     fontgrid_goto_first_page(FONTGRID(ed->fgrid));
410
411     /*
412      * Force the focus back to the Fontgrid.
413      */
414     gtk_widget_grab_focus(ed->fgrid);
415 }
416
417 static void
418 previous_page(GtkWidget *w, gpointer editor)
419 {
420     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
421
422     fontgrid_goto_previous_page(FONTGRID(ed->fgrid));
423
424     /*
425      * Force the focus back to the Fontgrid.
426      */
427     gtk_widget_grab_focus(ed->fgrid);
428 }
429
430 static void
431 next_page(GtkWidget *w, gpointer editor)
432 {
433     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
434
435     fontgrid_goto_next_page(FONTGRID(ed->fgrid));
436
437     /*
438      * Force the focus back to the Fontgrid.
439      */
440     gtk_widget_grab_focus(ed->fgrid);
441 }
442
443 static void
444 last_page(GtkWidget *w, gpointer editor)
445 {
446     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
447
448     fontgrid_goto_last_page(FONTGRID(ed->fgrid));
449
450     /*
451      * Force the focus back to the Fontgrid.
452      */
453     gtk_widget_grab_focus(ed->fgrid);
454 }
455
456 static void
457 goto_page_or_code(GtkWidget *w, gpointer editor)
458 {
459     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
460     const gchar *text;
461     gint32 code;
462     FontgridPageInfo pi;
463
464     fontgrid_get_page_info(FONTGRID(ed->fgrid), &pi);
465
466     if (!pi.unencoded_page)
467       ed->last_pageno = pi.current_page;
468     else
469       ed->last_upageno = pi.current_page;
470
471     if (w == ed->pageno) {
472         text = gtk_entry_get_text(GTK_ENTRY(ed->pageno));
473         fontgrid_goto_page(FONTGRID(ed->fgrid),
474                            _bdf_atol((char *) text, 0, 10));
475     } else {
476         text = gtk_entry_get_text(GTK_ENTRY(ed->charno));
477         code = _bdf_atol((char *) text, 0,
478                          fontgrid_get_code_base(FONTGRID(ed->fgrid)));
479         fontgrid_goto_code(FONTGRID(ed->fgrid), code);
480     }
481 }
482
483 static void
484 update_selection_info(GtkWidget *w, gpointer sinfo, gpointer editor)
485 {
486     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
487     FontgridSelectionInfo *si = (FontgridSelectionInfo *) sinfo;
488     short as, ds, rt, lt;
489     gint32 start, end;
490     guint b1 = 0, b2 = 0, b3, b4;
491
492     as = ds = rt = lt = 0;
493     if (si->start == si->end) {
494         if (si->num_glyphs != 0 && si->glyphs != 0) {
495             b1 = (si->start >> 8) & 0xff;
496             b2 = si->start & 0xff;
497
498             as = si->glyphs->bbx.ascent;
499             ds = si->glyphs->bbx.descent;
500             lt = si->glyphs->bbx.x_offset;
501             rt = si->glyphs->bbx.width + lt;
502             if (si->glyphs->name != 0)
503               (void) strcpy(buffer1, si->glyphs->name);
504             else
505               sprintf(buffer1, "char%d", si->glyphs->encoding);
506
507             /*
508              * If the glyph test dialog is active, send it the glyph if this
509              * is an end selection event.
510              */
511             if (si->reason == FONTGRID_END_SELECTION && glyphtest != 0)
512               glyphtest_add_glyph(GLYPHTEST(glyphtest),
513                                   fontgrid_get_font(FONTGRID(ed->fgrid)),
514                                   si->glyphs);
515         } else
516           sprintf(buffer1, "char%d", si->start);
517
518         switch (si->base) {
519           case 8:
520             sprintf(buffer2, "\"%s\" %o (%o, %o)", buffer1,
521                     si->start, b1, b2);
522             break;
523           case 10:
524             sprintf(buffer2, "\"%s\" %d (%d, %d)", buffer1,
525                     si->start, b1, b2);
526             break;
527           case 16:
528             sprintf(buffer2, "\"%s\" %04X (%02X, %02X)", buffer1,
529                     si->start, b1, b2);
530             break;
531         }
532
533     } else {
534         /*
535          * A range of glyphs has been selected.
536          */
537         if (si->end < si->start) {
538             start = si->end;
539             end = si->start;
540         } else {
541             start = si->start;
542             end = si->end;
543         }
544         b1 = (start >> 8) & 0xff;
545         b2 = start & 0xff;
546         b3 = (end >> 8) & 0xff;
547         b4 = end & 0xff;
548
549         switch (si->base) {
550           case 8:
551             sprintf(buffer2, "Selection %o (%o, %o) - %o (%o, %o)",
552                     start, b1, b2, end, b3, b4);
553             break;
554           case 10:
555             sprintf(buffer2, "Selection %d (%d, %d) - %d (%d, %d)",
556                     start, b1, b2, end, b3, b4);
557             break;
558           case 16:
559             sprintf(buffer2, "Selection %04X (%02X, %02X) - %04X (%02X, %02X)",
560                     start, b1, b2, end, b3, b4);
561             break;
562         }
563     }
564
565     /*
566      * Update the glyph info label.
567      */
568     gtk_label_set_text(GTK_LABEL(ed->charinfo), buffer2);
569
570     /*
571      * Update the metrics label.
572      */
573     sprintf(buffer1, "ascent %hd descent %hd right %hd left %hd",
574             as, ds, rt, lt);
575     gtk_label_set_text(GTK_LABEL(ed->metrics), buffer1);
576
577     switch (si->reason) {
578       case FONTGRID_START_SELECTION:
579         break;
580       case FONTGRID_EXTEND_SELECTION:
581         break;
582       case FONTGRID_END_SELECTION:
583         break;
584       case FONTGRID_ACTIVATE:
585         guigedit_edit_glyph(ed, si);
586         break;
587       case FONTGRID_BASE_CHANGE:
588         break;
589     }
590 }
591
592 static void
593 handle_modified_signal(GtkWidget *w, gpointer minfo, gpointer editor)
594 {
595     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
596     gchar *prgname = g_get_prgname();
597     FontgridModificationInfo *mi;
598
599     mi = (FontgridModificationInfo *) minfo;
600
601     /*
602      * Check to see what change was made so updates can be handled
603      * appropriately.
604      */
605     if (mi->reason == FONTGRID_NAME_MODIFIED)
606       gtk_entry_set_text(GTK_ENTRY(ed->fontname), mi->name);
607     else if (mi->reason == FONTGRID_PROPERTIES_MODIFIED)
608       /*
609        * Make sure the font info editing dialog knows that the list of
610        * font properties changed.
611        */
612       guiedit_update_font_properties(ed);
613     else if (mi->reason == FONTGRID_GLYPHS_DELETED ||
614              mi->reason == FONTGRID_GLYPHS_PASTED)
615       guiedit_update_font_details(ed);
616     else if ((mi->reason == FONTGRID_DEVICE_WIDTH_MODIFIED ||
617               mi->reason == FONTGRID_GLYPHS_MODIFIED) && glyphtest != 0)
618       /*
619        * Update the glyph test widget with the new device width.
620        */
621       glyphtest_update_device_width(GLYPHTEST(glyphtest),
622                                     fontgrid_get_font(FONTGRID(ed->fgrid)));
623
624     /*
625      * Update the title.
626      */
627     if (ed->file == 0)
628       sprintf(buffer1, "%s - (unnamed%d) [modified]", prgname, ed->id);
629     else
630       sprintf(buffer1, "%s - %s [modified]", prgname, ed->file);
631
632     gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
633 }
634
635 static void
636 view_font_messages(GtkWidget *w, gpointer editor)
637 {
638     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(editor);
639     GtkWidget *dialog, *frame, *button, *label, *vbox, *sw;
640     GtkTextBuffer *text;
641     gchar *msgs;
642
643     if (ed->messages_dialog == 0) {
644         /*
645          * Special case of no messages and the menu item hasn't been
646          * checked for sensitivity yet.
647          */
648         if (fontgrid_get_font_messages(FONTGRID(ed->fgrid)) == 0)
649           return;
650
651         dialog = ed->messages_dialog = gtk_dialog_new();
652         (void) g_signal_connect(G_OBJECT(dialog), "delete_event",
653                                 G_CALLBACK(gtk_widget_hide), 0);
654
655         frame = gtk_frame_new(0);
656         label = ed->messages_label = gtk_label_new("");
657         gtk_container_add(GTK_CONTAINER(frame), label);
658
659         vbox = GTK_DIALOG(dialog)->vbox;
660         gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0);
661
662         sw = gtk_scrolled_window_new(NULL, NULL);
663         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
664                                        GTK_POLICY_NEVER,
665                                        GTK_POLICY_ALWAYS);
666         gtk_box_pack_start(GTK_BOX(vbox), sw, FALSE, FALSE, 0);
667
668         /*
669          * Add the text widget.
670          */
671         text = gtk_text_buffer_new(NULL);
672         ed->messages_text = gtk_text_view_new_with_buffer(text);
673         gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(ed->messages_text),
674                                          FALSE);
675         gtk_widget_set_size_request(ed->messages_text, 500, 200);
676
677         gtk_text_view_set_editable(GTK_TEXT_VIEW(ed->messages_text), FALSE);
678         gtk_container_add(GTK_CONTAINER(sw), ed->messages_text);
679
680         button = gtk_button_new_with_label("Close");
681         (void) g_signal_connect_object(G_OBJECT(button), "clicked",
682                                        G_CALLBACK(gtk_widget_hide),
683                                        (gpointer) dialog,
684                                        G_CONNECT_SWAPPED);
685         gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->action_area),
686                           button);
687
688         gtk_widget_show_all(GTK_DIALOG(ed->messages_dialog)->vbox);
689         gtk_widget_show_all(GTK_DIALOG(ed->messages_dialog)->action_area);
690     } else
691       text = gtk_text_view_get_buffer(GTK_TEXT_VIEW(ed->messages_text));
692
693     /*
694      * Update the label with the font name in case it changed since the last
695      * time the messages were shown.
696      */
697     if (ed->file != 0)
698       sprintf(buffer1, "%s: Messages", ed->file);
699     else
700       sprintf(buffer1, "unnamed%d.bdf: Messages", ed->id);
701     gtk_label_set_text(GTK_LABEL(ed->messages_label), buffer1);
702
703     /*
704      * Now change the text itself.
705      */
706     if ((msgs = fontgrid_get_font_messages(FONTGRID(ed->fgrid))) == 0)
707       msgs = "";
708     gtk_text_buffer_set_text(text, msgs, -1);
709
710     guiutil_show_dialog_centered(ed->messages_dialog, ed->shell);
711 }
712
713 /**************************************************************************
714  *
715  * Menu construction.
716  *
717  **************************************************************************/
718
719 static GtkWidget *
720 make_accel_menu_item(GtkWidget *menu, const gchar *text, const gchar *accel,
721                      GtkAccelGroup *ag)
722 {
723     GtkWidget *mi;
724     guint key;
725     GdkModifierType mods;
726
727     mi = gtk_menu_item_new_with_mnemonic(text);
728
729     gtk_accelerator_parse(accel, &key, &mods);
730     gtk_widget_add_accelerator(mi, "activate", ag, key, mods,
731                                GTK_ACCEL_VISIBLE|GTK_ACCEL_LOCKED);
732     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mi);
733
734     return mi;
735 }
736
737 /*
738  * Handle all the menu checking needed to enable or disable menu items on
739  * all the menus.
740  */
741 static gint
742 menu_popup(GtkWidget *w, GdkEvent *event, gpointer data)
743 {
744     gbdfed_editor_t *ed;
745     bdf_font_t *font;
746     GtkWidget *mitem;
747     GList *kids, *label;
748     gboolean flag;
749     guint i;
750
751     /*
752      * Get a pointer to the editor.
753      */
754     ed = editors + GPOINTER_TO_UINT(data);
755
756     font = fontgrid_get_font(FONTGRID(ed->fgrid));
757
758     if (event->type == GDK_MAP) {
759         if (w == ed->file_menu) {
760             if (font && font->modified)
761               gtk_widget_set_sensitive(ed->file_save, TRUE);
762             else
763               gtk_widget_set_sensitive(ed->file_save, FALSE);
764
765             if (font && font->glyphs_used > 0)
766               gtk_widget_set_sensitive(ed->file_export, TRUE);
767             else
768               gtk_widget_set_sensitive(ed->file_export, FALSE);
769         } else if (w == ed->edit_menu) {
770             /*
771              * If the fontgrid clipboard is empty, then disable the paste,
772              * overlay, and insert menu options.
773              */
774             flag = fontgrid_clipboard_empty(FONTGRID(ed->fgrid)) ?
775                 FALSE : TRUE;
776             gtk_widget_set_sensitive(ed->edit_paste, flag);
777             gtk_widget_set_sensitive(ed->edit_overlay, flag);
778             gtk_widget_set_sensitive(ed->edit_insert, flag);
779
780             /*
781              * If there is no selection, disable the cut and copy menu
782              * options.
783              */
784             flag = fontgrid_has_selection(FONTGRID(ed->fgrid), 0) ?
785                 TRUE : FALSE;
786             gtk_widget_set_sensitive(ed->edit_cut, flag);
787             gtk_widget_set_sensitive(ed->edit_copy, flag);
788
789             flag = (font && font->glyphs_used > 0) ? TRUE : FALSE;
790
791             /*
792              * Disable glyph rename when viewing unecoded glyphs because their
793              * encoding values are not actual.
794              */
795             if (fontgrid_viewing_unencoded(FONTGRID(ed->fgrid)) || !flag)
796               gtk_widget_set_sensitive(ed->edit_rename_glyphs, FALSE);
797             else
798               gtk_widget_set_sensitive(ed->edit_rename_glyphs, TRUE);
799
800             gtk_widget_set_sensitive(ed->edit_test_glyphs, flag);
801         } else if (w == ed->edit_rename_menu) {
802             if (options.adobe_name_file != 0)
803               gtk_widget_set_sensitive(ed->edit_adobe_names, TRUE);
804             else
805               gtk_widget_set_sensitive(ed->edit_adobe_names, FALSE);
806             if (options.unicode_name_file != 0)
807               gtk_widget_set_sensitive(ed->edit_unicode_names, TRUE);
808             else
809               gtk_widget_set_sensitive(ed->edit_unicode_names, FALSE);
810         } else if (w == ed->name_submenu) {
811             flag = (!font || bdf_has_xlfd_name(font)) ? FALSE : TRUE;
812             gtk_widget_set_sensitive(ed->edit_make_xlfd, flag);
813         } else if (w == ed->view_menu) {
814             if (fontgrid_get_font_messages(FONTGRID(ed->fgrid)))
815               gtk_widget_set_sensitive(ed->view_messages, TRUE);
816             else
817               gtk_widget_set_sensitive(ed->view_messages, FALSE);
818         } else if (w == ed->win_menu) {
819             /*
820              * Go through and update the file names that might have changed
821              * since the last time this menu popped up.
822              */
823             for (i = 0, kids = GTK_MENU(w)->menu_shell.children; kids != 0;
824                  kids = kids->next, i++) {
825                 if (editors[i].file == 0)
826                   sprintf(buffer1, "(unnamed%d)", i);
827                 else
828                   strcpy(buffer1, editors[i].file);
829                 label = gtk_container_get_children(GTK_CONTAINER(kids->data));
830                 gtk_label_set_text(GTK_LABEL(label->data), buffer1);
831             } 
832
833             /*
834              * Add any new editors that were created since the last time this
835              * menu was shown.
836              */
837             for (; i < num_editors; i++) {
838                 if (editors[i].file == 0)
839                   sprintf(buffer1, "(unnamed%d)", editors[i].id);
840                 else
841                   strcpy(buffer1, editors[i].file);
842
843                 mitem = gtk_menu_item_new_with_label(buffer1);
844                 (void) g_signal_connect(G_OBJECT(mitem), "activate",
845                                         G_CALLBACK(show_editor),
846                                         GUINT_TO_POINTER(i));
847                 gtk_menu_shell_append(GTK_MENU_SHELL(ed->win_menu), mitem);
848                 gtk_widget_show(mitem);
849             }
850
851             /*
852              * Disable the item for this editor.
853              */
854             gtk_widget_set_sensitive(ed->win_menu_item, FALSE);
855         }
856     } else if (event->type == GDK_UNMAP) {
857         /*
858          * Enable everything again, so it doesn't get forgotten.
859          */
860         gtk_widget_set_sensitive(ed->file_save, TRUE);
861         gtk_widget_set_sensitive(ed->file_export, TRUE);
862         gtk_widget_set_sensitive(ed->edit_paste, TRUE);
863         gtk_widget_set_sensitive(ed->edit_overlay, TRUE);
864         gtk_widget_set_sensitive(ed->edit_insert, TRUE);
865         gtk_widget_set_sensitive(ed->edit_cut, TRUE);
866         gtk_widget_set_sensitive(ed->edit_copy, TRUE);
867         gtk_widget_set_sensitive(ed->edit_rename_glyphs, TRUE);
868         gtk_widget_set_sensitive(ed->edit_adobe_names, TRUE);
869         gtk_widget_set_sensitive(ed->edit_unicode_names, TRUE);
870         gtk_widget_set_sensitive(ed->edit_test_glyphs, TRUE);
871         gtk_widget_set_sensitive(ed->edit_make_xlfd, TRUE);
872         gtk_widget_set_sensitive(ed->win_menu_item, TRUE);
873         gtk_widget_set_sensitive(ed->view_messages, TRUE);
874     }
875
876     return FALSE;
877 }
878
879 #if (GTK_MAJOR_VERSION >= 2 && GTK_MINOR_VERSION >= 10)
880 static void
881 open_recent_font(GtkWidget *w, gpointer data)
882 {
883     gchar *p, *uri = gtk_recent_chooser_get_current_uri(GTK_RECENT_CHOOSER(w));
884     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
885
886     if (uri == NULL)
887       return;
888
889     /*
890      * Skip the URI prefix to get to the path. The URI's are strictly local
891      * at the moment.
892      */
893     for (p = uri; *p && *p != ':'; p++);
894     if (*p != ':')
895       return;
896     p++;
897     if (*p == '/' && *(p + 1) == '/')
898       p += 2;
899     guifile_load_bdf_font(ed, (const gchar *) p);
900     g_free(uri);
901 }
902
903 static GtkWidget *
904 make_recent_menu(guint ed_id)
905 {
906     GtkWidget *menu;
907     GtkRecentFilter *filter;
908     GtkRecentManager *manager;
909
910     manager = gtk_recent_manager_get_default();
911     menu = gtk_recent_chooser_menu_new_for_manager(manager);
912     gtk_recent_chooser_set_limit(GTK_RECENT_CHOOSER(menu), 10);
913     gtk_recent_chooser_set_sort_type(GTK_RECENT_CHOOSER(menu),
914                                      GTK_RECENT_SORT_MRU);
915     gtk_recent_chooser_set_show_tips(GTK_RECENT_CHOOSER(menu), TRUE);
916     gtk_recent_chooser_menu_set_show_numbers(GTK_RECENT_CHOOSER_MENU(menu),
917                                              TRUE);
918     gtk_recent_chooser_set_local_only(GTK_RECENT_CHOOSER(menu), TRUE);
919     filter = gtk_recent_filter_new();
920     gtk_recent_filter_add_pattern(filter, "*.[Bb][Dd][Ff]");
921     gtk_recent_chooser_set_filter(GTK_RECENT_CHOOSER(menu), filter);
922
923     (void) g_signal_connect(G_OBJECT(menu), "item_activated",
924                             G_CALLBACK(open_recent_font),
925                             GUINT_TO_POINTER(ed_id));
926
927     return menu;
928 }
929 #endif
930
931 static GtkWidget *
932 make_file_menu(gbdfed_editor_t *ed, GtkWidget *menubar)
933 {
934     GtkWidget *file, *menu, *submenu, *mitem, *sep;
935
936     /*
937      * Create the File menu.
938      */
939     file = gtk_menu_item_new_with_mnemonic("_File");
940
941     ed->file_menu = menu = gtk_menu_new();
942     (void) g_signal_connect(G_OBJECT(menu), "map_event",
943                             G_CALLBACK(menu_popup),
944                             GUINT_TO_POINTER(ed->id));
945
946     mitem = make_accel_menu_item(menu, "_New", "<Control>N", ed->ag);
947     (void) g_signal_connect(G_OBJECT(mitem), "activate",
948                             G_CALLBACK(guifile_new_editor), 0);
949
950     mitem = make_accel_menu_item(menu, "_Open", "<Control>O", ed->ag);
951     (void) g_signal_connect(G_OBJECT(mitem), "activate",
952                             G_CALLBACK(guifile_import_bdf_font),
953                             GUINT_TO_POINTER(ed->id));
954
955     ed->file_save = make_accel_menu_item(menu, "_Save", "<Control>S", ed->ag);
956     (void) g_signal_connect(G_OBJECT(ed->file_save), "activate",
957                             G_CALLBACK(guifile_save),
958                             GUINT_TO_POINTER(ed->id));
959     mitem = make_accel_menu_item(menu, "Save _As...", "<Control>W", ed->ag);
960     (void) g_signal_connect(G_OBJECT(mitem), "activate",
961                             G_CALLBACK(guifile_save_as),
962                             GUINT_TO_POINTER(ed->id));
963
964     /*
965      * Separator.
966      */
967     sep = gtk_menu_item_new();
968     gtk_widget_set_sensitive(sep, FALSE);
969     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
970
971     /*
972      * Create the Import and Export menu items with their submenus.
973      */
974     mitem = gtk_menu_item_new_with_mnemonic("_Import");
975     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
976
977     submenu = gtk_menu_new();
978     gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), submenu);
979
980     mitem = make_accel_menu_item(submenu, "_PK/GF Font", "<Control>K", ed->ag);
981     (void) g_signal_connect(G_OBJECT(mitem), "activate",
982                             G_CALLBACK(guifile_import_pkgf_font),
983                             GUINT_TO_POINTER(ed->id));
984     mitem = make_accel_menu_item(submenu, "_Console Font", "<Control>L",
985                                  ed->ag);
986     (void) g_signal_connect(G_OBJECT(mitem), "activate",
987                             G_CALLBACK(guifile_import_console_font),
988                             GUINT_TO_POINTER(ed->id));
989 #ifdef HAVE_HBF
990     mitem = make_accel_menu_item(submenu, "_HBF Font", "<Control>H",
991                                  ed->ag);
992     (void) g_signal_connect(G_OBJECT(mitem), "activate",
993                             G_CALLBACK(guifile_import_hbf_font),
994                             GUINT_TO_POINTER(ed->id));
995 #endif
996
997     mitem = make_accel_menu_item(submenu, "_Windows Font", "<Control>B",
998                                  ed->ag);
999
1000     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1001                             G_CALLBACK(guifile_import_windows_font),
1002                             GUINT_TO_POINTER(ed->id));
1003 #ifdef HAVE_FREETYPE
1004     mitem = make_accel_menu_item(submenu, "_OpenType Font", "<Control>Y",
1005                                  ed->ag);
1006     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1007                             G_CALLBACK(guifile_import_otf_font),
1008                             GUINT_TO_POINTER(ed->id));
1009 #endif /* HAVE_FREETYPE */
1010
1011 #ifdef HAVE_XLIB
1012     /*
1013      * Separator.
1014      */
1015     sep = gtk_menu_item_new();
1016     gtk_widget_set_sensitive(sep, FALSE);
1017     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), sep);
1018
1019     mitem = make_accel_menu_item(submenu, "_X Server Font", "<Control>G",
1020                                  ed->ag);
1021     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1022                             G_CALLBACK(guifile_import_xserver_font),
1023                             GUINT_TO_POINTER(ed->id));
1024 #endif
1025
1026     ed->file_export = gtk_menu_item_new_with_mnemonic("Ex_port");
1027     gtk_menu_shell_append(GTK_MENU_SHELL(menu), ed->file_export);
1028
1029     submenu = gtk_menu_new();
1030     gtk_menu_item_set_submenu(GTK_MENU_ITEM(ed->file_export), submenu);
1031
1032     mitem = make_accel_menu_item(submenu, "_PSF Font", "<Control>F",
1033                                  ed->ag);
1034     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1035                             G_CALLBACK(guifile_export_psf_font),
1036                             GUINT_TO_POINTER(ed->id));
1037     mitem = gtk_menu_item_new_with_mnemonic("_HEX");
1038     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1039                             G_CALLBACK(guifile_export_hex_font),
1040                             GUINT_TO_POINTER(ed->id));
1041     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1042
1043     /*
1044      * Separator.
1045      */
1046     sep = gtk_menu_item_new();
1047     gtk_widget_set_sensitive(sep, FALSE);
1048     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1049
1050 #if (GTK_MAJOR_VERSION >=2 && GTK_MINOR_VERSION >= 10)
1051     /*
1052      * Only add the Recent Fonts menu if the GTK version supports it.
1053      */
1054     mitem = gtk_menu_item_new_with_mnemonic("_Recent Fonts");
1055     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1056     gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), make_recent_menu(ed->id));
1057
1058     /*
1059      * Separator.
1060      */
1061     sep = gtk_menu_item_new();
1062     gtk_widget_set_sensitive(sep, FALSE);
1063     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1064 #endif
1065
1066     if (ed->id == 0) {
1067         mitem = make_accel_menu_item(menu, "E_xit", "<Control>F4", ed->ag);
1068
1069         (void) g_signal_connect(G_OBJECT(mitem), "activate",
1070                                 G_CALLBACK(quit_application),
1071                                 GUINT_TO_POINTER(ed->id));
1072     } else {
1073         mitem = make_accel_menu_item(menu, "Clos_e", "<Control>F4", ed->ag);
1074
1075         (void) g_signal_connect_object(G_OBJECT(mitem), "activate",
1076                                        G_CALLBACK(gtk_widget_hide),
1077                                        (gpointer) ed->shell,
1078                                        G_CONNECT_SWAPPED);
1079     }
1080
1081     gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), menu);
1082
1083     return file;
1084 }
1085
1086 static void
1087 make_xlfd_name(GtkWidget *w, gpointer data)
1088 {
1089     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1090
1091     fontgrid_make_xlfd_font_name(FONTGRID(ed->fgrid));
1092 }
1093
1094 static void
1095 update_name_from_props(GtkWidget *w, gpointer data)
1096 {
1097     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1098
1099     fontgrid_update_font_name_from_properties(FONTGRID(ed->fgrid));
1100 }
1101
1102 static void
1103 update_props_from_name(GtkWidget *w, gpointer data)
1104 {
1105     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1106
1107     fontgrid_update_properties_from_font_name(FONTGRID(ed->fgrid));
1108 }
1109
1110 static GtkWidget *
1111 make_edit_menu(gbdfed_editor_t *ed, GtkWidget *menubar)
1112 {
1113     GtkWidget *edit, *menu, *submenu, *mitem, *sep;
1114
1115     /*
1116      * Create the Edit menu.
1117      */
1118     edit = gtk_menu_item_new_with_mnemonic("_Edit");
1119
1120     ed->edit_menu = menu = gtk_menu_new();
1121     (void) g_signal_connect(G_OBJECT(menu), "map_event",
1122                             G_CALLBACK(menu_popup),
1123                             GUINT_TO_POINTER(ed->id));
1124
1125     ed->edit_copy = make_accel_menu_item(menu, "_Copy", "<Control>C", ed->ag);
1126     (void) g_signal_connect(G_OBJECT(ed->edit_copy), "activate",
1127                             G_CALLBACK(guiedit_copy_selection),
1128                             GUINT_TO_POINTER(ed->id));
1129
1130     ed->edit_cut = make_accel_menu_item(menu, "C_ut", "<Control>X", ed->ag);
1131     (void) g_signal_connect(G_OBJECT(ed->edit_cut), "activate",
1132                             G_CALLBACK(guiedit_cut_selection),
1133                             GUINT_TO_POINTER(ed->id));
1134
1135     ed->edit_paste = make_accel_menu_item(menu, "_Paste", "<Control>V",
1136                                           ed->ag);
1137     (void) g_signal_connect(G_OBJECT(ed->edit_paste), "activate",
1138                             G_CALLBACK(guiedit_paste_selection),
1139                             GUINT_TO_POINTER(ed->id));
1140
1141     ed->edit_overlay = make_accel_menu_item(menu, "_Overlay",
1142                                             "<Shift><Control>V", ed->ag);
1143     (void) g_signal_connect(G_OBJECT(ed->edit_overlay), "activate",
1144                             G_CALLBACK(guiedit_overlay_selection),
1145                             GUINT_TO_POINTER(ed->id));
1146
1147     ed->edit_insert = make_accel_menu_item(menu, "_Insert",
1148                                            "<Control><Alt>V", ed->ag);
1149     (void) g_signal_connect(G_OBJECT(ed->edit_insert), "activate",
1150                             G_CALLBACK(guiedit_insert_selection),
1151                             GUINT_TO_POINTER(ed->id));
1152
1153     /*
1154      * Separator.
1155      */
1156     sep = gtk_menu_item_new();
1157     gtk_widget_set_sensitive(sep, FALSE);
1158     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1159
1160     mitem = make_accel_menu_item(menu, "P_roperties", "<Control>P", ed->ag);
1161     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1162                             G_CALLBACK(guiedit_show_font_properties),
1163                             GUINT_TO_POINTER(ed->id));
1164
1165     mitem = make_accel_menu_item(menu, "Co_mments", "<Control>M", ed->ag);
1166     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1167                             G_CALLBACK(guiedit_show_font_comments),
1168                             GUINT_TO_POINTER(ed->id));
1169
1170     mitem = make_accel_menu_item(menu, "_Font Info", "<Control>I", ed->ag);
1171     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1172                               G_CALLBACK(guiedit_show_font_info),
1173                               GUINT_TO_POINTER(ed->id));
1174     /*
1175      * Separator.
1176      */
1177     sep = gtk_menu_item_new();
1178     gtk_widget_set_sensitive(sep, FALSE);
1179     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1180
1181     /*
1182      * Create the Font Name submenu.
1183      */
1184     mitem = gtk_menu_item_new_with_mnemonic("Font _Name");
1185     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1186
1187     ed->name_submenu = submenu = gtk_menu_new();
1188     gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), submenu);
1189     (void) g_signal_connect(G_OBJECT(submenu), "map_event",
1190                             G_CALLBACK(menu_popup),
1191                             GUINT_TO_POINTER(ed->id));
1192
1193     ed->edit_make_xlfd = gtk_menu_item_new_with_mnemonic("Make _XLFD Name");
1194     (void) g_signal_connect(G_OBJECT(ed->edit_make_xlfd), "activate",
1195                             G_CALLBACK(make_xlfd_name),
1196                             GUINT_TO_POINTER(ed->id));
1197     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), ed->edit_make_xlfd);
1198
1199     mitem = gtk_menu_item_new_with_mnemonic("Update _Name From Properties");
1200     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1201                             G_CALLBACK(update_name_from_props),
1202                             GUINT_TO_POINTER(ed->id));
1203     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1204
1205     mitem = gtk_menu_item_new_with_mnemonic("Update _Properties From Name");
1206     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1207                             G_CALLBACK(update_props_from_name),
1208                             GUINT_TO_POINTER(ed->id));
1209     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1210     mitem = gtk_menu_item_new_with_mnemonic("Update _Average Width");
1211     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1212
1213     /*
1214      * Separator.
1215      */
1216     sep = gtk_menu_item_new();
1217     gtk_widget_set_sensitive(sep, FALSE);
1218     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1219
1220     /*
1221      * Make the glyph naming menus and submenus.
1222      */
1223     ed->edit_rename_glyphs = gtk_menu_item_new_with_mnemonic("Ren_ame Glyphs");
1224     gtk_menu_shell_append(GTK_MENU_SHELL(menu), ed->edit_rename_glyphs);
1225
1226     ed->edit_rename_menu = submenu = gtk_menu_new();
1227     (void) g_signal_connect(G_OBJECT(submenu), "map_event",
1228                             G_CALLBACK(menu_popup),
1229                             GUINT_TO_POINTER(ed->id));
1230     gtk_menu_item_set_submenu(GTK_MENU_ITEM(ed->edit_rename_glyphs), submenu);
1231
1232     ed->edit_unicode_names = gtk_menu_item_new_with_mnemonic("_Unicode Names");
1233     (void) g_signal_connect(G_OBJECT(ed->edit_unicode_names), "activate",
1234                             G_CALLBACK(guiedit_set_unicode_glyph_names),
1235                             GUINT_TO_POINTER(ed->id));
1236     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), ed->edit_unicode_names);
1237
1238     ed->edit_adobe_names = gtk_menu_item_new_with_mnemonic("_Adobe Names");
1239     (void) g_signal_connect(G_OBJECT(ed->edit_adobe_names), "activate",
1240                             G_CALLBACK(guiedit_set_adobe_glyph_names),
1241                             GUINT_TO_POINTER(ed->id));
1242     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), ed->edit_adobe_names);
1243
1244     mitem = gtk_menu_item_new_with_mnemonic("_Hexadecimal Values");
1245     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1246     submenu = gtk_menu_new();
1247     gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), submenu);
1248
1249     mitem = gtk_menu_item_new_with_mnemonic("_uniXXXX");
1250     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1251                             G_CALLBACK(guiedit_set_uni_glyph_names),
1252                             GUINT_TO_POINTER(ed->id));
1253     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1254
1255     mitem = gtk_menu_item_new_with_mnemonic("0_xXXXX");
1256     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1257                             G_CALLBACK(guiedit_set_zerox_glyph_names),
1258                             GUINT_TO_POINTER(ed->id));
1259     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1260
1261     mitem = gtk_menu_item_new_with_mnemonic("U_+XXXX");
1262     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1263                             G_CALLBACK(guiedit_set_uplus_glyph_names),
1264                             GUINT_TO_POINTER(ed->id));
1265     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1266
1267     mitem = gtk_menu_item_new_with_mnemonic("_\\uXXXX");
1268     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1269                             G_CALLBACK(guiedit_set_bslashu_glyph_names),
1270                             GUINT_TO_POINTER(ed->id));
1271     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1272
1273     ed->edit_test_glyphs = make_accel_menu_item(menu, "_Test Glyphs",
1274                                                 "<Control>Z", ed->ag);
1275     (void) g_signal_connect(G_OBJECT(ed->edit_test_glyphs), "activate",
1276                             G_CALLBACK(guiedit_show_glyphtest),
1277                             GUINT_TO_POINTER(ed->id));
1278
1279     /*
1280      * Separator.
1281      */
1282     sep = gtk_menu_item_new();
1283     gtk_widget_set_sensitive(sep, FALSE);
1284     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1285
1286     mitem = make_accel_menu_item(menu, "Pr_eferences", "<Control>T", ed->ag);
1287     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1288                             G_CALLBACK(guiedit_show_preferences), 0);
1289
1290     gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit), menu);
1291
1292     return edit;
1293 }
1294
1295 static GtkWidget *
1296 make_view_menu(gbdfed_editor_t *ed, GtkWidget *menubar)
1297 {
1298     GtkWidget *view, *menu, *submenu, *mitem, *sep;
1299     GSList *group;
1300     GtkRadioMenuItem *ri;
1301
1302     /*
1303      * Create the View menu.
1304      */
1305     view = gtk_menu_item_new_with_mnemonic("_View");
1306
1307     ed->view_menu = menu = gtk_menu_new();
1308     (void) g_signal_connect(G_OBJECT(menu), "map_event",
1309                             G_CALLBACK(menu_popup),
1310                             GUINT_TO_POINTER(ed->id));
1311
1312     ed->view_unencoded = mitem =
1313         make_accel_menu_item(menu, "Unencoded", "<Control>E", ed->ag);
1314     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1315                             G_CALLBACK(toggle_encoding_view),
1316                             GUINT_TO_POINTER(ed->id));
1317
1318     /*
1319      * Create the Code Base submenu.
1320      */
1321     mitem = gtk_menu_item_new_with_mnemonic("_Code Base");
1322     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1323
1324     submenu = gtk_menu_new();
1325     gtk_menu_item_set_submenu(GTK_MENU_ITEM(mitem), submenu);
1326
1327     ed->view_oct = mitem = gtk_radio_menu_item_new_with_mnemonic(0, "_Octal");
1328     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1329     ri = GTK_RADIO_MENU_ITEM(mitem);
1330     if (options.code_base == 8)
1331       gtk_check_menu_item_set_active(&ri->check_menu_item, TRUE);
1332
1333     group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem));
1334     ed->view_dec = mitem =
1335         gtk_radio_menu_item_new_with_mnemonic(group, "_Decimal");
1336     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1337     ri = GTK_RADIO_MENU_ITEM(mitem);
1338     if (options.code_base == 10)
1339       gtk_check_menu_item_set_active(&ri->check_menu_item, TRUE);
1340
1341     group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(mitem));
1342     ed->view_hex = mitem =
1343         gtk_radio_menu_item_new_with_mnemonic(group, "_Hexadecimal");
1344     gtk_menu_shell_append(GTK_MENU_SHELL(submenu), mitem);
1345     ri = GTK_RADIO_MENU_ITEM(mitem);
1346     if (options.code_base == 16)
1347       gtk_check_menu_item_set_active(&ri->check_menu_item, TRUE);
1348
1349     /*
1350      * Add the code base toggle handler to the three toggles.
1351      */
1352     (void) g_signal_connect(G_OBJECT(ed->view_oct), "toggled",
1353                             G_CALLBACK(set_code_base),
1354                             GUINT_TO_POINTER(ed->id));
1355     (void) g_signal_connect(G_OBJECT(ed->view_dec), "toggled",
1356                             G_CALLBACK(set_code_base),
1357                             GUINT_TO_POINTER(ed->id));
1358     (void) g_signal_connect(G_OBJECT(ed->view_hex), "toggled",
1359                             G_CALLBACK(set_code_base),
1360                             GUINT_TO_POINTER(ed->id));
1361
1362     /*
1363      * Separator.
1364      */
1365     sep = gtk_menu_item_new();
1366     gtk_widget_set_sensitive(sep, FALSE);
1367     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1368
1369     mitem = make_accel_menu_item(menu, "_Other Page", "<Shift><Control>S",
1370                                  ed->ag);
1371     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1372                             G_CALLBACK(goto_other_page),
1373                             GUINT_TO_POINTER(ed->id));
1374
1375     if (options.orientation == GTK_ORIENTATION_VERTICAL)
1376       ed->view_orientation = mitem =
1377           make_accel_menu_item(menu, "Horizontal View", "<Control>Q", ed->ag);
1378     else
1379       ed->view_orientation = mitem =
1380           make_accel_menu_item(menu, "Vertical View", "<Control>Q", ed->ag);
1381     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1382                             G_CALLBACK(toggle_view_orientation),
1383                             GUINT_TO_POINTER(ed->id));
1384
1385     /*
1386      * Separator.
1387      */
1388     sep = gtk_menu_item_new();
1389     gtk_widget_set_sensitive(sep, FALSE);
1390     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1391
1392     /*
1393      * Messages dialog.
1394      */
1395     ed->view_messages = mitem =
1396         make_accel_menu_item(menu, "_Messages", "<Control>A", ed->ag);
1397     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1398                             G_CALLBACK(view_font_messages),
1399                             GUINT_TO_POINTER(ed->id));
1400
1401     gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), menu);
1402
1403     return view;
1404 }
1405
1406 static GtkWidget *
1407 make_ops_menu(gbdfed_editor_t *ed, GtkWidget *menubar)
1408 {
1409     GtkWidget *ops, *menu, *mitem;
1410
1411     /*
1412      * Create the Edit menu.
1413      */
1414     ops = gtk_menu_item_new_with_mnemonic("_Operations");
1415
1416     ed->ops_menu = menu = gtk_menu_new();
1417     (void) g_signal_connect(G_OBJECT(menu), "map_event",
1418                             G_CALLBACK(menu_popup),
1419                             GUINT_TO_POINTER(ed->id));
1420
1421     mitem = make_accel_menu_item(menu, "_Translate Glyphs", "<Control>D",
1422                                  ed->ag);
1423     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1424                             G_CALLBACK(guiops_show_translate),
1425                             GUINT_TO_POINTER(ed->id));
1426
1427     mitem = make_accel_menu_item(menu, "_Rotate Glyphs", "<Control>R",
1428                                  ed->ag);
1429     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1430                             G_CALLBACK(guiops_show_rotate),
1431                             GUINT_TO_POINTER(ed->id));
1432
1433     mitem = make_accel_menu_item(menu, "_Shear Glyphs", "<Control>J",
1434                                  ed->ag);
1435     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1436                             G_CALLBACK(guiops_show_shear),
1437                             GUINT_TO_POINTER(ed->id));
1438
1439     mitem = make_accel_menu_item(menu, "_Embolden Glyphs", "<Shift><Control>B",
1440                                  ed->ag);
1441     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1442                             G_CALLBACK(guiops_show_embolden),
1443                             GUINT_TO_POINTER(ed->id));
1444
1445     gtk_menu_item_set_submenu(GTK_MENU_ITEM(ops), menu);
1446
1447     return ops;
1448 }
1449
1450 static GtkWidget *
1451 make_windows_menu(gbdfed_editor_t *ed, GtkWidget *menubar)
1452 {
1453     GtkWidget *win, *menu, *mitem;
1454     guint i;
1455
1456     win = gtk_menu_item_new_with_mnemonic("_Windows");
1457
1458     ed->win_menu = menu = gtk_menu_new();
1459     (void) g_signal_connect(G_OBJECT(menu), "map_event",
1460                             G_CALLBACK(menu_popup),
1461                             GUINT_TO_POINTER(ed->id));
1462
1463     for (i = 0; i < num_editors; i++) {
1464         if (editors[i].file == 0)
1465           sprintf(buffer1, "(unnamed%d)", editors[i].id);
1466         else
1467           strcpy(buffer1, editors[i].file);
1468
1469         ed->win_menu_item = mitem = gtk_menu_item_new_with_label(buffer1);
1470         (void) g_signal_connect(G_OBJECT(mitem), "activate",
1471                                 G_CALLBACK(show_editor),
1472                                 GUINT_TO_POINTER(ed->id));
1473         gtk_menu_shell_append(GTK_MENU_SHELL(ed->win_menu), mitem);
1474     }
1475
1476     gtk_menu_item_set_submenu(GTK_MENU_ITEM(win), menu);
1477
1478     return win;
1479 }
1480
1481 static GtkWidget *
1482 make_help_menu(gbdfed_editor_t *ed, GtkWidget *menubar)
1483 {
1484     GtkWidget *help, *menu, *mitem, *sep;
1485
1486     /*
1487      * Create the Edit menu.
1488      */
1489     help = gtk_menu_item_new_with_mnemonic("_Help");
1490     gtk_menu_item_set_right_justified(GTK_MENU_ITEM(help), TRUE);
1491
1492     menu = gtk_menu_new();
1493
1494     mitem = gtk_menu_item_new_with_mnemonic("The _Program");
1495     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1496     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1497                             G_CALLBACK(guihelp_show_help),
1498                             GINT_TO_POINTER(GUIHELP_PROGRAM));
1499
1500     mitem = gtk_menu_item_new_with_mnemonic("_Font Grid");
1501     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1502     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1503                             G_CALLBACK(guihelp_show_help),
1504                             GINT_TO_POINTER(GUIHELP_FONTGRID));
1505
1506     mitem = gtk_menu_item_new_with_mnemonic("_Glyph Editor");
1507     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1508     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1509                             G_CALLBACK(guihelp_show_help),
1510                             GINT_TO_POINTER(GUIHELP_GLYPH_EDITOR));
1511
1512     mitem = gtk_menu_item_new_with_mnemonic("_Configuration File");
1513     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1514     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1515                             G_CALLBACK(guihelp_show_help),
1516                             GINT_TO_POINTER(GUIHELP_CONFIG_FILE));
1517
1518     mitem = gtk_menu_item_new_with_mnemonic("P_references Dialog");
1519     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1520     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1521                             G_CALLBACK(guihelp_show_help),
1522                             GINT_TO_POINTER(GUIHELP_PREFERENCES));
1523
1524     /*
1525      * Separator.
1526      */
1527     sep = gtk_menu_item_new();
1528     gtk_widget_set_sensitive(sep, FALSE);
1529     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1530
1531     mitem = gtk_menu_item_new_with_mnemonic("_Windows Font Notes");
1532     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1533     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1534                             G_CALLBACK(guihelp_show_help),
1535                             GINT_TO_POINTER(GUIHELP_FNT));
1536
1537     mitem = gtk_menu_item_new_with_mnemonic("_OpenType Font Notes");
1538     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1539     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1540                             G_CALLBACK(guihelp_show_help),
1541                             GINT_TO_POINTER(GUIHELP_OTF));
1542
1543     mitem = gtk_menu_item_new_with_mnemonic("P_SF Font Notes");
1544     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1545     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1546                             G_CALLBACK(guihelp_show_help),
1547                             GINT_TO_POINTER(GUIHELP_PSF));
1548
1549     mitem = gtk_menu_item_new_with_mnemonic("_HEX Font Notes");
1550     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1551     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1552                             G_CALLBACK(guihelp_show_help),
1553                             GINT_TO_POINTER(GUIHELP_HEX));
1554
1555     /*
1556      * Separator.
1557      */
1558     sep = gtk_menu_item_new();
1559     gtk_widget_set_sensitive(sep, FALSE);
1560     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1561
1562     mitem = gtk_menu_item_new_with_mnemonic("C_olor Notes");
1563     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1564     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1565                             G_CALLBACK(guihelp_show_help),
1566                             GINT_TO_POINTER(GUIHELP_COLOR));
1567
1568     /*
1569      * Separator.
1570      */
1571     sep = gtk_menu_item_new();
1572     gtk_widget_set_sensitive(sep, FALSE);
1573     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1574
1575     mitem = gtk_menu_item_new_with_mnemonic("T_ips");
1576     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1577     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1578                             G_CALLBACK(guihelp_show_help),
1579                             GINT_TO_POINTER(GUIHELP_TIPS));
1580
1581     /*
1582      * Separator.
1583      */
1584     sep = gtk_menu_item_new();
1585     gtk_widget_set_sensitive(sep, FALSE);
1586     gtk_menu_shell_append(GTK_MENU_SHELL(menu), sep);
1587
1588     sprintf(buffer1, "_About %s", g_get_prgname());
1589     mitem = gtk_menu_item_new_with_mnemonic(buffer1);
1590     gtk_menu_shell_append(GTK_MENU_SHELL(menu), mitem);
1591     (void) g_signal_connect(G_OBJECT(mitem), "activate",
1592                             G_CALLBACK(guihelp_show_help),
1593                             GINT_TO_POINTER(GUIHELP_ABOUT));
1594
1595     gtk_menu_item_set_submenu(GTK_MENU_ITEM(help), menu);
1596
1597     return help;
1598 }
1599
1600 #define UPDMSG "Font Name: XLFD name has been modified.\nDo you want to update the font properties from the name?"
1601
1602 static void
1603 update_font_name(GtkWidget *w, gpointer data)
1604 {
1605     gbdfed_editor_t *ed = editors + GPOINTER_TO_UINT(data);
1606     bdf_font_t *font;
1607     gchar *name;
1608
1609     name = (gchar *) gtk_entry_get_text(GTK_ENTRY(ed->fontname));
1610
1611     font = fontgrid_get_font(FONTGRID(ed->fgrid));
1612     if (font && strcmp(name, font->name) == 0)
1613       /*
1614        * There was no actual change to the name.
1615        */
1616       return;
1617
1618     fontgrid_set_font_name(FONTGRID(ed->fgrid), name);
1619
1620     /*
1621      * If the new name is an XLFD name, then offer to update the
1622      * font properties from the name.
1623      */
1624     if (font && bdf_has_xlfd_name(font)) {
1625         if (guiutil_yes_or_no(ed->shell, UPDMSG, TRUE)) {
1626             fontgrid_update_properties_from_font_name(FONTGRID(ed->fgrid));
1627
1628             /*
1629              * If the font info dialog is up, make sure it is updated with
1630              * the font property changes.
1631              */
1632             guiedit_update_font_properties(ed);
1633         }
1634     }
1635 }
1636
1637 guint
1638 gbdfed_make_editor(gchar *filename, gboolean cmdline)
1639 {
1640     FILE *in;
1641     GtkWidget *mb, *mitem, *table;
1642     GtkWidget *vbox, *hbox, *bbox, *frame;
1643     gbdfed_editor_t *ed;
1644     bdf_font_t *font;
1645     gchar *path;
1646     GList *icon_list = 0;
1647     FontgridPageInfo pageinfo;
1648
1649     font = 0;
1650
1651     /*
1652      * Attempt to load the specified font before doing anything else.
1653      */
1654     if (filename != 0) {
1655         /*
1656          * Change code to put up an error dialog if the font won't load.
1657          */
1658         if ((in = fopen(filename, "r")) == 0) {
1659             fprintf(stderr, "%s: unable to open BDF font '%s'.\n",
1660                     g_get_prgname(), filename);
1661             if (num_editors > 0 && !cmdline)
1662               return ~0;
1663             filename = 0;
1664         } else {
1665             font = bdf_load_font(in, &options.font_opts, 0, 0);
1666             fclose(in);
1667             if (font == 0)
1668               fprintf(stderr, "%s: problem loading BDF font '%s'.\n",
1669                       g_get_prgname(), filename);
1670         }
1671     }
1672
1673     /*
1674      * Create the icon list if it hasn't already been created.
1675      */
1676     if (icons_set == FALSE) {
1677         /*
1678          * Create the 16x16 icon.
1679          */
1680         icon_list = g_list_append(icon_list,
1681                                   gdk_pixbuf_new_from_xpm_data(gbdfed_48x48));
1682         icon_list = g_list_append(icon_list,
1683                                   gdk_pixbuf_new_from_xpm_data(gbdfed_32x32));
1684         icon_list = g_list_append(icon_list,
1685                                   gdk_pixbuf_new_from_xpm_data(gbdfed_16x16));
1686
1687         gtk_window_set_default_icon_list(icon_list);
1688
1689         icons_set = TRUE;
1690     }
1691
1692     /*
1693      * Create a new editor structure.
1694      */
1695     if (num_editors == 0)
1696       editors = g_malloc(sizeof(gbdfed_editor_t));
1697     else
1698       editors = g_realloc(editors,
1699                           sizeof(gbdfed_editor_t) * (num_editors + 1));
1700
1701     ed = editors + num_editors;
1702     (void) memset(ed, 0, sizeof(gbdfed_editor_t));
1703     ed->id = num_editors++;
1704
1705     /*
1706      * Construct the path and filename from the one passed.  This makes copies
1707      * of the strings.
1708      */
1709     if (font != 0 && filename != 0) {
1710         if (filename[0] != G_DIR_SEPARATOR) {
1711             path = g_get_current_dir();
1712             sprintf(buffer1, "%s%c%s", path, G_DIR_SEPARATOR, filename);
1713             g_free(path);
1714         } else
1715           strcpy(buffer1, filename);
1716
1717         ed->file = g_path_get_basename(buffer1);
1718         ed->path = g_path_get_dirname(buffer1);
1719     }
1720
1721     /*
1722      * Create the top level window for the editor.
1723      */
1724     ed->shell = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1725
1726     /*
1727      * This is a bit risky, but it allows the shell to shrink to fit new
1728      * fonts when they are added.
1729      */
1730     gtk_window_set_resizable(GTK_WINDOW(ed->shell), TRUE);
1731
1732     if (ed->id == 0) {
1733         (void) g_signal_connect(G_OBJECT(ed->shell), "destroy_event",
1734                                 G_CALLBACK(quit_application),
1735                                 GUINT_TO_POINTER(ed->id));
1736         (void) g_signal_connect(G_OBJECT(ed->shell), "delete_event",
1737                                 G_CALLBACK(quit_application),
1738                                 GUINT_TO_POINTER(ed->id));
1739     } else {
1740         (void) g_signal_connect(G_OBJECT(ed->shell), "destroy_event",
1741                                 G_CALLBACK(gtk_widget_hide), 0);
1742         (void) g_signal_connect(G_OBJECT(ed->shell), "delete_event",
1743                                 G_CALLBACK(gtk_widget_hide), 0);
1744     }
1745
1746     /*
1747      * Determine the name for the window.
1748      */
1749     if (filename == 0)
1750       sprintf(buffer1, "%s - (unnamed%d)", g_get_prgname(), ed->id);
1751     else {
1752         if (font && font->modified)
1753           sprintf(buffer1, "%s - %s [modified]", g_get_prgname(), ed->file);
1754         else
1755           sprintf(buffer1, "%s - %s", g_get_prgname(), ed->file);
1756     }
1757     gtk_window_set_title(GTK_WINDOW(ed->shell), buffer1);
1758
1759     /*
1760      * Create the vertical box that will contain the widgets.
1761      */
1762     table = gtk_table_new(5, 1, FALSE);
1763     gtk_container_add(GTK_CONTAINER(ed->shell), table);
1764
1765     ed->ag = gtk_accel_group_new();
1766
1767     mb = gtk_menu_bar_new();
1768     gtk_table_attach(GTK_TABLE(table), mb, 0, 1, 0, 1, GTK_FILL, GTK_FILL,
1769                      0, 0);
1770
1771     /*
1772      * Create the File menu.
1773      */
1774     mitem = make_file_menu(ed, mb);
1775     gtk_menu_shell_append(GTK_MENU_SHELL(mb), mitem);
1776
1777     /*
1778      * Create the Edit menu.
1779      */
1780     mitem = make_edit_menu(ed, mb);
1781     gtk_menu_shell_append(GTK_MENU_SHELL(mb), mitem);
1782
1783     /*
1784      * Create the View menu.
1785      */
1786     mitem = make_view_menu(ed, mb);
1787     gtk_menu_shell_append(GTK_MENU_SHELL(mb), mitem);
1788
1789     /*
1790      * Create the Operations menu.
1791      */
1792     mitem = make_ops_menu(ed, mb);
1793     gtk_menu_shell_append(GTK_MENU_SHELL(mb), mitem);
1794
1795     /*
1796      * Create the Windows menu.
1797      */
1798     mitem = make_windows_menu(ed, mb);
1799     gtk_menu_shell_append(GTK_MENU_SHELL(mb), mitem);
1800
1801     /*
1802      * Create the Help menu.
1803      */
1804     mitem = make_help_menu(ed, mb);
1805     gtk_menu_shell_append(GTK_MENU_SHELL(mb), mitem);
1806
1807     /*
1808      * Attach the accelerators to the editor.
1809      */
1810     gtk_window_add_accel_group(GTK_WINDOW(ed->shell), ed->ag);
1811
1812     /*
1813      * 1. Add the font name widget.
1814      */
1815     frame = gtk_frame_new(0);
1816     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
1817     gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 1, 2, GTK_FILL, GTK_FILL,
1818                      0, 0);
1819
1820     ed->fontname = gtk_widget_new(gtk_entry_get_type(),
1821                                   "max_length", 128, NULL);
1822     mitem = labcon_new_label_defaults("Font:", ed->fontname, 0);
1823     gtk_container_add(GTK_CONTAINER(frame), mitem);
1824     g_signal_connect(G_OBJECT(ed->fontname), "activate",
1825                      G_CALLBACK(update_font_name), GUINT_TO_POINTER(ed->id));
1826
1827     /*
1828      * 2. Add the glyph information widgets.
1829      */
1830     frame = gtk_frame_new(0);
1831     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
1832     gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 2, 3, GTK_FILL, GTK_FILL,
1833                      0, 0);
1834
1835     vbox = gtk_vbox_new(TRUE, 0);
1836     ed->charinfo = gtk_label_new("\"None\" (0000) (00,00)");
1837     ed->metrics = gtk_label_new("ascent 0 descent 0 right 0 left 0");
1838     gtk_misc_set_alignment(GTK_MISC(ed->charinfo), 0.0, 0.5);
1839     gtk_misc_set_alignment(GTK_MISC(ed->metrics), 0.0, 0.5);
1840     gtk_box_pack_start(GTK_BOX(vbox), ed->charinfo, TRUE, TRUE, 0);
1841     gtk_box_pack_start(GTK_BOX(vbox), ed->metrics, TRUE, TRUE, 0);
1842
1843     mitem = labcon_new_label_defaults("Glyph:", vbox, mitem);
1844     gtk_container_add(GTK_CONTAINER(frame), mitem);
1845
1846     frame = gtk_frame_new(0);
1847     gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
1848     gtk_table_attach(GTK_TABLE(table), frame, 0, 1, 3, 4, GTK_FILL, GTK_FILL,
1849                      0, 0);
1850
1851     hbox = gtk_hbox_new(FALSE, 2);
1852
1853     bbox = gtk_hbox_new(FALSE, 0);
1854
1855     ed->first = gtk_button_new_with_label("First Page");
1856     (void) g_signal_connect(G_OBJECT(ed->first), "released",
1857                             G_CALLBACK(first_page),
1858                             GUINT_TO_POINTER(ed->id));
1859
1860     ed->prev = gtk_button_new_with_label("Previous Page");
1861     (void) g_signal_connect(G_OBJECT(ed->prev), "released",
1862                             G_CALLBACK(previous_page),
1863                             GUINT_TO_POINTER(ed->id));
1864
1865     ed->next = gtk_button_new_with_label("Next Page");
1866     (void) g_signal_connect(G_OBJECT(ed->next), "released",
1867                             G_CALLBACK(next_page),
1868                             GUINT_TO_POINTER(ed->id));
1869
1870     ed->last = gtk_button_new_with_label("Last Page");
1871     (void) g_signal_connect(G_OBJECT(ed->last), "released",
1872                             G_CALLBACK(last_page),
1873                             GUINT_TO_POINTER(ed->id));
1874
1875     gtk_box_pack_start(GTK_BOX(bbox), ed->first, FALSE, FALSE, 0);
1876     gtk_box_pack_start(GTK_BOX(bbox), ed->prev, FALSE, FALSE, 0);
1877     gtk_box_pack_start(GTK_BOX(bbox), ed->next, FALSE, FALSE, 0);
1878     gtk_box_pack_start(GTK_BOX(bbox), ed->last, FALSE, FALSE, 0);
1879
1880     gtk_box_pack_start(GTK_BOX(hbox), bbox, FALSE, FALSE, 0);
1881
1882     mitem = gtk_label_new("Page:");
1883     ed->pageno = gtk_widget_new(gtk_entry_get_type(),
1884                                 "max_length", 6,
1885                                 "width-request", 70,
1886                                 NULL);
1887     (void) g_signal_connect(G_OBJECT(ed->pageno), "activate",
1888                             G_CALLBACK(goto_page_or_code),
1889                             GUINT_TO_POINTER(ed->id));
1890
1891     gtk_box_pack_start(GTK_BOX(hbox), mitem, FALSE, FALSE, 0);
1892     gtk_box_pack_start(GTK_BOX(hbox), ed->pageno, FALSE, FALSE, 0);
1893
1894     mitem = gtk_label_new("Code:");
1895     ed->charno = gtk_widget_new(gtk_entry_get_type(),
1896                                 "max_length", 6,
1897                                 "width-request", 70,
1898                                 NULL);
1899     (void) g_signal_connect(G_OBJECT(ed->charno), "activate",
1900                             G_CALLBACK(goto_page_or_code),
1901                             GUINT_TO_POINTER(ed->id));
1902
1903     gtk_box_pack_start(GTK_BOX(hbox), mitem, FALSE, FALSE, 0);
1904     gtk_box_pack_start(GTK_BOX(hbox), ed->charno, FALSE, FALSE, 0);
1905
1906     gtk_container_add(GTK_CONTAINER(frame), hbox);
1907
1908     /*
1909      * Now add the font grid itself.
1910      */
1911     ed->fgrid = fontgrid_newv(font,
1912                               options.font_opts.point_size,
1913                               options.font_opts.font_spacing,
1914                               options.no_blanks,
1915                               options.overwrite_mode,
1916                               options.power2,
1917                               options.colors,
1918                               options.initial_glyph,
1919                               options.code_base,
1920                               options.orientation,
1921                               options.font_opts.bits_per_pixel,
1922                               options.font_opts.resolution_x,
1923                               options.font_opts.resolution_y,
1924                               &pageinfo);
1925     (void) g_signal_connect(G_OBJECT(ed->fgrid), "turn_to_page",
1926                             G_CALLBACK(page_change),
1927                             GUINT_TO_POINTER(ed->id));
1928     (void) g_signal_connect(G_OBJECT(ed->fgrid), "selection-start",
1929                             G_CALLBACK(update_selection_info),
1930                             GUINT_TO_POINTER(ed->id));
1931     (void) g_signal_connect(G_OBJECT(ed->fgrid), "selection-extend",
1932                             G_CALLBACK(update_selection_info),
1933                             GUINT_TO_POINTER(ed->id));
1934     (void) g_signal_connect(G_OBJECT(ed->fgrid), "selection-end",
1935                             G_CALLBACK(update_selection_info),
1936                             GUINT_TO_POINTER(ed->id));
1937     (void) g_signal_connect(G_OBJECT(ed->fgrid), "activate",
1938                             G_CALLBACK(update_selection_info),
1939                             GUINT_TO_POINTER(ed->id));
1940     (void) g_signal_connect(G_OBJECT(ed->fgrid), "modified",
1941                             G_CALLBACK(handle_modified_signal),
1942                             GUINT_TO_POINTER(ed->id));
1943     gtk_table_attach(GTK_TABLE(table), ed->fgrid, 0, 1, 4, 5,
1944                      GTK_FILL|GTK_EXPAND|GTK_SHRINK,
1945                      GTK_FILL|GTK_EXPAND|GTK_SHRINK, 0, 0);
1946
1947     /*
1948      * Set up the initial page information.
1949      */
1950     page_change(ed->fgrid, &pageinfo, GUINT_TO_POINTER(ed->id));
1951
1952     /*
1953      * Show the editor if it the first one created or is not being created
1954      * from the command line.
1955      */
1956     if (ed->id == 0)
1957       gtk_widget_show_all(ed->shell);
1958
1959     {
1960         /*
1961          * Get the initial selection info to set up the glyph info labels.
1962          *
1963          * NOTE: This has to be done here because for some reason labels
1964          * do not display properly if changed before the editor is fully
1965          * realized.
1966          */
1967         FontgridSelectionInfo sinfo;
1968         if (fontgrid_has_selection(FONTGRID(ed->fgrid), &sinfo) == TRUE)
1969           update_selection_info(ed->fgrid, (gpointer) &sinfo,
1970                                 GUINT_TO_POINTER(ed->id));
1971     }
1972
1973     /*
1974      * Set the font name in the entry field if the font exists.
1975      */
1976     gtk_entry_set_text(GTK_ENTRY(ed->fontname),
1977                        fontgrid_get_font_name(FONTGRID(ed->fgrid)));
1978
1979     /*
1980      * Change the focus to the Fontgrid.
1981      */
1982     gtk_widget_grab_focus(ed->fgrid);
1983
1984     return ed->id;
1985 }
1986
1987 static int
1988 handle_unknown_options(bdf_options_t *opts, char **params,
1989                        unsigned int nparams, void *client_data)
1990 {
1991     gint idx;
1992     gbdfed_options_t *op;
1993
1994     op = (gbdfed_options_t *) client_data;
1995
1996     if (nparams == 0)
1997       return 0;
1998
1999     /*
2000      * Handle the 2 bits per pixel color list.
2001      */
2002     if (strncmp(params[0], "2bpp_grays", 10) == 0) {
2003         for (idx = 1; idx < 5; idx++)
2004           op->colors[idx] = (unsigned short) _bdf_atos(params[idx], 0, 10);
2005         return 1;
2006     }
2007
2008     /*
2009      * Handle the 4 bits per pixel color list.
2010      */
2011     if (strncmp(params[0], "4bpp_grays", 10) == 0) {
2012         for (idx = 1; idx < 17; idx++)
2013           op->colors[idx-1+4] = (unsigned short) _bdf_atos(params[idx], 0, 10);
2014         return 1;
2015     }
2016
2017     if (params[0][0] == 'a' &&
2018         strncmp(params[0], "adobe_name_file", 15) == 0) {
2019         if (op->adobe_name_file != 0)
2020           g_free(op->adobe_name_file);
2021         if (params[1] == 0 || params[1][0] == 0)
2022           op->adobe_name_file = 0;
2023         else
2024           op->adobe_name_file = g_strdup(params[1]);
2025         return 1;
2026     }
2027
2028     if (params[0][0] == 'c') {
2029         if (strncmp(params[0], "close_accelerator", 17) == 0) {
2030             if (params[0][17] == 0) {
2031                 /*
2032                  * We have the accelerator itself.  Add code to convert Xt key
2033                  * bindings to GTK.
2034                  */
2035                 if (op->accelerator != 0)
2036                   g_free(op->accelerator);
2037                 if (params[1] == 0 || params[1][0] == 0)
2038                   op->accelerator = 0;
2039                 else
2040                   op->accelerator = g_strdup(params[1]);
2041             }
2042
2043             /*
2044              * Ignore instances of 'close_accelerator_text'.  GTK+ figures this
2045              * out already.
2046              */
2047
2048             return 1;
2049         }
2050
2051         if (strncmp(params[0], "code_base", 9) == 0) {
2052             switch (params[1][0]) {
2053               case 'o': case 'O': op->code_base = 8; break;
2054               case 'd': case 'D': op->code_base = 10; break;
2055               case 'h': case 'H': op->code_base = 16; break;
2056               default: op->code_base = 16;
2057             }
2058             return 1;
2059         }
2060
2061         /*
2062          * Ignore the old grayscale specification keywords.
2063          */
2064         if (strncmp(params[0], "color", 5) == 0) {
2065             /*
2066              * Quietly ignore the old color list.
2067              */
2068             return 1;
2069         }
2070     }
2071
2072     if (params[0][0] == 'f' &&
2073         strncmp(params[0], "font_grid_horizontal", 20) == 0) {
2074         switch (params[1][0]) {
2075           case '0': case 'F': case 'f': case 'N': case 'n':
2076             op->orientation = GTK_ORIENTATION_VERTICAL;
2077             break;
2078           case '1': case 'T': case 't': case 'Y': case 'y':
2079             op->orientation = GTK_ORIENTATION_HORIZONTAL;
2080             break;
2081         }
2082         return 1;
2083     }        
2084
2085     if (params[0][0] == 'g') {
2086         if (strncmp(params[0], "grid_overwrite_mode", 19) == 0) {
2087             switch (params[1][0]) {
2088               case '0': case 'F': case 'f': case 'N': case 'n':
2089                 op->overwrite_mode = FALSE;
2090                 break;
2091               case '1': case 'T': case 't': case 'Y': case 'y':
2092                 op->overwrite_mode = TRUE;
2093                 break;
2094             }
2095             return 1;
2096         }
2097
2098         if (strncmp(params[0], "generate_sbit_metrics", 21) == 0) {
2099             switch (params[1][0]) {
2100               case '0': case 'F': case 'f': case 'N': case 'n':
2101                 op->sbit = FALSE;
2102                 break;
2103               case '1': case 'T': case 't': case 'Y': case 'y':
2104                 op->sbit = TRUE;
2105                 break;
2106             }
2107             return 1;
2108         }
2109     }
2110
2111     if (params[0][0] == 'm' && strncmp(params[0], "make_backups", 12) == 0) {
2112         switch (params[1][0]) {
2113           case '0': case 'F': case 'f': case 'N': case 'n':
2114             op->backups = FALSE;
2115             break;
2116           case '1': case 'T': case 't': case 'Y': case 'y':
2117             op->backups = TRUE;
2118             break;
2119         }
2120         return 1;
2121     }
2122
2123     if ((params[0][0] == 'n' && strncmp(params[0], "name_file", 9) == 0) ||
2124         (params[0][0] == 'u' &&
2125          strncmp(params[0], "unicode_name_file", 17) == 0)) {
2126         if (op->unicode_name_file != 0)
2127           g_free(op->unicode_name_file);
2128         if (params[1] == 0 || params[1][0] == 0)
2129           op->unicode_name_file = 0;
2130         else
2131           op->unicode_name_file = g_strdup(params[1]);
2132         return 1;
2133     }
2134
2135     if (params[0][0] == 'o' && strncmp(params[0], "orientation", 11) == 0) {
2136         switch (params[1][0]) {
2137           case 'H': case 'h':
2138             op->orientation = GTK_ORIENTATION_HORIZONTAL;
2139             break;
2140           case 'V': case 'v':
2141             op->orientation = GTK_ORIENTATION_VERTICAL;
2142             break;
2143         }
2144         return 1;
2145     }
2146
2147     if (params[0][0] == 'p') {
2148         if (strncmp(params[0], "pixel_size", 10) == 0) {
2149             op->pixel_size = _bdf_atoul(params[1], 0, 10);
2150             if (op->pixel_size < 2)
2151               op->pixel_size = 2;
2152             else if (op->pixel_size > 20)
2153               op->pixel_size = 20;
2154             return 1;
2155         }
2156
2157         if (strncmp(params[0], "power2", 6) == 0) {
2158             switch (params[1][0]) {
2159               case '0': case 'F': case 'f': case 'N': case 'n':
2160                 op->power2 = FALSE;
2161                 break;
2162               case '1': case 'T': case 't': case 'Y': case 'y':
2163                 op->power2 = TRUE;
2164                 break;
2165             }
2166             return 1;
2167         }
2168
2169         if (strncmp(params[0], "percentage_only", 15) == 0)
2170           /*
2171            * Ignore this option.  No longer needed.
2172            */
2173           return 1;
2174
2175         if (strncmp(params[0], "progress_bar", 12) == 0)
2176           /*
2177            * The progress bar is no longer being used as of version 5.0.
2178            */
2179           return 1;
2180     }
2181
2182     if (params[0][0] == 'r') {
2183         if (strncmp(params[0], "resolution", 10) == 0) {
2184             op->resolution = _bdf_atoul(params[1], 0, 10);
2185             return 1;
2186         }
2187
2188         if (strncmp(params[0], "really_exit", 11) == 0) {
2189             switch (params[1][0]) {
2190               case '0': case 'F': case 'f': case 'N': case 'n':
2191                 op->really_exit = FALSE;
2192                 break;
2193               case '1': case 'T': case 't': case 'Y': case 'y':
2194                 op->really_exit = TRUE;
2195                 break;
2196             }
2197             return 1;
2198         }
2199     }
2200
2201     if (params[0][0] == 's') {
2202         if (strncmp(params[0], "skip_blank_pages", 16) == 0) {
2203             switch (params[1][0]) {
2204               case '0': case 'F': case 'f': case 'N': case 'n':
2205                 op->no_blanks = FALSE;
2206                 break;
2207               case '1': case 'T': case 't': case 'Y': case 'y':
2208                 op->no_blanks = TRUE;
2209                 break;
2210             }
2211             return 1;
2212         }
2213
2214         if (strncmp(params[0], "show_cap_height", 15) == 0) {
2215             switch (params[1][0]) {
2216               case '0': case 'F': case 'f': case 'N': case 'n':
2217                 op->show_cap_height = FALSE;
2218                 break;
2219               case '1': case 'T': case 't': case 'Y': case 'y':
2220                 op->show_cap_height = TRUE;
2221                 break;
2222             }
2223             return 1;
2224         }
2225
2226         if (strncmp(params[0], "show_x_height", 13) == 0) {
2227             switch (params[1][0]) {
2228               case '0': case 'F': case 'f': case 'N': case 'n':
2229                 op->show_x_height = FALSE;
2230                 break;
2231               case '1': case 'T': case 't': case 'Y': case 'y':
2232                 op->show_x_height = TRUE;
2233                 break;
2234             }
2235             return 1;
2236         }
2237     }
2238
2239     return 0;
2240 }
2241
2242 static void
2243 usage(void)
2244 {
2245     fprintf(stderr, "Usage: %s [font1.bdf .....]\n", g_get_prgname());
2246     exit(1);
2247 }
2248
2249 static void
2250 editor_setup(int argc, char *argv[])
2251 {
2252     int base = 0;
2253     gchar *ap;
2254     FILE *in;
2255     gboolean need_editor;
2256     GdkScreen *screen;
2257
2258     /*
2259      * Get the default BDF options.
2260      */
2261     bdf_default_options(&options.font_opts);
2262
2263     options.accelerator = options.accelerator_text =
2264         options.unicode_name_file = options.adobe_name_file = 0;
2265     options.pixel_size = 10;
2266     options.resolution = 0;
2267     options.no_blanks = options.really_exit = 
2268         options.overwrite_mode = options.power2 =
2269         options.backups = TRUE;
2270     options.show_cap_height = options.show_x_height =
2271         options.sbit = options.gbdfed_opts = FALSE;
2272     options.initial_glyph = -1;
2273     options.code_base = 16;
2274
2275     options.orientation = GTK_ORIENTATION_HORIZONTAL;
2276
2277     /*
2278      * Set the default colors for 2 bits per pixel.
2279      */
2280     options.colors[0] = 0;
2281     options.colors[1] = 175;
2282     options.colors[2] = 207;
2283     options.colors[3] = 239;
2284
2285     /*
2286      * Set the default colors for 4 bits per pixel.
2287      */
2288     options.colors[4] = 0;
2289     options.colors[5] = 31;
2290     options.colors[6] = 63;
2291     options.colors[7] = 95;
2292     options.colors[8] = 127;
2293     options.colors[9] = 159;
2294     options.colors[10] = 167;
2295     options.colors[11] = 175;
2296     options.colors[12] = 183;
2297     options.colors[13] = 191;
2298     options.colors[14] = 199;
2299     options.colors[15] = 207;
2300     options.colors[16] = 215;
2301     options.colors[17] = 223;
2302     options.colors[18] = 231;
2303     options.colors[19] = 239;
2304
2305     /*
2306      * Attempt to load the user config file.
2307      */
2308     if ((ap = getenv("HOME")) != 0) {
2309         sprintf(buffer1, "%s/.gbdfedrc", ap);
2310         if ((in = fopen(buffer1, "r")) != 0) {
2311             bdf_load_options(in, &options.font_opts, handle_unknown_options,
2312                              (void *) &options);
2313             fclose(in);
2314         } else {
2315             /*
2316              * Try reading the older ".xmbdfedrc".
2317              */
2318             sprintf(buffer1, "%s/.xmbdfedrc", ap);
2319             if ((in = fopen(buffer1, "r")) != 0) {
2320                 bdf_load_options(in, &options.font_opts,
2321                                  handle_unknown_options, (void *) &options);
2322                 fclose(in);
2323             }
2324         }
2325     }
2326
2327     /*
2328      * Determine the horizontal and vertical resolutions if they have not been
2329      * set on the command line or from the config file.
2330      */
2331     if (options.resolution != 0)
2332       options.font_opts.resolution_x = options.font_opts.resolution_y =
2333           options.resolution;
2334
2335     screen = gdk_drawable_get_screen(GDK_DRAWABLE(gdk_get_default_root_window()));
2336     if (options.font_opts.resolution_x == 0)
2337       options.font_opts.resolution_x =
2338           (unsigned int) ((((double) gdk_screen_get_width(screen)) * 25.4) /
2339                            ((double) gdk_screen_get_width_mm(screen)) + 0.5);
2340
2341     if (options.font_opts.resolution_y == 0)
2342       options.font_opts.resolution_y =
2343           (unsigned int) ((((double) gdk_screen_get_height(screen)) * 25.4) /
2344                            ((double) gdk_screen_get_height_mm(screen)) + 0.5);
2345
2346     /*
2347      * Handle the case of no command line options here.
2348      */
2349     if (argc == 0) {
2350         (void) gbdfed_make_editor(0, TRUE);
2351         return;
2352     }
2353
2354     /*
2355      * If a filename is not present on the command line, make sure an
2356      * editor is created after the command line is parsed.
2357      */
2358     need_editor = TRUE;
2359
2360     /*
2361      * Now parse the options from the command line.
2362      */
2363     while (argc > 0) {
2364         ap = *argv;
2365         if (*ap == '-') {
2366             if (strcmp(ap + 1, "nm") == 0)
2367               options.font_opts.correct_metrics = 0;
2368             else if (strcmp(ap + 1, "nu") == 0)
2369               options.font_opts.keep_unencoded = 0;
2370             else if (strcmp(ap + 1, "nc") == 0)
2371               options.font_opts.keep_comments = 0;
2372             else if (strcmp(ap + 1, "np") == 0)
2373               options.font_opts.pad_cells = 0;
2374             else if (strcmp(ap + 1, "bp") == 0)
2375               options.no_blanks = FALSE;
2376             else if (strcmp(ap + 1, "ed") == 0)
2377               options.really_exit = FALSE;
2378             else if (strcmp(ap + 1, "im") == 0)
2379               options.overwrite_mode = FALSE;
2380             else if (strcmp(ap + 1, "o") == 0) {
2381                 argc--;
2382                 argv++;
2383                 options.orientation =
2384                     (argv[0][0] == 'v' || argv[0][0] == 'V') ?
2385                     GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL;
2386             } else if (strcmp(ap + 1, "ps") == 0) {
2387                 argc--;
2388                 argv++;
2389                 options.font_opts.point_size = _bdf_atoul(*argv, 0, 10);
2390             } else if (strcmp(ap + 1, "res") == 0) {
2391                 argc--;
2392                 argv++;
2393                 options.resolution = _bdf_atoul(*argv, 0, 10);
2394                 options.font_opts.resolution_x =
2395                     options.font_opts.resolution_y = options.resolution;
2396             } else if (strcmp(ap + 1, "hres") == 0) {
2397                 argc--;
2398                 argv++;
2399                 options.font_opts.resolution_x = _bdf_atoul(*argv, 0, 10);
2400             } else if (strcmp(ap + 1, "vres") == 0) {
2401                 argc--;
2402                 argv++;
2403                 options.font_opts.resolution_y = _bdf_atoul(*argv, 0, 10);
2404             } else if (strcmp(ap + 1, "bpp") == 0) {
2405                 argc--;
2406                 argv++;
2407                 options.font_opts.bits_per_pixel = _bdf_atoul(*argv, 0, 10);
2408             } else if (strcmp(ap + 1, "g") == 0) {
2409                 argc--;
2410                 argv++;
2411                 ap = *argv;
2412                 if (*ap == '\\') {
2413                     switch (*(ap + 1)) {
2414                       case 'u': case 'x': base = 16; ap += 2; break;
2415                       case 'o': base = 8; ap += 2; break;
2416                       case 'd': base = 10; ap += 2; break;
2417                     }
2418                 } else if ((*ap == 'U' && (*(ap + 1) == '+' ||
2419                                            *(ap + 1) == '-')) ||
2420                            (*ap == '0' && (*(ap + 1) == 'x' ||
2421                                            *(ap + 1) == 'X'))) {
2422                     base = 16;
2423                     ap += 2;
2424                 } else if (*ap == '0')
2425                   base = 8;
2426
2427                 options.initial_glyph = _bdf_atol(ap, 0, base);
2428             } else if (strcmp(ap + 1, "sp") == 0) {
2429                 argc--;
2430                 argv++;
2431                 switch (argv[0][0]) {
2432                   case 'c': case 'C':
2433                     options.font_opts.font_spacing = BDF_CHARCELL; break;
2434                   case 'm': case 'M':
2435                     options.font_opts.font_spacing = BDF_MONOWIDTH; break;
2436                   case 'p': case 'P':
2437                     options.font_opts.font_spacing = BDF_PROPORTIONAL; break;
2438                 }
2439             } else if (strcmp(ap + 1, "eol") == 0) {
2440                 argc--;
2441                 argv++;
2442                 switch (argv[0][0]) {
2443                   case 'd': case 'D':
2444                     options.font_opts.eol = BDF_DOS_EOL; break;
2445                   case 'm': case 'M':
2446                     options.font_opts.eol = BDF_MAC_EOL; break;
2447                   case 'u': case 'U':
2448                     options.font_opts.eol = BDF_UNIX_EOL; break;
2449                 }
2450             } else if (strcmp(ap + 1, "cb") == 0) {
2451                 argc--;
2452                 argv++;
2453                 switch (argv[0][0]) {
2454                   case 'd': case 'D':
2455                     options.code_base = 10; break;
2456                   case 'h': case 'H':
2457                     options.code_base = 16; break;
2458                   case 'o': case 'O':
2459                     options.code_base = 8; break;
2460                 }
2461             } else {
2462                 if (ap[1] != 'h')
2463                   fprintf(stderr, "%s: unknown parameter '%s'.\n",
2464                           g_get_prgname(), ap);
2465                 usage();
2466             }
2467         } else {
2468             need_editor = FALSE;
2469             (void) gbdfed_make_editor(argv[0], TRUE);
2470         }
2471
2472         argc--;
2473         argv++;
2474     }
2475
2476     if (need_editor == TRUE)
2477       /*
2478        * If an editor was not created, make one here.
2479        */
2480       (void) gbdfed_make_editor(0, TRUE);
2481 }
2482
2483 int 
2484 main(int argc, char* argv[])
2485 {
2486     num_editors = 0;
2487
2488     /*
2489      * Make sure the BDF library is initialized.
2490      */
2491     bdf_setup();
2492
2493     gtk_init(&argc, &argv);  
2494
2495     argc--;
2496     argv++;
2497
2498     editor_setup(argc, argv);
2499
2500     gtk_main();
2501
2502     return 0;
2503 }