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