]> git.karo-electronics.de Git - gbdfed.git/blob - fontgrid.c
Fixup several compile faults due to changes in recent distributions,
[gbdfed.git] / fontgrid.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 "fontgrid.h"
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkselection.h>
26 #include <gtk/gtkwidget.h>
27
28 #ifdef HAVE_XLIB
29 #include <gdk/gdkx.h>
30 #endif
31
32 #ifdef ENABLE_NLS
33 #include <libintl.h>
34 #define _(s) dgettext(GETTEXT_PACKAGE,s)
35 #else
36 #define _(s) (s)
37 #endif
38
39 /*
40  * Macros that represent the properties used by this type of object.
41  */
42 #define FONTGRID_CLIPBOARD gdk_atom_intern("FONTGRID_CLIPBOARD", FALSE)
43 #define FONTGRID_GLYPHLIST gdk_atom_intern("FONTGRID_GLYPHLIST", FALSE)
44
45 /*
46  * Set several defaults.
47  */
48 #define FGRID_MAX_COLS            16
49 #define FGRID_MAX_ROWS            16
50 #define FGRID_DEFAULT_COLS        16
51 #define FGRID_DEFAULT_ROWS        8
52 #define FGRID_DEFAULT_CELL_HEIGHT 18
53
54 /*
55  * Enums used for identifying properties.
56  */
57 enum {
58     PROP_0 = 0,
59     PROP_CODE_BASE,
60     PROP_POWER2,
61     PROP_ORIENTATION,
62     PROP_FONT,
63     PROP_POINT_SIZE,
64     PROP_SPACING,
65     PROP_SKIP_BLANKS,
66     PROP_OVERWRITE,
67     PROP_COLORS,
68     PROP_INITIAL_GLYPH,
69     PROP_BPP,
70     PROP_HRES,
71     PROP_VRES
72 };
73
74 /**************************************************************************
75  *
76  * Selection macros for toggling & testing glyph selected state.
77  *
78  **************************************************************************/
79
80 /*
81  * Macros for dealing with the selected state of glyphs in the font grid.
82  */
83 #define IsSelected(code, map) (map[(code) >> 5] & (1 << ((code) & 31)))
84 #define Select(code, map) (map[(code) >> 5] |= (1 << ((code) & 31)))
85 #define Unselect(code, map) (map[(code) >> 5] &= ~(1 << ((code) & 31)))
86
87 /**************************************************************************
88  *
89  * Signals.
90  *
91  **************************************************************************/
92
93 /*
94  * Enums that represent the signals these objects send out.
95  */
96 enum {
97     SELECTION_START = 0,
98     SELECTION_EXTEND,
99     SELECTION_END,
100     ACTIVATE,
101     MODIFIED,
102     TURN_TO_PAGE
103 };
104
105 static GtkWidgetClass *parent_class = 0;
106 static guint fontgrid_signals[TURN_TO_PAGE + 1];
107
108 static bdf_glyph_t empty_glyph;
109
110 /**************************************************************************
111  *
112  * Digits for displaying the cell encoding.
113  *
114  **************************************************************************/
115
116 /*
117  * Lists of points that describe the encoding digits.
118  */
119 typedef struct {
120     GdkPoint *points;
121     guint npoints;
122 } fontgrid_digit;
123
124 static GdkPoint digit00[] = {{2, 0}, {1, 1}, {3, 1}, {0, 2}, {4, 2}, {0, 3},
125                              {4, 3}, {0, 4}, {4, 4}, {1, 5}, {3, 5}, {2, 6}}; 
126
127 static GdkPoint digit01[] = {{2, 0}, {1, 1}, {2, 1}, {0, 2}, {2, 2}, {2, 3},
128                              {2, 4}, {2, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6},
129                              {4, 6}};
130
131 static GdkPoint digit02[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {4, 2},
132                              {2, 3}, {3, 3}, {1, 4}, {0, 5}, {0, 6}, {1, 6},
133                              {2, 6}, {3, 6}, {4, 6}};
134
135 static GdkPoint digit03[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {4, 1},
136                              {3, 2}, {2, 3},{3, 3}, {4, 4}, {0, 5}, {4, 5},
137                              {1, 6}, {2, 6}, {3, 6}};
138
139 static GdkPoint digit04[] = {{3, 0}, {2, 1}, {3, 1}, {1, 2}, {3, 2}, {0, 3},
140                              {3, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4},
141                              {3, 5}, {3, 6}};
142
143 static GdkPoint digit05[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
144                              {0, 2}, {2, 2}, {3, 2}, {0, 3}, {1, 3}, {4, 3},
145                              {4, 4}, {0, 5}, {4, 5}, {1, 6}, {2, 6}, {3, 6}};
146
147 static GdkPoint digit06[] = {{2, 0}, {3, 0}, {1, 1}, {0, 2}, {0, 3}, {2, 3},
148                              {3, 3}, {0, 4}, {1, 4}, {4, 4}, {0, 5}, {4, 5},
149                              {1, 6}, {2, 6}, {3, 6}};
150
151 static GdkPoint digit07[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {4, 1},
152                              {3, 2}, {3, 3}, {2, 4}, {1, 5}, {1, 6}};
153
154 static GdkPoint digit08[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
155                              {4, 2}, {1, 3}, {2, 3}, {3, 3}, {0, 4}, {4, 4},
156                              {0, 5}, {4, 5}, {1, 6}, {2, 6}, {3, 6}};
157
158 static GdkPoint digit09[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
159                              {3, 2}, {4, 2}, {1, 3}, {2, 3}, {4, 3}, {4, 4},
160                              {3, 5}, {1, 6}, {2, 6}};
161
162 static GdkPoint digit10[] = {{2, 0}, {1, 1}, {3, 1}, {0, 2}, {4, 2}, {0, 3},
163                              {4, 3}, {0, 4}, {1, 4}, {2, 4}, {3, 4}, {4, 4},
164                              {0, 5}, {4, 5}, {0, 6}, {4, 6}};
165
166 static GdkPoint digit11[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {1, 1}, {4, 1},
167                              {1, 2}, {4, 2}, {1, 3}, {2, 3}, {3, 3}, {1, 4},
168                              {4, 4}, {1, 5}, {4, 5}, {0, 6}, {1, 6}, {2, 6},
169                              {3, 6}};
170
171 static GdkPoint digit12[] = {{1, 0}, {2, 0}, {3, 0}, {0, 1}, {4, 1}, {0, 2},
172                              {0, 3}, {0, 4},{0, 5}, {4, 5}, {1, 6}, {2, 6},
173                              {3, 6}};
174
175 static GdkPoint digit13[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {1, 1}, {4, 1},
176                              {1, 2}, {4, 2}, {1, 3}, {4, 3}, {1, 4}, {4, 4},
177                              {1, 5}, {4, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6}};
178
179 static GdkPoint digit14[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
180                              {0, 2}, {0, 3}, {1, 3}, {2, 3}, {3, 3}, {0, 4},
181                              {0, 5}, {0, 6}, {1, 6}, {2, 6}, {3, 6}, {4, 6}};
182
183 static GdkPoint digit15[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {0, 1},
184                              {0, 2}, {0, 3}, {1, 3}, {2, 3}, {3, 3}, {0, 4},
185                              {0, 5}, {0, 6}};
186 static GdkPoint minus[] = {{1, 3}, {2, 3}, {3, 3}, {4,3}};
187
188 static fontgrid_digit digits[] = {
189    {digit00, sizeof(digit00)/sizeof(GdkPoint)},
190    {digit01, sizeof(digit01)/sizeof(GdkPoint)},
191    {digit02, sizeof(digit02)/sizeof(GdkPoint)},
192    {digit03, sizeof(digit03)/sizeof(GdkPoint)},
193    {digit04, sizeof(digit04)/sizeof(GdkPoint)},
194    {digit05, sizeof(digit05)/sizeof(GdkPoint)},
195    {digit06, sizeof(digit06)/sizeof(GdkPoint)},
196    {digit07, sizeof(digit07)/sizeof(GdkPoint)},
197    {digit08, sizeof(digit08)/sizeof(GdkPoint)},
198    {digit09, sizeof(digit09)/sizeof(GdkPoint)},
199    {digit10, sizeof(digit10)/sizeof(GdkPoint)},
200    {digit11, sizeof(digit11)/sizeof(GdkPoint)},
201    {digit12, sizeof(digit12)/sizeof(GdkPoint)},
202    {digit13, sizeof(digit13)/sizeof(GdkPoint)},
203    {digit14, sizeof(digit14)/sizeof(GdkPoint)},
204    {digit15, sizeof(digit15)/sizeof(GdkPoint)},
205    {minus, sizeof(minus)/sizeof(GdkPoint)},
206 };
207
208 /*
209  * This array is used to hold a set of digits that will be displayed.  It
210  * provides for a max of 19 points per digit and a max of 6 digits.
211  */
212 static GdkPoint encoding_digits[19*6];
213
214 /*
215  * Used to determine spacing between digits when displaying.
216  */
217 #define FONTGRID_DIGIT_WIDTH   6
218 #define FONTGRID_DIGIT_HEIGHT 10
219
220 /*
221  * A macro for getting the current foreground GC.
222  */
223 #define WIDGET_FG_GC(w) ((w)->style->fg_gc[GTK_WIDGET_STATE(w)])
224
225 #define HMARGINS(fw) ((fw)->hmargin << 1)
226 #define VMARGINS(fw) ((fw)->vmargin << 1)
227
228 static void
229 fontgrid_set_cell_geometry(Fontgrid *fw)
230 {
231     bdf_font_t *font;
232     gint lw;
233
234     font = fw->font;
235
236     lw = FONTGRID_DIGIT_WIDTH * 7;
237
238     /*
239      * The labels will always be numbers in base 8, 10, or 16, so we are only
240      * interested in the max ascent.  Add a 2-pixel margin on top and bottom.
241      */
242     fw->label_height = FONTGRID_DIGIT_HEIGHT + 4;
243
244     /*
245      * We want a minumum padding of 3 pixels on each side of the glyph bitmap
246      * in each cell. Thus the addition of 6 to each dimension.
247      */
248     if (font != 0) {
249         fw->cell_width = font->bbx.width + 6;
250         fw->cell_height = font->bbx.height + 6;
251     } else {
252         /*
253          * Hard-code a minimum size for NULL fonts. The initial height of
254          * an empty cell is 20 to give it a better visual appearance.
255          */
256         fw->cell_width = lw + 6;
257         fw->cell_height = FGRID_DEFAULT_CELL_HEIGHT + 6;
258     }
259
260     fw->cell_width = MAX(fw->cell_width, lw);
261     fw->cell_height = MAX(fw->cell_height, fw->label_height);
262
263     /*
264      * Now add the label size into the picture.
265      */
266     fw->cell_height += fw->label_height - 1;
267 }
268
269 static void
270 fontgrid_set_rows_cols(Fontgrid *fw, GtkAllocation *core)
271 {
272     gint i;
273     guint16 dw, dh, wd, ht;
274
275     /*
276      * Limit the window size to 7/8 of the actual screen dimensions.
277      */
278     dw = (gdk_screen_width() * 7) >> 3;
279     dh = (gdk_screen_height() * 7) >> 3;
280
281     if (!core) {
282         /*
283          * Adjust the rows and columns based on the preferred geometry.
284          */
285         wd = (fw->cell_width * fw->cell_cols) + HMARGINS(fw);
286         ht = (fw->cell_height * fw->cell_rows) + VMARGINS(fw);
287
288         if (wd > dw)
289           fw->cell_cols = (dw - HMARGINS(fw)) / fw->cell_width;
290
291         if (ht > dh)
292           fw->cell_rows = (dh - VMARGINS(fw)) / fw->cell_height;
293     } else {
294         /*
295          * Adjust the rows and columns based on the current geometry.
296          */
297         fw->cell_cols = (core->width - HMARGINS(fw)) / fw->cell_width;
298         fw->cell_rows = (core->height - VMARGINS(fw)) / fw->cell_height;
299     }
300
301     /*
302      * Adjust rows and columns to powers of two if necessary.
303      */
304     if (fw->power2) {
305         /*
306          * Make sure the columns are a power of 2.
307          */
308         for (i = 15; i >= 0; i--) {
309             if (fw->cell_cols & (1 << i)) {
310                 fw->cell_cols = 1 << i;
311                 break;
312             }
313         }
314
315         /*
316          * Make sure the rows are a power of 2.
317          */
318         for (i = 15; i >= 0; i--) {
319             if (fw->cell_rows & (1 << i)) {
320                 fw->cell_rows = 1 << i;
321                 break;
322             }
323         }
324     }
325
326     /*
327      * Fall back to a minimum of two rows.
328      */
329     if (fw->cell_rows == 0)
330       fw->cell_rows = 2;
331
332     /*
333      * Fall back to a minimum of two columns.
334      */
335     if (fw->cell_cols == 0)
336       fw->cell_cols = 2;
337
338     /*
339      * Make sure the number of rows and cols are within the max limits.
340      */
341     if (fw->cell_cols > FGRID_MAX_COLS)
342       fw->cell_cols = FGRID_MAX_COLS;
343
344     if (fw->cell_rows > FGRID_MAX_ROWS)
345       fw->cell_rows = FGRID_MAX_ROWS;
346
347     /*
348      * Set the new page size based on the calculated rows and columns.
349      */
350     fw->pagesize = fw->cell_rows * fw->cell_cols;
351 }
352
353 /**************************************************************************
354  *
355  * GObjectClass functions.
356  *
357  **************************************************************************/
358
359 static void
360 fontgrid_set_property(GObject *obj, guint prop_id, const GValue *value,
361                       GParamSpec *pspec)
362 {
363     GtkWidget *widget;
364     Fontgrid *fw;
365
366     widget = GTK_WIDGET(obj);
367     fw = FONTGRID(obj);
368
369     switch (prop_id) {
370       case PROP_CODE_BASE:
371         fw->base = g_value_get_uint(value);
372         /*
373          * Force the encodings to be redisplayed here?
374          */
375         break;
376       case PROP_POWER2:
377         fw->power2 = g_value_get_boolean(value);
378         break;
379       case PROP_ORIENTATION:
380         fontgrid_set_orientation(fw, g_value_get_enum(value));
381         break;
382       case PROP_FONT:
383         /*
384          * Need to set the rows and columns back to their defaults when
385          * a new font is passed in case it is NULL.
386          */
387         fw->font = (bdf_font_t *) g_value_get_pointer(value);
388
389         fontgrid_set_cell_geometry(fw);
390         fontgrid_set_rows_cols(fw, 0);
391         break;
392       case PROP_POINT_SIZE:
393         fw->point_size = g_value_get_uint(value);
394         break;
395       case PROP_SPACING:
396         fw->spacing = g_value_get_int(value);
397         break;
398       case PROP_SKIP_BLANKS:
399         fw->noblanks = g_value_get_boolean(value);
400         break;
401       case PROP_OVERWRITE:
402         fw->overwrite = g_value_get_boolean(value);
403         break;
404       case PROP_COLORS:
405         fw->colors = (guint16 *) g_value_get_pointer(value);
406         break;
407       case PROP_INITIAL_GLYPH:
408         fw->initial_glyph = g_value_get_int(value);
409         break;
410       case PROP_BPP:
411         fw->bpp = g_value_get_int(value);
412         break;
413       case PROP_HRES:
414         fw->hres = g_value_get_int(value);
415         break;
416       case PROP_VRES:
417         fw->vres = g_value_get_int(value);
418         break;
419     }
420 }
421
422 static void
423 fontgrid_get_property(GObject *obj, guint prop_id, GValue *value,
424                       GParamSpec *pspec)
425 {
426     Fontgrid *f;
427
428     f = FONTGRID(obj);
429
430     switch (prop_id) {
431       case PROP_CODE_BASE:
432         g_value_set_uint(value, f->base);
433         break;
434       case PROP_POWER2:
435         g_value_set_boolean(value, f->power2);
436         break;
437       case PROP_ORIENTATION:
438         g_value_set_enum(value, f->orientation);
439         break;
440       case PROP_FONT:
441         g_value_set_pointer(value, f->font);
442         break;
443       case PROP_POINT_SIZE:
444         g_value_set_uint(value, f->point_size);
445         break;
446       case PROP_SPACING:
447         g_value_set_int(value, f->spacing);
448         break;
449       case PROP_SKIP_BLANKS:
450         g_value_set_boolean(value, f->noblanks);
451         break;
452       case PROP_COLORS:
453         g_value_set_pointer(value, f->colors);
454         break;
455       case PROP_INITIAL_GLYPH:
456         g_value_set_int(value, f->initial_glyph);
457         break;
458       case PROP_BPP:
459         g_value_set_int(value, f->bpp);
460         break;
461       case PROP_HRES:
462         g_value_set_int(value, f->hres);
463         break;
464       case PROP_VRES:
465         g_value_set_int(value, f->vres);
466         break;
467     }
468 }
469
470 /**************************************************************************
471  *
472  * GtkObjectClass functions.
473  *
474  **************************************************************************/
475
476 static void
477 fontgrid_destroy(GtkObject *obj)
478 {
479     Fontgrid *f;
480     guint32 i;
481     bdf_glyphlist_t *gl;
482
483     /*
484      * Do some checks to make sure the incoming object exists and is the right
485      * kind.
486      */
487     g_return_if_fail(obj != 0);
488     g_return_if_fail(IS_FONTGRID(obj));
489
490     f = FONTGRID(obj);
491
492     /*
493      * Clean up this object instance.
494      */
495     if (f->font)
496       bdf_free_font(f->font);
497     f->font = 0;
498
499     if (f->xor_gc != 0)
500       g_object_unref(G_OBJECT(f->xor_gc));
501     f->xor_gc = 0;
502
503     if (f->points_size > 0)
504       g_free(f->points);
505     f->points_size = f->points_used = 0;
506
507     if (f->rgb_size > 0)
508       g_free(f->rgb);
509     f->rgb_used = f->rgb_size = 0;
510
511     /*
512      * Remove all ownership of selections.
513      */
514     gtk_selection_remove_all(GTK_WIDGET(obj));
515
516     /*
517      * Free up the clipboard contents if there are any.
518      */
519     gl = &f->clipboard;
520     for (i = 0; i < gl->glyphs_used; i++) {
521         if (gl->glyphs[i].name)
522           free(gl->glyphs[i].name);
523         if (gl->glyphs[i].bytes > 0)
524           free((char *) gl->glyphs[i].bitmap);
525     }
526     if (gl->glyphs_size > 0)
527       free((char *) gl->glyphs);
528     gl->glyphs_size = gl->glyphs_used = 0;
529
530     /*
531      * Follow the class chain back up to free up resources allocated in the
532      * parent classes.
533      */
534     GTK_OBJECT_CLASS(parent_class)->destroy(obj);
535 }
536
537 static void
538 fontgrid_finalize(GObject *obj)
539 {
540     /*
541      * Do some checks to make sure the incoming object exists and is the right
542      * kind.
543      */
544     g_return_if_fail(obj != 0);
545     g_return_if_fail(IS_FONTGRID(obj));
546
547     /*
548      * Follow the class chain back up to free up resources allocated in the
549      * parent classes.
550      */
551     G_OBJECT_CLASS(parent_class)->finalize(obj);
552 }
553
554 /**************************************************************************
555  *
556  * GtkWidgetClass functions.
557  *
558  **************************************************************************/
559
560 static void
561 fontgrid_preferred_size(GtkWidget *widget, GtkRequisition *preferred)
562 {
563     Fontgrid *fw;
564
565     fw = FONTGRID(widget);
566     preferred->width = (fw->cell_width * fw->cell_cols) + HMARGINS(fw);
567     preferred->height = (fw->cell_height * fw->cell_rows) + VMARGINS(fw);
568 }
569
570 static void
571 fontgrid_actual_size(GtkWidget *widget, GtkAllocation *actual)
572 {
573     Fontgrid *fw;
574
575     fw = FONTGRID(widget);
576
577     widget->allocation = *actual;
578
579     /*
580      * Make sure the rows and columns are adjusted to fit the actual allocated
581      * size.
582      */
583     fontgrid_set_rows_cols(fw, actual);
584
585     if (GTK_WIDGET_REALIZED(widget))
586       gdk_window_move_resize(widget->window, actual->x, actual->y,
587                              actual->width, actual->height);
588 }
589
590 static void
591 fontgrid_realize(GtkWidget *widget)
592 {
593     Fontgrid *fw;
594     GdkWindowAttr attributes;
595     GdkGCValues values;
596     gint attributes_mask;
597
598     g_return_if_fail(widget != NULL);
599     g_return_if_fail(IS_FONTGRID(widget));
600
601     fw = FONTGRID(widget);
602     GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
603
604     attributes.window_type = GDK_WINDOW_CHILD;
605     attributes.x = widget->allocation.x;
606     attributes.y = widget->allocation.y;
607     attributes.width = widget->allocation.width;
608     attributes.height = widget->allocation.height;
609     attributes.wclass = GDK_INPUT_OUTPUT;
610     attributes.visual = gtk_widget_get_visual(widget);
611     attributes.colormap = gtk_widget_get_colormap(widget);
612     attributes.event_mask = gtk_widget_get_events(widget);
613     attributes.event_mask |= (GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|
614                               GDK_BUTTON_RELEASE_MASK|GDK_ENTER_NOTIFY_MASK|
615                               GDK_POINTER_MOTION_MASK|
616                               GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK|
617                               GDK_LEAVE_NOTIFY_MASK|GDK_FOCUS_CHANGE_MASK|
618                               GDK_PROPERTY_CHANGE_MASK);
619
620     attributes_mask = GDK_WA_X|GDK_WA_Y|GDK_WA_VISUAL|GDK_WA_COLORMAP;
621
622     widget->window = gdk_window_new(gtk_widget_get_parent_window(widget),
623                                     &attributes, attributes_mask);
624     gdk_window_set_user_data(widget->window, widget);
625
626     widget->style = gtk_style_attach(widget->style, widget->window);
627     gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL);
628
629     if (fw->xor_gc != 0)
630       g_object_unref(G_OBJECT(fw->xor_gc));
631
632     /*
633      * Create the GC used to display selected cells.
634      */
635     values.foreground.pixel =
636         widget->style->fg[GTK_WIDGET_STATE(widget)].pixel ^
637         widget->style->bg[GTK_WIDGET_STATE(widget)].pixel;
638     (void) memset((char *) &values.background, 0, sizeof(GdkColor));
639     values.function = GDK_XOR;
640     fw->xor_gc = gdk_gc_new_with_values(widget->window, &values,
641                                         GDK_GC_FOREGROUND|
642                                         GDK_GC_BACKGROUND|GDK_GC_FUNCTION);
643 }
644
645 static bdf_glyph_t *
646 fontgrid_locate_glyph(bdf_glyph_t *glyphs, guint32 nglyphs, gint32 code,
647                       gboolean exact_match)
648 {
649     gint32 l, r, m = 0;
650
651     if (code < 0 || glyphs == 0 || nglyphs == 0)
652       return 0;
653
654     for (l = 0, r = (gint32) (nglyphs - 1); l <= r; ) {
655         m = (l + r) >> 1;
656         if (glyphs[m].encoding < code)
657           l = m + 1;
658         else if (glyphs[m].encoding > code)
659           r = m - 1;
660         else {
661             if (exact_match)
662               return glyphs + m;
663             break;
664         }
665     }
666
667     if (exact_match)
668       return 0;
669
670     /*
671      * Adjust to the beginning or end if nothing was found in the search.
672      */
673     while (m > 0 && glyphs[m].encoding > code)
674       m--;
675     while (m < (gint32) nglyphs && glyphs[m].encoding < code)
676       m++;
677
678     return (m < (gint32) nglyphs) ? glyphs + m : 0;
679 }
680
681 static void
682 fontgrid_get_glyph_points(Fontgrid *fw, gint x, gint y, gint rx, gint by,
683                           bdf_glyph_t *glyph)
684 {
685     gint i, j, bpr, col;
686     unsigned char *bmap, *masks = 0;
687
688     switch (fw->bpp) {
689       case 1: masks = bdf_onebpp; break;
690       case 2: masks = bdf_twobpp; break;
691       case 4: masks = bdf_fourbpp; break;
692       case 8: masks = bdf_eightbpp; break;
693     }
694
695     fw->points_used = 0;
696     bmap = glyph->bitmap;
697     bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
698
699     for (i = 0; i + y - glyph->bbx.ascent < by && i < glyph->bbx.height; i++) {
700         for (col = j = 0; j + x < rx && j < glyph->bbx.width;
701              j++, col += fw->bpp) {
702             if (bmap[(i * bpr) + (col >> 3)] &
703                 masks[(col & 7) / fw->bpp]) {
704                 if (fw->points_used == fw->points_size) {
705                     if (fw->points_size == 0)
706                       fw->points =
707                           (GdkPoint *) g_malloc(sizeof(GdkPoint) << 7);
708                     else
709                       fw->points =
710                           (GdkPoint *) g_realloc(fw->points,
711                                                  sizeof(GdkPoint) *
712                                                  (fw->points_size + 128));
713                     fw->points_size += 128;
714                 }
715
716                 fw->points[fw->points_used].x = j + x;
717                 fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
718                 fw->points_used++;
719             }
720         }
721     }
722 }
723
724 #if 0
725 static void
726 fontgrid_get_glyph_points_color(Fontgrid *fw, gint x, gint y, gint rx, gint by,
727                                 gint color_index, bdf_glyph_t *glyph)
728 {
729     gint i, j, bpr, col, byte, di = 0, si, cidx = 0;
730     unsigned char *bmap, *masks = 0;
731
732     switch (fw->bpp) {
733       case 1: masks = bdf_onebpp; di = 7; break;
734       case 2: masks = bdf_twobpp; di = 3; break;
735       case 4: masks = bdf_fourbpp; di = 1; break;
736       case 8: masks = bdf_eightbpp; di = 0; break;
737     }
738
739     fw->points_used = 0;
740     bmap = glyph->bitmap;
741     bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
742
743     for (i = 0; i + y - glyph->bbx.ascent < by && i < glyph->bbx.height; i++) {
744         for (col = j = 0; j + x < rx && j < glyph->bbx.width;
745              j++, col += fw->bpp) {
746             si = (col & 7) / fw->bpp;
747             byte = bmap[(i * bpr) + (col >> 3)] & masks[si];
748             if (byte) {
749                 /*
750                  * Check to see if the byte matches the color index being
751                  * collected.
752                  */
753                 if (di > si)
754                   byte >>= (di - si) * fw->bpp;
755
756                 if (byte == cidx) {
757                     if (fw->points_used == fw->points_size) {
758                         if (fw->points_size == 0)
759                           fw->points = (GdkPoint *)
760                               g_malloc(sizeof(GdkPoint) << 6);
761                         else
762                           fw->points = (GdkPoint *)
763                               g_realloc(fw->points, sizeof(GdkPoint) *
764                                         (fw->points_size + 64));
765                         fw->points_size += 64;
766                     }
767
768                     fw->points[fw->points_used].x = j + x;
769                     fw->points[fw->points_used].y = i + y - glyph->bbx.ascent;
770                     fw->points_used++;
771                 }
772             }
773         }
774     }
775 }
776 #endif
777
778 /*
779  * This routine creates a 24 bits per pixel image of a glyph so it can be
780  * drawn using GtkRGB. This is less complicated than the old method of
781  * collecting and drawing individual pixels of each different color.
782  */
783 static void
784 fontgrid_make_rgb_image(Fontgrid *fw, bdf_glyph_t *glyph)
785 {
786     GtkWidget *w = GTK_WIDGET(fw);
787     gint x, y, bpr, rgb_bpr, col, byte, di = 0, si;
788     guchar bg[4], pix[4], *bmap, *masks = 0;
789
790     /*
791      * Figure out the background color.
792      */
793     bg[0] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].red;
794     bg[1] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].green;
795     bg[2] = (guchar) w->style->bg[GTK_WIDGET_STATE(w)].blue;
796
797     switch (fw->bpp) {
798       case 1: masks = bdf_onebpp; di = 7; break;
799       case 2: masks = bdf_twobpp; di = 3; break;
800       case 4: masks = bdf_fourbpp; di = 1; break;
801       case 8: masks = bdf_eightbpp; di = 0; break;
802     }
803
804     bmap = glyph->bitmap;
805     bpr = ((glyph->bbx.width * fw->bpp) + 7) >> 3;
806
807     rgb_bpr = glyph->bbx.width * 3;
808     fw->rgb_used = rgb_bpr * glyph->bbx.height;
809
810     if (fw->rgb_size < fw->rgb_used) {
811         if (fw->rgb_size == 0)
812           fw->rgb = g_malloc(fw->rgb_used);
813         else
814           fw->rgb = g_realloc(fw->rgb, fw->rgb_used);
815         fw->rgb_size = fw->rgb_used;
816     }
817
818     for (y = 0; y < glyph->bbx.height; y++) {
819         for (col = x = 0; x < glyph->bbx.width; x++, col += fw->bpp) {
820             si = (col & 7) / fw->bpp;
821
822             byte = bmap[(y * bpr) + (col >> 3)] & masks[si];
823             if (di > si)
824               byte >>= (di - si) * fw->bpp;
825             if (byte) {
826                 /*
827                  * Look up the color.
828                  */
829                 switch (fw->bpp) {
830                   case 1: memset(pix, 0, 3); break;
831                   case 2: memset(pix, fw->colors[byte-1], 3); break;
832                   case 4: memset(pix, fw->colors[byte-1+4], 3); break;
833                   case 8: memset(pix, byte, 3); break;
834                 }
835             } else
836               /*
837                * Set the pixel to the background color.
838                */
839               memcpy(pix, bg, 3);
840
841             memcpy(&fw->rgb[(y * rgb_bpr) + (x * 3)], pix, 3);
842         }
843     }
844 }
845
846 static void
847 fontgrid_draw_encoding(GtkWidget *w, GdkGC *gc, gint x, gint y, gchar *num,
848                        gint numlen)
849 {
850     gint i, j, d;
851     GdkPoint *dp;
852
853     if (!GTK_WIDGET_REALIZED(w))
854       return;
855
856     dp = encoding_digits;
857     for (i = 0; i < numlen; i++) {
858         if (num[i] == '-') 
859           d = 16;
860         else if (num[i] <= '9')
861           d = num[i] - '0';
862         else
863           d = (num[i] - 'A') + 10;
864
865         /*
866          * Copy the next digit into the display array.
867          */
868         (void) memcpy((char *) dp, (char *) digits[d].points,
869                       sizeof(GdkPoint) * digits[d].npoints);
870         /*
871          * Position the points.
872          */
873         for (j = 0; j < digits[d].npoints; j++) {
874             dp[j].x += x;
875             dp[j].y += y;
876         }
877         dp += digits[d].npoints;
878         x += 6;
879     }
880
881     /*
882      * Draw the points.
883      */
884     gdk_draw_points(w->window, gc, encoding_digits, dp - encoding_digits);
885 }
886
887 static void
888 fontgrid_draw_cells(GtkWidget *widget, gint32 start, gint32 end,
889                     gboolean labels, gboolean glyphs)
890 {
891     Fontgrid *fw;
892     gint x, y, wd, as, ds, len, lx, ly;
893     gint32 i, n, r, c;
894     guint32 nglyphs, ng;
895     gboolean mod;
896     bdf_font_t *font;
897     bdf_glyph_t *glyph, *gp;
898     FontgridInternalPageInfo *pi;
899     GdkGC *gc;
900     GdkRectangle rect;
901     gchar nbuf[16];
902
903     if (!GTK_WIDGET_REALIZED(widget) || (labels == FALSE && glyphs == FALSE))
904       return;
905
906     fw = FONTGRID(widget);
907
908     font = fw->font;
909
910     glyph = 0;
911     nglyphs = 0;
912
913     if (!fw->unencoded) {
914         pi = &fw->npage;
915         if (font) {
916             glyph = font->glyphs;
917             nglyphs = font->glyphs_used;
918         }
919     } else {
920         /*
921          * When viewing the unencoded glyph pages, all glyphs are labelled
922          * with an encoding of -1.
923          */
924         strcpy(nbuf, "-1");
925
926         pi = &fw->upage;
927         if (font) {
928             glyph = font->unencoded;
929             nglyphs = font->unencoded_used;
930         }
931     }
932
933     /*
934      * The initial code to work from.
935      */
936     n = pi->bcode;
937
938     /*
939      * Locate the glyph closest to the starting code.
940      */
941     if ((glyph = fontgrid_locate_glyph(glyph, nglyphs, start, FALSE)) == 0)
942       nglyphs = 0;
943
944     gp = glyph;
945
946     gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
947
948     for (ng = 0, i = start; i <= end; i++) {
949         /*
950          * Only draw those cells that are on the current page.
951          */
952         if (i < pi->bcode || i >= pi->bcode + fw->pagesize)
953           continue;
954
955         if (fw->orientation == GTK_ORIENTATION_HORIZONTAL) {
956             r = (i - n) / fw->cell_cols;
957             c = (i - n) % fw->cell_cols;
958         } else {
959             c = (i - n) / fw->cell_rows;
960             r = (i - n) % fw->cell_rows;
961         }
962
963         x = fw->xoff + (c * fw->cell_width);
964         y = fw->yoff + (r * fw->cell_height);
965
966         if (labels) {
967             if (!fw->unencoded) {
968                 switch (fw->base) {
969                   case 8: sprintf(nbuf, "%o", i); break;
970                   case 10: sprintf(nbuf, "%d", i); break;
971                   case 16: sprintf(nbuf, "%X", i); break;
972                 }
973             }
974             rect.x = x + 1;
975             rect.y = y + 1;
976             rect.width = fw->cell_width - 2;
977             rect.height = fw->label_height - 2;
978             gdk_draw_rectangle(widget->window, gc, FALSE,
979                                rect.x, rect.y, rect.width, rect.height);
980
981             len = strlen(nbuf);
982             wd = len * 6;
983             as = 8;
984             ds = 0;
985
986             lx = (x + ((fw->cell_width >> 1) - (wd >> 1))) + 1;
987             ly = (y + ((fw->label_height >> 1) - ((as + ds) >> 1))) + 1;
988
989             mod = FALSE;
990             if (i <= 0xffff)
991               mod = (!fw->unencoded) ? bdf_glyph_modified(font, i, 0) :
992                 bdf_glyph_modified(font, i, 1);
993
994             gdk_window_clear_area(widget->window, rect.x + 1, rect.y + 1,
995                                   rect.width - 1, rect.height - 1);
996
997             if (!fw->unencoded && mod) {
998                 gdk_draw_rectangle(widget->window, gc, TRUE,
999                                    rect.x + 2, rect.y + 2,
1000                                    rect.width - 3, rect.height - 3);
1001                 fontgrid_draw_encoding(widget, fw->xor_gc, lx, ly, nbuf, len);
1002                 if (gp && gp->encoding == i) {
1003                     ng++;
1004                     gp++;
1005                     if (ng == nglyphs)
1006                       gp = 0;
1007                 }
1008             } else {
1009                 /*
1010                  * If the glyph exists, then darken the rectangle to indicate
1011                  * this.
1012                  */
1013                 if (gp && gp->encoding == i) {
1014                     gdk_draw_rectangle(widget->window, gc, FALSE,
1015                                        rect.x + 1, rect.y + 1,
1016                                        rect.width - 2, rect.height - 2);
1017                     ng++;
1018                     gp++;
1019                     if (ng == nglyphs)
1020                       gp = 0;
1021                 }
1022                 fontgrid_draw_encoding(widget, gc, lx, ly, nbuf, len);
1023             }
1024         }
1025
1026         if (glyphs) {
1027             rect.x = x + 1;
1028             rect.y = y + fw->label_height + 1;
1029             rect.width = fw->cell_width - 2;
1030             rect.height = (fw->cell_height - fw->label_height) - 2;
1031
1032             if (i <= 0xffff && nglyphs > 0 && glyph->encoding == i) {
1033                 /*
1034                  * Draw the glyph.
1035                  */
1036
1037                 /*
1038                  * Set the right and left limits for generating points.
1039                  */
1040                 lx = x + fw->cell_width - 2;
1041                 ly = y + fw->cell_height - 2;
1042
1043                 /*
1044                  * Adjust the X,Y coordinate pair so the bitmap points will
1045                  * be generated to center the glyphs horizontally and align
1046                  * them to the BDF font's baseline vertically.
1047                  */
1048                 x += (fw->cell_width >> 1) -
1049                     ((font->bbx.width + font->bbx.x_offset) >> 1) + 1;
1050                 y += fw->label_height + font->bbx.ascent + 3;
1051
1052                 if (IsSelected(glyph->encoding, pi->selmap)) {
1053                     gdk_draw_rectangle(widget->window, gc, TRUE,
1054                                        rect.x + 1, rect.y + 1,
1055                                        rect.width - 1, rect.height - 1);
1056                     if (glyph->bytes > 0) {
1057                         fontgrid_get_glyph_points(fw, x, y, lx, ly, glyph);
1058                         if (fw->points_used > 0)
1059                           gdk_draw_points(widget->window, fw->xor_gc,
1060                                           fw->points, fw->points_used);
1061                     }
1062                 } else {
1063                     /*
1064                      * The glyph is not selected, so draw it according to
1065                      * the bytes-per-pixel of the font.
1066                      */
1067                     gdk_window_clear_area(widget->window, rect.x, rect.y,
1068                                           rect.width, rect.height);
1069                     if (glyph->bytes > 0) {
1070                         fontgrid_make_rgb_image(fw, glyph);
1071                         gdk_draw_rgb_image(widget->window, gc,
1072                                            x, y - glyph->bbx.ascent,
1073                                            glyph->bbx.width,
1074                                            glyph->bbx.height,
1075                                            GDK_RGB_DITHER_NONE,
1076                                            fw->rgb, glyph->bbx.width * 3);
1077                     }
1078                 }
1079                 glyph++;
1080                 if (ng == nglyphs) {
1081                     nglyphs = 0;
1082                     glyph = 0;
1083                 }
1084             } else {
1085                 /*
1086                  * Clear the empty cell.
1087                  */
1088                 if (i <= 0xffff && IsSelected(i, pi->selmap))
1089                   gdk_draw_rectangle(widget->window, gc, TRUE,
1090                                      rect.x + 1, rect.y + 1,
1091                                      rect.width - 1, rect.height - 1);
1092                 else {
1093                     gdk_window_clear_area(widget->window, rect.x, rect.y,
1094                                           rect.width, rect.height);
1095                     if (i > 0xffff) {
1096                         gdk_draw_line(widget->window, gc, rect.x, rect.y,
1097                                       rect.x + rect.width,
1098                                       rect.y + rect.height);
1099                         gdk_draw_line(widget->window, gc,
1100                                       rect.x + rect.width, rect.y,
1101                                       rect.x, rect.y + rect.height);
1102                     }
1103                 }
1104             }
1105         }
1106     }
1107 }
1108
1109 static void
1110 fontgrid_draw(GtkWidget *widget, GdkRegion *region)
1111 {
1112     Fontgrid *fw;
1113     gint x, y, i;
1114     guint16 wd, ht, gw, gh;
1115     gint32 start, end;
1116     GdkGC *gc;
1117
1118     g_return_if_fail(widget != NULL);
1119     g_return_if_fail(IS_FONTGRID(widget));
1120
1121     fw = FONTGRID(widget);
1122
1123     gc = widget->style->fg_gc[GTK_WIDGET_STATE(widget)];
1124
1125     gw = fw->cell_width * fw->cell_cols;
1126     gh = fw->cell_height * fw->cell_rows;
1127     wd = widget->allocation.width;
1128     ht = widget->allocation.height;
1129     x = fw->xoff = ((wd >> 1) - (gw >> 1)) - 1;
1130     y = fw->yoff = ((ht >> 1) - (gh >> 1)) - 1;
1131
1132     /*
1133      * Draw the horizontal lines.
1134      */
1135     for (i = 0; i <= fw->cell_rows; i++) {
1136         gdk_draw_line(widget->window, gc, x, y, x + gw, y);
1137
1138         /*
1139          * Only draw the second line if this is not the last line.
1140          */
1141         if (i < fw->cell_rows)
1142           gdk_draw_line(widget->window, gc, x, y + fw->label_height,
1143                         x + gw, y + fw->label_height);
1144
1145         y += fw->cell_height;
1146     }
1147
1148     /*
1149      * Draw the vertical lines.
1150      */
1151     x = fw->xoff;
1152     y = fw->yoff;
1153
1154     for (i = 0; i <= fw->cell_cols; i++) {
1155         gdk_draw_line(widget->window, gc, x, y, x, y + gh);
1156         x += fw->cell_width;
1157     }
1158
1159     start = (!fw->unencoded) ? fw->npage.bcode : fw->upage.bcode;
1160     end = start + (gint32) (fw->pagesize - 1);
1161
1162     fontgrid_draw_cells(widget, start, end, TRUE, TRUE);
1163 }
1164
1165 static void
1166 fontgrid_select_range(Fontgrid *fw, gint32 start, gint32 end)
1167 {
1168     gint32 i, tmp;
1169     FontgridInternalPageInfo *pi;
1170
1171     if (start > end) {
1172         tmp = start;
1173         start = end;
1174         end = tmp;
1175     }
1176
1177     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1178
1179     for (i = start; i <= end; i++)
1180       Select(i, pi->selmap);
1181
1182     /*
1183      * Adjust the start and end values to the current page to determine which
1184      * cells need to be redrawn.
1185      */
1186     tmp = pi->bcode + (fw->pagesize - 1);
1187     if (start >= tmp || end < pi->bcode)
1188       return;
1189
1190     if (start < pi->bcode)
1191       start = pi->bcode;
1192     if (end > tmp)
1193       end = tmp;
1194     fontgrid_draw_cells(GTK_WIDGET(fw), start, end, FALSE, TRUE);
1195 }
1196
1197 static void
1198 fontgrid_deselect_range(Fontgrid *fw, gint32 start, gint32 end)
1199 {
1200     gint32 i, tmp;
1201     FontgridInternalPageInfo *pi;
1202
1203     if (start > end) {
1204         tmp = start;
1205         start = end;
1206         end = tmp;
1207     }
1208
1209     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1210     for (i = start; i <= end; i++) {
1211         if (IsSelected(i, pi->selmap)) {
1212             Unselect(i, pi->selmap);
1213             if (i >= pi->bcode && i <= pi->bcode + (fw->pagesize - 1))
1214               fontgrid_draw_cells(GTK_WIDGET(fw), i, i, FALSE, TRUE);
1215         }
1216     }
1217 }
1218
1219 static void
1220 fontgrid_deselect_all(Fontgrid *fw)
1221 {
1222     FontgridInternalPageInfo *pi, *opi;
1223
1224     if (!fw->unencoded) {
1225         pi = &fw->npage;
1226         opi = &fw->upage;
1227     } else {
1228         pi = &fw->upage;
1229         opi = &fw->npage;
1230     }
1231
1232     if (pi->sel_start != -1 || pi->sel_end != -1)
1233       fontgrid_deselect_range(fw, pi->bcode, pi->bcode + fw->pagesize - 1);
1234     else if (opi->sel_start != -1 || opi->sel_end != -1)
1235       fontgrid_deselect_range(fw, opi->bcode, opi->bcode + fw->pagesize - 1);
1236
1237     /*
1238      * Now clear the selected bitmaps.
1239      */
1240     (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
1241     (void) memset((char *) opi->selmap, 0, sizeof(guint32) * 2048);
1242
1243     /*
1244      * Reset the selection start and end points.
1245      */
1246     pi->sel_start = pi->sel_end = opi->sel_start = opi->sel_end = -1;
1247 }
1248
1249 static void
1250 fontgrid_draw_focus(GtkWidget *widget, GdkRectangle *area)
1251 {
1252     GdkGC *gc;
1253     gint x, y, wd, ht, fwidth, fpad;
1254
1255     /*
1256      * Do something with this later to make sure the focus line width
1257      * is set in the GC's.
1258      */
1259     gtk_widget_style_get(widget,
1260                          "focus-line-width", &fwidth,
1261                          "focus-padding", &fpad, NULL);
1262
1263     gc = widget->style->bg_gc[GTK_WIDGET_STATE(widget)];
1264
1265     x = (widget->style->xthickness + fwidth + fpad) - 1;
1266     y = (widget->style->ythickness + fwidth + fpad) - 1;
1267     wd = (widget->allocation.width - (x * 2));
1268     ht = (widget->allocation.height - (y * 2));
1269
1270     if (GTK_WIDGET_HAS_FOCUS(widget))
1271       gtk_paint_focus(widget->style, widget->window, GTK_WIDGET_STATE(widget),
1272                       area, widget, "fontgrid", x, y, wd, ht);
1273     else {
1274         gdk_gc_set_clip_rectangle(gc, area);
1275         gdk_draw_rectangle(widget->window, gc, FALSE, x, y, wd - 1, ht - 1);
1276         gdk_gc_set_clip_rectangle(gc, 0);
1277     }
1278 }
1279
1280 static gint
1281 fontgrid_expose(GtkWidget *widget, GdkEventExpose *event)
1282 {
1283     /*
1284      * Paint the shadow first.
1285      */
1286     if (GTK_WIDGET_DRAWABLE(widget))
1287       gtk_paint_shadow(widget->style, widget->window,
1288                        GTK_WIDGET_STATE(widget), GTK_SHADOW_OUT,
1289                        &event->area, widget, "fontgrid",
1290                        0, 0,
1291                        widget->allocation.width,
1292                        widget->allocation.height);
1293
1294     fontgrid_draw(widget, event->region);
1295
1296     fontgrid_draw_focus(widget, &event->area);
1297
1298     return FALSE;
1299 }
1300
1301 static gint
1302 fontgrid_focus_in(GtkWidget *widget, GdkEventFocus *event)
1303 {
1304     g_return_val_if_fail(widget != NULL, FALSE);
1305     g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1306     g_return_val_if_fail(event != NULL, FALSE);
1307
1308     GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1309     fontgrid_draw_focus(widget, 0);
1310
1311     return FALSE;
1312 }
1313
1314 static gint
1315 fontgrid_focus_out(GtkWidget *widget, GdkEventFocus *event)
1316 {
1317     g_return_val_if_fail(widget != NULL, FALSE);
1318     g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1319     g_return_val_if_fail(event != NULL, FALSE);
1320
1321     GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
1322     fontgrid_draw_focus(widget, 0);
1323
1324     return FALSE;
1325 }
1326
1327 static gint
1328 fontgrid_lose_selection(GtkWidget *widget, GdkEventSelection *event)
1329 {
1330     Fontgrid *fw;
1331     FontgridInternalPageInfo *pi;
1332     gint32 code;
1333
1334     fw = FONTGRID(widget);
1335
1336     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1337
1338     if (pi->sel_start != pi->sel_end) {
1339         code = pi->sel_start;
1340         fontgrid_deselect_all(fw);
1341         pi->sel_end = pi->sel_start = code;
1342         Select(pi->sel_start, pi->selmap);
1343         fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
1344     }
1345
1346     return TRUE;
1347 }
1348
1349 /**************************************************************************
1350  *
1351  * Paging routines.
1352  *
1353  **************************************************************************/
1354
1355 static void
1356 fontgrid_neighbor_pages(Fontgrid *fw, gint32 page, gint32 *prev, gint32 *next)
1357 {
1358     gint32 bcode, l, r, m;
1359     guint32 nglyphs;
1360     bdf_glyph_t *glyphs;
1361     FontgridInternalPageInfo *pip;
1362
1363     pip = (!fw->unencoded) ? &fw->npage : &fw->upage;
1364
1365     if (fw->noblanks == FALSE ||
1366         (fw->unencoded == FALSE &&
1367          (fw->font == 0 || fw->font->glyphs_used == 0))) {
1368         *prev = page - 1;
1369         *next = (page < pip->maxpage) ? page + 1 : -1;
1370         return;
1371     }
1372
1373     bcode = page * fw->pagesize;
1374
1375     if (!fw->unencoded) {
1376         glyphs = fw->font->glyphs;
1377         nglyphs = fw->font->glyphs_used;
1378     } else {
1379         glyphs = fw->font->unencoded;
1380         nglyphs = fw->font->unencoded_used;
1381     }
1382
1383     /*
1384      * Do a binary search to find the the preceding page number.
1385      */
1386     for (l = m = 0, r = nglyphs - 1; l < r; ) {
1387         m = (l + r) >> 1;
1388         if (glyphs[m].encoding < bcode)
1389           l = m + 1;
1390         else if (glyphs[m].encoding > bcode)
1391           r = m - 1;
1392         else {
1393             /*
1394              * Exact match.
1395              */
1396             l = r = m - 1;
1397             break;
1398         }
1399     }
1400
1401     /*
1402      * In case the search ends on a code in the specified page.
1403      */
1404     while (r >= 0 && glyphs[r].encoding >= bcode)
1405       r--;
1406
1407     /*
1408      * Set the previous page code.
1409      */
1410     *prev = (r >= 0) ? glyphs[r].encoding / fw->pagesize : -1;
1411
1412     /*
1413      * Determine the following page code.
1414      */
1415     if (r < 0)
1416       r = 0;
1417     while (r < nglyphs && glyphs[r].encoding < bcode + fw->pagesize)
1418       r++;
1419
1420     *next = (r < nglyphs) ? glyphs[r].encoding / fw->pagesize : -1;
1421 }
1422
1423 /**************************************************************************
1424  *
1425  * Selection routines.
1426  *
1427  **************************************************************************/
1428
1429 static void
1430 start_selection(GtkWidget *widget, GdkEventButton *event)
1431 {
1432     Fontgrid *fw;
1433     gint16 x, y, row, col;
1434     gint32 code;
1435     bdf_glyph_t *gp;
1436     FontgridInternalPageInfo *pi, *opi;
1437     FontgridSelectionInfo sinfo;
1438
1439     fw = FONTGRID(widget);
1440
1441     /*
1442      * Deal with the focus issue first.
1443      */
1444     if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1445         GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1446         (void) fontgrid_draw_focus(widget, NULL);
1447     }
1448
1449     x = (gint16) event->x;
1450     y = (gint16) event->y;
1451
1452     col = fw->xoff + (fw->cell_width * fw->cell_cols);
1453     row = fw->yoff + (fw->cell_height * fw->cell_rows);
1454
1455     /*
1456      * If the button press is not in the font grid proper, just return.
1457      */
1458     if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1459       return;
1460
1461     /*
1462      * Calculate the row and column that was clicked.
1463      */
1464     row = (y - fw->yoff) / fw->cell_height;
1465     col = (x - fw->xoff) / fw->cell_width;
1466
1467     if (!fw->unencoded) {
1468         pi = &fw->npage;
1469         opi = &fw->upage;
1470     } else {
1471         pi = &fw->upage;
1472         opi = &fw->npage;
1473     }
1474
1475     if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1476       code = pi->bcode + (row * fw->cell_cols) + col;
1477     else
1478       code = pi->bcode + (col * fw->cell_rows) + row;
1479
1480     /*
1481      * Any code greater than the maximum is ignored.
1482      */
1483     if (code > 0xffff)
1484       return;
1485
1486     gp = 0;
1487     if (fw->font) {
1488         if (!fw->unencoded)
1489           gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1490                                      code, TRUE);
1491         else
1492           gp = fontgrid_locate_glyph(fw->font->unencoded,
1493                                      fw->font->unencoded_used,
1494                                      code, TRUE);
1495     }
1496
1497     if (gp == 0) {
1498         empty_glyph.encoding = code;
1499         gp = &empty_glyph;
1500     }
1501
1502     if (code != pi->sel_start || code != pi->sel_end) {
1503         /*
1504          * Clear any existing selection.
1505          */
1506         if (pi->sel_start != -1 || pi->sel_end != -1 ||
1507             opi->sel_start != -1 || opi->sel_end != -1)
1508           fontgrid_deselect_all(fw);
1509
1510         Select(code, pi->selmap);
1511
1512         fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
1513
1514         pi->sel_start = pi->sel_end = code;
1515
1516         /*
1517          * Clear the last click time to avoid situations where the second
1518          * click on a different cell will cause the select callback to be
1519          * called.
1520          */
1521         fw->last_click = 0;
1522     }
1523
1524     sinfo.glyphs = gp;
1525     sinfo.num_glyphs = 1;
1526     sinfo.start = pi->sel_start;
1527     sinfo.end = pi->sel_end;
1528     sinfo.base = fw->base;
1529     sinfo.unencoded = fw->unencoded;
1530     if (event->type == GDK_BUTTON_PRESS &&
1531         event->time - fw->last_click >= fw->mclick_time) {
1532         sinfo.reason = FONTGRID_START_SELECTION;
1533         g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
1534                       &sinfo);
1535     } else if (event->type == GDK_2BUTTON_PRESS) {
1536         sinfo.reason = FONTGRID_ACTIVATE;
1537         g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
1538                       &sinfo);
1539     }
1540     fw->last_click = event->time;
1541 }
1542
1543 static void
1544 extend_selection(GtkWidget *widget, gint16 x, gint16 y)
1545 {
1546     Fontgrid *fw;
1547     gint16 row, col;
1548     gint32 code;
1549     bdf_glyph_t *gp;
1550     gboolean call_extend;
1551     FontgridInternalPageInfo *pi;
1552     FontgridSelectionInfo sinfo;
1553
1554     fw = FONTGRID(widget);
1555
1556     /*
1557      * Deal with the focus issue first.
1558      */
1559     if (!GTK_WIDGET_HAS_FOCUS(widget)) {
1560         GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
1561         (void) fontgrid_draw_focus(widget, NULL);
1562     }
1563
1564     col = fw->xoff + (fw->cell_width * fw->cell_cols);
1565     row = fw->yoff + (fw->cell_height * fw->cell_rows);
1566
1567     /*
1568      * If the button press is not in the font grid proper, just return.
1569      */
1570     if (x < fw->xoff || x >= col || y < fw->yoff || y >= row)
1571       return;
1572
1573     /*
1574      * Calculate the row and column that was clicked.
1575      */
1576     row = (y - fw->yoff) / fw->cell_height;
1577     col = (x - fw->xoff) / fw->cell_width;
1578
1579     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1580
1581     if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1582       code = pi->bcode + (row * fw->cell_cols) + col;
1583     else
1584       code = pi->bcode + (col * fw->cell_rows) + row;
1585
1586     /*
1587      * Any code greater than the maximum is ignored.
1588      */
1589     if (code > 0xffff)
1590       return;
1591
1592     gp = 0;
1593     if (fw->font) {
1594         if (!fw->unencoded)
1595           gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
1596                                      code, TRUE);
1597         else
1598           gp = fontgrid_locate_glyph(fw->font->unencoded,
1599                                      fw->font->unencoded_used,
1600                                      code, TRUE);
1601         if (gp == 0) {
1602             empty_glyph.encoding = code;
1603             gp = &empty_glyph;
1604         }
1605     }
1606
1607     call_extend = FALSE;
1608     if (code > pi->sel_end) {
1609         call_extend = TRUE;
1610         if (code <= pi->sel_start)
1611           fontgrid_deselect_range(fw, pi->sel_end, code - 1);
1612         else {
1613             if (pi->sel_end < pi->sel_start) {
1614                 fontgrid_deselect_range(fw, pi->sel_end, pi->sel_start - 1);
1615                 fontgrid_select_range(fw, pi->sel_start + 1, code);
1616             } else
1617               fontgrid_select_range(fw, pi->sel_end, code);
1618         }
1619     } else if (code < pi->sel_end) {
1620         call_extend = TRUE;
1621         if (code < pi->sel_start) {
1622             if (pi->sel_end > pi->sel_start) {
1623                 fontgrid_deselect_range(fw, pi->sel_start + 1, pi->sel_end);
1624                 fontgrid_select_range(fw, code, pi->sel_start);
1625             } else
1626               fontgrid_select_range(fw, code, pi->sel_end);
1627         } else
1628           fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1629     }
1630
1631     pi->sel_end = code;
1632
1633     if (call_extend == TRUE) {
1634         if (pi->sel_start == pi->sel_end) {
1635             sinfo.glyphs = gp;
1636             sinfo.num_glyphs = 1;
1637         } else {
1638             sinfo.glyphs = 0;
1639             sinfo.num_glyphs = 0;
1640         }
1641         sinfo.start = pi->sel_start;
1642         sinfo.end = pi->sel_end;
1643         sinfo.base = fw->base;
1644         sinfo.unencoded = fw->unencoded;
1645         sinfo.reason = FONTGRID_EXTEND_SELECTION;
1646         g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_EXTEND], 0,
1647                       &sinfo);
1648     }
1649 }
1650
1651 static void
1652 end_selection(GtkWidget *widget, GdkEventButton *event)
1653 {
1654     Fontgrid *fw;
1655     bdf_glyph_t *gp;
1656     FontgridInternalPageInfo *pi;
1657     FontgridSelectionInfo sinfo;
1658
1659     fw = FONTGRID(widget);
1660
1661     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
1662
1663     if (pi->sel_start != pi->sel_end) {
1664         /*
1665          * Assert ownership of the clipboard if there is a selection of
1666          * more than one glyph.
1667          */
1668         gdk_selection_owner_set(widget->window, FONTGRID_CLIPBOARD,
1669                                 GDK_CURRENT_TIME, FALSE);
1670         sinfo.glyphs = 0;
1671         sinfo.num_glyphs = 0;
1672     } else {
1673         gp = 0;
1674         if (fw->font) {
1675             if (!fw->unencoded)
1676               gp = fontgrid_locate_glyph(fw->font->glyphs,
1677                                          fw->font->glyphs_used,
1678                                          pi->sel_start, TRUE);
1679             else
1680               gp = fontgrid_locate_glyph(fw->font->unencoded,
1681                                          fw->font->unencoded_used,
1682                                          pi->sel_start, TRUE);
1683             if (gp == 0) {
1684                 empty_glyph.encoding = pi->sel_start;
1685                 gp = &empty_glyph;
1686             }
1687         }
1688
1689         sinfo.glyphs = gp;
1690         sinfo.num_glyphs = 1;
1691     }
1692     sinfo.start = pi->sel_start;
1693     sinfo.end = pi->sel_end;
1694     sinfo.base = fw->base;
1695     sinfo.unencoded = fw->unencoded;
1696     sinfo.reason = FONTGRID_END_SELECTION;
1697     g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_END], 0,
1698                   &sinfo);
1699 }
1700
1701 static void
1702 paste_selection(GtkWidget *widget, GdkEventButton *event)
1703 {
1704     start_selection(widget, event);
1705
1706     if (event->state & GDK_SHIFT_MASK)
1707       fontgrid_paste_selection(FONTGRID(widget), FONTGRID_INSERT_PASTE);
1708     else if (event->state & GDK_CONTROL_MASK)
1709       fontgrid_paste_selection(FONTGRID(widget), FONTGRID_MERGE_PASTE);
1710     else
1711       fontgrid_paste_selection(FONTGRID(widget), FONTGRID_NORMAL_PASTE);
1712 }
1713
1714 static void
1715 copy_selection(GtkWidget *widget, GdkEventButton *event)
1716 {
1717     fontgrid_copy_selection(FONTGRID(widget));
1718 }
1719
1720 /**************************************************************************
1721  *
1722  * Button, pointer motion, and keyboard handling routines.
1723  *
1724  **************************************************************************/
1725
1726 static gint
1727 fontgrid_button_press(GtkWidget *widget, GdkEventButton *event)
1728 {
1729     switch (event->button) {
1730       case 1:
1731         if (event->state & GDK_SHIFT_MASK)
1732           extend_selection(widget, (gint16) event->x, (gint16) event->y);
1733         else
1734           start_selection(widget, event);
1735         break;
1736       case 2: paste_selection(widget, event); break;
1737       case 3: copy_selection(widget, event); break;
1738     }
1739
1740     return FALSE;
1741 }
1742
1743 static gint
1744 fontgrid_button_release(GtkWidget *widget, GdkEventButton *event)
1745 {
1746     switch (event->button) {
1747       case 1: end_selection(widget, event); break;
1748       case 2: break;
1749       case 3: break;
1750     }
1751     return FALSE;
1752 }
1753
1754 static gint
1755 fontgrid_motion_notify(GtkWidget *widget, GdkEventMotion *event)
1756 {
1757     if (event->state & GDK_BUTTON1_MASK)
1758       extend_selection(widget, (gint16) event->x, (gint16) event->y);
1759 #if 0
1760     /*
1761      * Don't need these at the moment.
1762      */
1763     if (event->state & GDK_BUTTON2_MASK) {
1764     }
1765     if (event->state & GDK_BUTTON3_MASK) {
1766     }
1767 #endif
1768     return FALSE;
1769 }
1770
1771 static gint
1772 fontgrid_shift_key_press(GtkWidget *widget, GdkEventKey *event)
1773 {
1774     Fontgrid *fw;
1775     bdf_glyph_t *gp;
1776     guint keyval;
1777     gint32 code, pageno;
1778     guint32 count;
1779     gboolean signal_extend, activate;
1780     FontgridInternalPageInfo *pi, *opi;
1781     FontgridSelectionInfo sinfo;
1782
1783     g_return_val_if_fail(widget != NULL, FALSE);
1784     g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
1785     g_return_val_if_fail(event != NULL, FALSE);
1786
1787     fw = FONTGRID(widget);
1788
1789     /*
1790      * For number keys, use them to add up a count that will effect the
1791      * behavior of the other keys.
1792      */
1793     if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
1794         fw->count = (fw->count * 10) + (event->keyval - GDK_0);
1795         return FALSE;
1796     }
1797
1798     if (!fw->unencoded) {
1799         pi = &fw->npage;
1800         opi = &fw->upage;
1801         gp = (fw->font && fw->font->glyphs_used) ?
1802             (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
1803     } else {
1804         pi = &fw->upage;
1805         opi = &fw->npage;
1806         gp = (fw->font && fw->font->unencoded_used) ?
1807             (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
1808     }
1809
1810     activate = FALSE;
1811
1812     code = pi->sel_end;
1813
1814     if ((count = fw->count) == 0)
1815       count = 1;
1816
1817     keyval = event->keyval;
1818     switch (event->keyval) {
1819       case GDK_Page_Up:
1820       case GDK_KP_Page_Up:
1821         count *= fw->pagesize;
1822         keyval = GDK_Left;
1823         break;
1824       case GDK_Page_Down:
1825       case GDK_KP_Page_Down:
1826         count *= fw->pagesize;
1827         keyval = GDK_Right;
1828         break;
1829       case GDK_Home:
1830       case GDK_KP_Home:
1831         count = (pi->pageno - pi->minpage) * fw->pagesize;
1832         keyval = GDK_Left;
1833         break;
1834       case GDK_End:
1835       case GDK_KP_End:
1836         count = (pi->maxpage - pi->pageno) * fw->pagesize;
1837         keyval = GDK_Right;
1838         break;
1839     }
1840
1841     switch (keyval) {
1842       case GDK_Left:
1843       case GDK_KP_Left:
1844         if (code == 0) {
1845             gdk_beep();
1846             return TRUE;
1847         }
1848
1849         if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1850           code -= (fw->cell_rows * count);
1851         else
1852           code -= count;
1853
1854         if (code < 0)
1855           code = 0;
1856
1857         break;
1858       case GDK_Right:
1859       case GDK_KP_Right:
1860         /*
1861          * Make sure that when on the unencoded pages, the final glyph is
1862          * the limit unlike the encoded pages where the max value is 0xffff.
1863          */
1864         if ((fw->unencoded &&
1865              (gp == 0 || code == gp->encoding)) ||
1866             code == 0xffff) {
1867             gdk_beep();
1868             return TRUE;
1869         }
1870
1871         if (fw->orientation == GTK_ORIENTATION_VERTICAL)
1872           code += (fw->cell_rows * count);
1873         else
1874           code += count;
1875
1876         if (fw->unencoded && code > gp->encoding)
1877           code = gp->encoding;
1878         else if (code > 0xffff)
1879           code = 0xffff;
1880
1881         break;
1882       case GDK_Up:
1883       case GDK_KP_Up:
1884         if (code == 0) {
1885             gdk_beep();
1886             return TRUE;
1887         }
1888
1889         if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1890           code -= (fw->cell_cols * count);
1891         else
1892           code -= count;
1893
1894         if (code < 0)
1895           code = 0;
1896
1897         break;
1898       case GDK_Down:
1899       case GDK_KP_Down:
1900         /*
1901          * Make sure that when on the unencoded pages, the final glyph is
1902          * the limit unlike the encoded pages where the max value is 0xffff.
1903          */
1904         if ((fw->unencoded &&
1905              (gp == 0 || code == gp->encoding)) ||
1906             code == 0xffff) {
1907             gdk_beep();
1908             return TRUE;
1909         }
1910
1911         if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
1912           code += (fw->cell_cols * count);
1913         else
1914           code += count;
1915
1916         if (fw->unencoded && code > gp->encoding)
1917           code = gp->encoding;
1918         else if (code > 0xffff)
1919           code = 0xffff;
1920
1921         break;
1922       case GDK_Return:
1923       case GDK_KP_Enter:
1924         pi->sel_end = pi->sel_start;
1925         activate = TRUE;
1926         break;
1927       default:
1928         return FALSE;
1929     }
1930
1931     signal_extend = FALSE;
1932     if (code > pi->sel_end) {
1933         signal_extend = TRUE;
1934         if (code <= pi->sel_start)
1935           fontgrid_deselect_range(fw, pi->sel_end, code - 1);
1936         else {
1937             if (pi->sel_end < pi->sel_start) {
1938                 fontgrid_deselect_range(fw, pi->sel_end, pi->sel_start - 1);
1939                 fontgrid_select_range(fw, pi->sel_start + 1, code);
1940             } else
1941               fontgrid_select_range(fw, pi->sel_end, code);
1942         }
1943     } else if (code < pi->sel_end) {
1944         signal_extend = TRUE;
1945         if (code < pi->sel_start) {
1946             if (pi->sel_end > pi->sel_start) {
1947                 fontgrid_deselect_range(fw, pi->sel_start + 1, pi->sel_end);
1948                 fontgrid_select_range(fw, code, pi->sel_start);
1949             } else
1950               fontgrid_select_range(fw, code, pi->sel_end);
1951         } else
1952           fontgrid_deselect_range(fw, code + 1, pi->sel_end);
1953     }
1954
1955     pi->sel_end = code;
1956
1957     /*
1958      * If the selection endpoint is on some page other than the current
1959      * page, make sure the page holding the end point is made visible.
1960      */
1961     pageno = code / fw->pagesize;
1962     if (pageno != pi->pageno) {
1963         fw->no_sel_callback = TRUE;
1964         fontgrid_goto_page(fw, pageno);
1965     }
1966
1967     /*
1968      * Reset the count.
1969      */
1970     fw->count = 0;
1971
1972     if (signal_extend) {
1973         if (pi->sel_start == pi->sel_end) {
1974             /*
1975              * Set up and emit the selection start signal.
1976              */
1977             if (!fw->unencoded)
1978               gp = fontgrid_locate_glyph(fw->font->glyphs,
1979                                          fw->font->glyphs_used,
1980                                          code, TRUE);
1981             else
1982               gp = fontgrid_locate_glyph(fw->font->unencoded,
1983                                          fw->font->unencoded_used,
1984                                          code, TRUE);
1985             if (gp == 0) {
1986                 empty_glyph.encoding = code;
1987                 gp = &empty_glyph;
1988             }
1989             sinfo.glyphs = gp;
1990             sinfo.num_glyphs = 1;
1991         } else {
1992             sinfo.glyphs = 0;
1993             sinfo.num_glyphs = 0;
1994         }
1995         sinfo.start = pi->sel_start;
1996         sinfo.end = pi->sel_end;
1997         sinfo.base = fw->base;
1998         sinfo.unencoded = fw->unencoded;
1999
2000         if (!activate) {
2001             sinfo.reason = FONTGRID_EXTEND_SELECTION;
2002             g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_EXTEND],
2003                           0, &sinfo);
2004         } else {
2005             sinfo.reason = FONTGRID_ACTIVATE;
2006             g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0,
2007                           &sinfo);
2008         }
2009     }
2010
2011     return TRUE;
2012 }
2013
2014 static gint
2015 fontgrid_key_press(GtkWidget *widget, GdkEventKey *event)
2016 {
2017     Fontgrid *fw;
2018     bdf_glyph_t *gp;
2019     gint32 code, pageno;
2020     guint32 count;
2021     gboolean activate;
2022     FontgridInternalPageInfo *pi, *opi;
2023     FontgridSelectionInfo sinfo;
2024
2025     g_return_val_if_fail(widget != NULL, FALSE);
2026     g_return_val_if_fail(IS_FONTGRID(widget), FALSE);
2027     g_return_val_if_fail(event != NULL, FALSE);
2028
2029     if (event->state & GDK_SHIFT_MASK)
2030       return fontgrid_shift_key_press(widget, event);
2031
2032     fw = FONTGRID(widget);
2033
2034     /*
2035      * For number keys, use them to add up a count that will effect the
2036      * behavior of the other keys.
2037      */
2038     if (event->keyval >= GDK_0 && event->keyval <= GDK_9) {
2039         fw->count = (fw->count * 10) + (event->keyval - GDK_0);
2040         return FALSE;
2041     }
2042
2043     if (!fw->unencoded) {
2044         pi = &fw->npage;
2045         opi = &fw->upage;
2046         gp = (fw->font && fw->font->glyphs_used) ?
2047             (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
2048     } else {
2049         pi = &fw->upage;
2050         opi = &fw->npage;
2051         gp = (fw->font && fw->font->unencoded_used) ?
2052             (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
2053     }
2054
2055     activate = FALSE;
2056
2057     code = pi->sel_start;
2058
2059     if ((count = fw->count) == 0)
2060       count = 1;
2061
2062     switch (event->keyval) {
2063       case GDK_Left:
2064       case GDK_KP_Left:
2065         if (code == 0) {
2066             gdk_beep();
2067             return TRUE;
2068         }
2069
2070         if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2071           code -= (fw->cell_rows * count);
2072         else
2073           code -= count;
2074
2075         if (code < 0)
2076           code = 0;
2077
2078         break;
2079       case GDK_Right:
2080       case GDK_KP_Right:
2081         /*
2082          * Make sure that when on the unencoded pages, the final glyph is
2083          * the limit unlike the encoded pages where the max value is 0xffff.
2084          */
2085         if ((fw->unencoded &&
2086              (gp == 0 || code == gp->encoding)) ||
2087             code == 0xffff) {
2088             gdk_beep();
2089             return TRUE;
2090         }
2091
2092         if (fw->orientation == GTK_ORIENTATION_VERTICAL)
2093           code += (fw->cell_rows * count);
2094         else
2095           code += count;
2096
2097         if (fw->unencoded && code > gp->encoding)
2098           code = gp->encoding;
2099         else if (code > 0xffff)
2100           code = 0xffff;
2101
2102         break;
2103       case GDK_Up:
2104       case GDK_KP_Up:
2105         if (code == 0) {
2106             gdk_beep();
2107             return TRUE;
2108         }
2109
2110         if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2111           code -= (fw->cell_cols * count);
2112         else
2113           code -= count;
2114
2115         if (code < 0)
2116           code = 0;
2117
2118         break;
2119       case GDK_Down:
2120       case GDK_KP_Down:
2121         /*
2122          * Make sure that when on the unencoded pages, the final glyph is
2123          * the limit unlike the encoded pages where the max value is 0xffff.
2124          */
2125         if ((fw->unencoded &&
2126              (gp == 0 || code == gp->encoding)) ||
2127             code == 0xffff) {
2128             gdk_beep();
2129             return TRUE;
2130         }
2131
2132         if (fw->orientation == GTK_ORIENTATION_HORIZONTAL)
2133           code += (fw->cell_cols * count);
2134         else
2135           code += count;
2136
2137         if (fw->unencoded && code > gp->encoding)
2138           code = gp->encoding;
2139         else if (code > 0xffff)
2140           code = 0xffff;
2141
2142         break;
2143       case GDK_Page_Up:
2144       case GDK_KP_Page_Up:
2145         fw->from_keyboard = TRUE;
2146         fontgrid_goto_previous_page(fw);
2147         return TRUE;
2148         break;
2149       case GDK_Page_Down:
2150       case GDK_KP_Page_Down:
2151         fw->from_keyboard = TRUE;
2152         fontgrid_goto_next_page(fw);
2153         return TRUE;
2154         break;
2155       case GDK_Home:
2156       case GDK_KP_Home:
2157         fw->from_keyboard = TRUE;
2158         fontgrid_goto_first_page(fw);
2159         return TRUE;
2160         break;
2161       case GDK_End:
2162       case GDK_KP_End:
2163         fw->from_keyboard = TRUE;
2164         fontgrid_goto_last_page(fw);
2165         return TRUE;
2166         break;
2167       case GDK_Return:
2168       case GDK_KP_Enter:
2169         pi->sel_end = pi->sel_start;
2170         activate = TRUE;
2171         break;
2172       case GDK_BackSpace:
2173       case GDK_Delete:
2174       case GDK_KP_Delete:
2175         fontgrid_cut_selection(fw);
2176         return TRUE;
2177       default:
2178         return FALSE;
2179     }
2180
2181     /*
2182      * This turns off the selection which means the cursor is effectively
2183      * turned off even for the fontgrid_goto_page() call.  The reason is that
2184      * for keyboard navigation, the cursor should move up and down by rows and
2185      * not whole pages when a page change occurs.
2186      */
2187     fontgrid_deselect_all(fw);
2188
2189     pageno = code / fw->pagesize;
2190     if (pageno != pi->pageno) {
2191         fw->no_sel_callback = TRUE;
2192         fontgrid_goto_page(fw, pageno);
2193     }
2194
2195     pi->sel_start = pi->sel_end = code;
2196     Select(code, pi->selmap);
2197     fontgrid_draw_cells(widget, code, code, FALSE, TRUE);
2198
2199     /*
2200      * Reset the count.
2201      */
2202     fw->count = 0;
2203
2204     /*
2205      * Set up and emit the selection start signal.
2206      */
2207     if (!fw->unencoded)
2208       gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
2209                                  code, TRUE);
2210     else
2211       gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
2212                                  code, TRUE);
2213     if (gp == 0) {
2214         empty_glyph.encoding = code;
2215         gp = &empty_glyph;
2216     }
2217     sinfo.glyphs = gp;
2218     sinfo.num_glyphs = 1;
2219     sinfo.start = pi->sel_start;
2220     sinfo.end = pi->sel_end;
2221     sinfo.base = fw->base;
2222     sinfo.unencoded = fw->unencoded;
2223
2224     if (!activate) {
2225         sinfo.reason = FONTGRID_START_SELECTION;
2226         g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
2227                       &sinfo);
2228     } else {
2229         sinfo.reason = FONTGRID_ACTIVATE;
2230         g_signal_emit(G_OBJECT(fw), fontgrid_signals[ACTIVATE], 0, &sinfo);
2231     }
2232
2233     return TRUE;
2234 }
2235
2236 /**************************************************************************
2237  *
2238  * Class and instance setup.
2239  *
2240  **************************************************************************/
2241
2242 static void
2243 fontgrid_class_init(gpointer g_class, gpointer class_data)
2244 {
2245     GObjectClass *gocp = G_OBJECT_CLASS(g_class);
2246     GtkObjectClass *ocp = GTK_OBJECT_CLASS(g_class);
2247     GtkWidgetClass *wcp = GTK_WIDGET_CLASS(g_class);
2248
2249     /*
2250      * Set the class global variables.
2251      */
2252     parent_class = g_type_class_peek_parent(g_class);
2253
2254     /*
2255      * GObject class functions.
2256      */
2257     gocp->set_property = fontgrid_set_property;
2258     gocp->get_property = fontgrid_get_property;
2259     gocp->finalize = fontgrid_finalize;
2260
2261     /*
2262      * GtkObjectClass functions.
2263      */
2264     ocp->destroy = fontgrid_destroy;
2265
2266     /*
2267      * Instance functions.
2268      */
2269     wcp->size_request = fontgrid_preferred_size;
2270     wcp->size_allocate = fontgrid_actual_size;
2271     wcp->realize = fontgrid_realize;
2272     wcp->expose_event = fontgrid_expose;
2273     wcp->focus_in_event = fontgrid_focus_in;
2274     wcp->focus_out_event = fontgrid_focus_out;
2275     wcp->button_press_event = fontgrid_button_press;
2276     wcp->button_release_event = fontgrid_button_release;
2277     wcp->motion_notify_event = fontgrid_motion_notify;
2278     wcp->key_press_event = fontgrid_key_press;
2279     wcp->selection_clear_event = fontgrid_lose_selection;
2280
2281     /*
2282      * Add parameters (a.k.a. resource) types.
2283      */
2284     g_object_class_install_property(gocp, PROP_CODE_BASE,
2285                                     g_param_spec_uint("codeBase",
2286                                                       _("Code base"),
2287                                                       _("Override for the code base (oct, dec, hex) for glyph codes."),
2288                                                       8,
2289                                                       16,
2290                                                       16,
2291                                                       G_PARAM_READWRITE));
2292     g_object_class_install_property(gocp, PROP_POWER2,
2293                                     g_param_spec_boolean("powersOfTwo",
2294                                                          _("Powers of two"),
2295                                                          _("Indicate whether the grid display should be a power-of-two rows."),
2296                                                          TRUE,
2297                                                          G_PARAM_READWRITE));
2298
2299     g_object_class_install_property(gocp, PROP_ORIENTATION,
2300                                     g_param_spec_enum("orientation",
2301                                                       _("Orientation"),
2302                                                       _("Should the grid display vertically or horizontally."),
2303                                                       GTK_TYPE_ORIENTATION,
2304                                                       GTK_ORIENTATION_HORIZONTAL,
2305                                                       G_PARAM_READWRITE));
2306
2307     g_object_class_install_property(gocp, PROP_FONT,
2308                                     g_param_spec_pointer("font",
2309                                                          _("Font"),
2310                                                          _("Font to be displayed."),
2311                                                          G_PARAM_READWRITE));
2312
2313     g_object_class_install_property(gocp, PROP_POINT_SIZE,
2314                                     g_param_spec_uint("pointSize",
2315                                                        _("Point size"),
2316                                                        _("Set the default point size for new fonts."),
2317                                                        2,
2318                                                        256,
2319                                                        12,
2320                                                        G_PARAM_READWRITE));
2321
2322     g_object_class_install_property(gocp, PROP_SPACING,
2323                                     g_param_spec_int("spacing",
2324                                                      _("Spacing"),
2325                                                      _("Set the default glyph spacing."),
2326                                                        BDF_PROPORTIONAL,
2327                                                        BDF_CHARCELL,
2328                                                        BDF_PROPORTIONAL,
2329                                                        G_PARAM_READWRITE));
2330
2331     g_object_class_install_property(gocp, PROP_SKIP_BLANKS,
2332                                     g_param_spec_boolean("skipBlankPages",
2333                                                          _("Skip blank pages"),
2334                                                          _("Avoid displaying pages with no glyphs."),
2335                                                          TRUE,
2336                                                          G_PARAM_READWRITE));
2337
2338     g_object_class_install_property(gocp, PROP_OVERWRITE,
2339                                     g_param_spec_boolean("overwriteMode",
2340                                                          _("Overwrite mode"),
2341                                                          _("Pasting the selection overwrites."),
2342                                                          TRUE,
2343                                                          G_PARAM_READWRITE));
2344
2345     g_object_class_install_property(gocp, PROP_COLORS,
2346                                     g_param_spec_pointer("colorList",
2347                                                          _("Color list"),
2348                                                          _("Colors to be used for glyphs having bits-per-pixel > 1."),
2349                                                          G_PARAM_READWRITE));
2350
2351     g_object_class_install_property(gocp, PROP_INITIAL_GLYPH,
2352                                     g_param_spec_int("initialGlyph",
2353                                                       _("Initial glyph"),
2354                                                       _("Code of the glyph to be displayed first."),
2355                                                       -1,
2356                                                       0xffff,
2357                                                       -1,
2358                                                       G_PARAM_READWRITE));
2359
2360     g_object_class_install_property(gocp, PROP_BPP,
2361                                     g_param_spec_int("bitsPerPixel",
2362                                                       _("Bits per pixel"),
2363                                                       _("Number of bits per pixel for grayscale glyphs."),
2364                                                       1,
2365                                                       4,
2366                                                       1,
2367                                                       G_PARAM_READWRITE));
2368
2369     g_object_class_install_property(gocp, PROP_HRES,
2370                                     g_param_spec_int("horizontalResolution",
2371                                                       _("Horizontal resolution"),
2372                                                       _("Set the default horizontal resolution for new fonts."),
2373                                                       1,
2374                                                       2400,
2375                                                       100,
2376                                                       G_PARAM_READWRITE));
2377
2378     g_object_class_install_property(gocp, PROP_VRES,
2379                                     g_param_spec_int("verticalResolution",
2380                                                       _("Vertical resolution"),
2381                                                       _("Set the default vertical resolution for new fonts."),
2382                                                       1,
2383                                                       2400,
2384                                                       100,
2385                                                       G_PARAM_READWRITE));
2386
2387     /*
2388      * Add the signals these objects emit.
2389      */
2390     fontgrid_signals[SELECTION_START] =
2391         g_signal_new("selection-start",
2392                      G_TYPE_FROM_CLASS(gocp),
2393                      G_SIGNAL_RUN_FIRST,
2394                      G_STRUCT_OFFSET(FontgridClass, selection_start),
2395                      NULL, NULL,
2396                      g_cclosure_marshal_VOID__POINTER,
2397                      G_TYPE_NONE,
2398                      1,
2399                      G_TYPE_POINTER);
2400     fontgrid_signals[SELECTION_EXTEND] =
2401         g_signal_new("selection-extend",
2402                      G_TYPE_FROM_CLASS(gocp),
2403                      G_SIGNAL_RUN_FIRST,
2404                      G_STRUCT_OFFSET(FontgridClass, selection_extend),
2405                      NULL, NULL,
2406                      g_cclosure_marshal_VOID__POINTER,
2407                      G_TYPE_NONE,
2408                      1,
2409                      G_TYPE_POINTER);
2410     fontgrid_signals[SELECTION_END] =
2411         g_signal_new("selection-end",
2412                      G_TYPE_FROM_CLASS(gocp),
2413                      G_SIGNAL_RUN_FIRST,
2414                      G_STRUCT_OFFSET(FontgridClass, selection_end),
2415                      NULL, NULL,
2416                      g_cclosure_marshal_VOID__POINTER,
2417                      G_TYPE_NONE,
2418                      1,
2419                      G_TYPE_POINTER);
2420     fontgrid_signals[ACTIVATE] =
2421         g_signal_new("activate",
2422                      G_TYPE_FROM_CLASS(gocp),
2423                      G_SIGNAL_RUN_FIRST,
2424                      G_STRUCT_OFFSET(FontgridClass, activate),
2425                      NULL, NULL,
2426                      g_cclosure_marshal_VOID__POINTER,
2427                      G_TYPE_NONE,
2428                      1,
2429                      G_TYPE_POINTER);
2430     fontgrid_signals[MODIFIED] =
2431         g_signal_new("modified",
2432                      G_TYPE_FROM_CLASS(gocp),
2433                      G_SIGNAL_RUN_FIRST,
2434                      G_STRUCT_OFFSET(FontgridClass, modified),
2435                      NULL, NULL,
2436                      g_cclosure_marshal_VOID__POINTER,
2437                      G_TYPE_NONE,
2438                      1,
2439                      G_TYPE_POINTER);
2440     fontgrid_signals[TURN_TO_PAGE] =
2441         g_signal_new("turn_to_page",
2442                      G_TYPE_FROM_CLASS(gocp),
2443                      G_SIGNAL_RUN_FIRST,
2444                      G_STRUCT_OFFSET(FontgridClass, page),
2445                      NULL, NULL,
2446                      g_cclosure_marshal_VOID__POINTER,
2447                      G_TYPE_NONE,
2448                      1,
2449                      G_TYPE_POINTER);
2450 }
2451
2452 static void
2453 fontgrid_init(GTypeInstance *obj, gpointer g_class)
2454 {
2455     Fontgrid *fw = FONTGRID(obj);
2456     FontgridInternalPageInfo *pi;
2457     GdkScreen *screen;
2458     gint fwidth, fpad;
2459
2460     GTK_WIDGET_SET_FLAGS(fw, GTK_CAN_FOCUS);
2461
2462     gtk_widget_style_get(GTK_WIDGET(fw),
2463                          "focus-line-width", &fwidth,
2464                          "focus-padding", &fpad,
2465                          NULL);
2466
2467     fw->base = 16;
2468     fw->power2 = TRUE;
2469     fw->overwrite = TRUE;
2470     fw->noblanks = TRUE;
2471     fw->orientation = GTK_ORIENTATION_HORIZONTAL;
2472     fw->point_size = 12;
2473     fw->spacing = BDF_CHARCELL;
2474     fw->colors = 0;
2475     fw->initial_glyph = 0;
2476     fw->bpp = 1;
2477
2478     screen =
2479         gdk_drawable_get_screen(GDK_DRAWABLE(gdk_get_default_root_window()));
2480     fw->hres = (gint32) ((((double) gdk_screen_get_width(screen)) * 25.4) /
2481                          ((double) gdk_screen_get_width_mm(screen)) + 0.5);
2482     fw->vres = (gint32) ((((double) gdk_screen_get_height(screen)) * 25.4) /
2483                          ((double) gdk_screen_get_height_mm(screen)) + 0.5);
2484
2485     fw->cell_rows = FGRID_DEFAULT_ROWS;
2486     fw->cell_cols = FGRID_DEFAULT_COLS;
2487     fw->border = 4;
2488     fw->hmargin = fw->widget.style->xthickness + fwidth + fpad + fw->border;
2489     fw->vmargin = fw->widget.style->ythickness + fwidth + fpad + fw->border;
2490
2491     fontgrid_set_cell_geometry(fw);
2492     fontgrid_set_rows_cols(fw, 0);
2493
2494     /*
2495      * Private variables.
2496      */
2497     fw->unencoded = FALSE;
2498     fw->debug = FALSE;
2499     fw->xor_gc = 0;
2500     fw->points_used = 0;
2501     fw->points_size = 0;
2502     fw->rgb_used = 0;
2503     fw->rgb_size = 0;
2504
2505     fw->last_click = 0;
2506     fw->mclick_time = 0;
2507
2508     fw->count = 0;
2509     memset((char *) &fw->clipboard, 0, sizeof(bdf_glyphlist_t));
2510
2511     /*
2512      * Initialize the page information.
2513      */
2514     pi = &fw->upage;
2515     pi->minpage = 0;
2516     pi->maxpage = 0xffff / fw->pagesize;
2517     pi->npage = pi->ppage = -1;
2518     pi->pageno = pi->bcode = 0;
2519     pi->sel_start = pi->sel_end = -1;
2520     (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2521     pi = &fw->npage;
2522     pi->minpage = 0;
2523     pi->maxpage = 0xffff / fw->pagesize;
2524     pi->npage = pi->ppage = -1;
2525     pi->pageno = pi->bcode = 0;
2526     pi->sel_start = pi->sel_end = -1;
2527     (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2528 }
2529
2530 /**************************************************************************
2531  *
2532  * API.
2533  *
2534  **************************************************************************/
2535
2536 /*
2537  * Type instantiation routines.
2538  */
2539 GType
2540 fontgrid_get_type(void)
2541 {
2542     static GType fontgrid_type = 0;
2543
2544     if (!fontgrid_type) {
2545         static const GTypeInfo fontgrid_info = {
2546             sizeof (FontgridClass),             /* class_size           */
2547             0,                                  /* base_init            */
2548             0,                                  /* base_finalize        */
2549             fontgrid_class_init,                /* class_init           */
2550             0,                                  /* class_finalize       */
2551             0,                                  /* class_data           */
2552             sizeof(Fontgrid),                   /* instance_size        */
2553             0,                                  /* n_preallocs          */
2554             fontgrid_init,                      /* instance_init        */
2555             0,                                  /* value_table          */
2556         };
2557         fontgrid_type = g_type_register_static(GTK_TYPE_WIDGET,
2558                                                "Fontgrid", &fontgrid_info, 0);
2559     }
2560
2561     return fontgrid_type;
2562 }
2563
2564 GtkWidget *
2565 fontgrid_new(const gchar *prop1, ...)
2566 {
2567     GtkWidget *w;
2568     va_list var_args;
2569
2570     va_start(var_args, prop1);
2571     w = GTK_WIDGET(g_object_new_valist(fontgrid_get_type(), prop1, var_args));
2572     va_end(var_args);
2573
2574     return w;
2575 }
2576
2577 GtkWidget *
2578 fontgrid_newv(bdf_font_t *font, guint32 pointSize, gint32 spacing,
2579               gboolean skipBlankPages, gboolean overwriteMode,
2580               gboolean powersOfTwo, guint16 *colorList, gint32 initialGlyph,
2581               guint codeBase, GtkOrientation orientation,
2582               gint32 bitsPerPixel, gint32 horizontalResolution,
2583               gint32 verticalResolution, FontgridPageInfo *initialPageInfo)
2584 {
2585     Fontgrid *fw = FONTGRID(g_object_new(fontgrid_get_type(), NULL));
2586     gint32 i, boundary;
2587     FontgridInternalPageInfo *pi;
2588
2589     fw->font = font;
2590     fw->point_size = pointSize;
2591     fw->spacing = spacing;
2592     fw->colors = colorList;
2593     fw->noblanks = skipBlankPages;
2594     fw->overwrite = overwriteMode;
2595     fw->power2 = powersOfTwo;
2596     fw->initial_glyph = initialGlyph;
2597     fw->base = codeBase;
2598     fw->orientation = orientation;
2599     fw->bpp = (font) ? font->bpp : bitsPerPixel;
2600     fw->hres = horizontalResolution;
2601     fw->vres = verticalResolution;
2602
2603     /*
2604      * If no font has been provided, make sure a default is created.
2605      * Too many other things depend on a font existing.
2606      */
2607     if (font == 0) {
2608         fw->font = bdf_new_font(0, fw->point_size, fw->hres, fw->vres,
2609                                 fw->spacing, fw->bpp);
2610         if (fw->font->name == 0)
2611           fw->font->name = bdf_make_xlfd_name(fw->font, g_get_prgname(),
2612                                               "Unknown");
2613     }
2614
2615     fontgrid_set_cell_geometry(fw);
2616     fontgrid_set_rows_cols(fw, 0);
2617
2618     /*
2619      * Initialize the page information.
2620      */
2621     pi = &fw->upage;
2622     pi->minpage = 0;
2623     pi->maxpage = 0xffff / fw->pagesize;
2624     pi->npage = pi->ppage = -1;
2625     pi->pageno = pi->bcode = 0;
2626     pi->sel_start = pi->sel_end = -1;
2627     (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2628     pi = &fw->npage;
2629     pi->minpage = 0;
2630     pi->maxpage = 0xffff / fw->pagesize;
2631     pi->npage = pi->ppage = -1;
2632     pi->pageno = pi->bcode = 0;
2633     pi->sel_start = pi->sel_end = -1;
2634     (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2635
2636     /*
2637      * Determine the page info from the initial glyph setting.
2638      */
2639     if (font != 0) {
2640         if (fw->initial_glyph == -1)
2641           fw->initial_glyph = (font->glyphs_used > 0) ?
2642               font->glyphs->encoding : 0;
2643
2644         pi = &fw->npage;
2645         pi->pageno = fw->initial_glyph / fw->pagesize;
2646         pi->bcode = pi->pageno * fw->pagesize;
2647         pi->sel_start = pi->sel_end = fw->initial_glyph;
2648         Select(fw->initial_glyph, pi->selmap);
2649         fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
2650
2651         /*
2652          * Set the min/max page numbers for the encoded glyphs.
2653          */
2654         if (font->glyphs_used > 0) {
2655             if (fw->noblanks) {
2656                 pi->minpage = font->glyphs->encoding / fw->pagesize;
2657                 pi->maxpage =
2658                     font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2659             } else {
2660                 pi->minpage = 0;
2661                 pi->maxpage = 0xffff / fw->pagesize;
2662             }
2663         }
2664
2665         /*
2666          * Set the min/max page numbers for the unencoded glyphs.
2667          */
2668         if (font->unencoded_used > 0) {
2669             pi = &fw->upage;
2670
2671             if (fw->noblanks) {
2672                 pi->pageno = pi->minpage =
2673                     font->glyphs->encoding / fw->pagesize;
2674                 pi->maxpage =
2675                     font->unencoded[font->unencoded_used-1].encoding /
2676                     fw->pagesize;
2677                 pi->bcode = pi->pageno * fw->pagesize;
2678                 pi->ppage = -1;
2679
2680                 /*
2681                  * Lower boundary for the next page.
2682                  */
2683                 boundary = pi->bcode + fw->pagesize;
2684                 for (i = 0; i < font->unencoded_used &&
2685                          font->unencoded[i].encoding < boundary; i++) ;
2686                 pi->npage = (i == font->unencoded_used) ?
2687                     -1 : font->unencoded[i].encoding / fw->pagesize;
2688                   
2689             } else {
2690                 pi->pageno = pi->minpage = 0;
2691                 pi->maxpage = 0xffff / fw->pagesize;
2692                 pi->ppage = -1;
2693                 pi->npage = pi->pageno + 1;
2694             }
2695         }
2696     }
2697
2698     /*
2699      * Provide the initial page info the calling application will need
2700      * to set up the page changing labels.
2701      */
2702     initialPageInfo->unencoded_page = fw->unencoded;
2703     initialPageInfo->encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
2704     initialPageInfo->unencoded_glyphs =
2705         (fw->font) ? fw->font->unencoded_used : 0;
2706
2707     if (!fw->unencoded) {
2708         initialPageInfo->previous_page = fw->npage.ppage;
2709         initialPageInfo->current_page = fw->npage.pageno;
2710         initialPageInfo->next_page = fw->npage.npage;
2711     } else {
2712         initialPageInfo->previous_page = fw->upage.ppage;
2713         initialPageInfo->current_page = fw->upage.pageno;
2714         initialPageInfo->next_page = fw->upage.npage;
2715     }
2716
2717     return GTK_WIDGET(fw);
2718 }
2719
2720 gboolean
2721 fontgrid_has_selection(Fontgrid *fw, FontgridSelectionInfo *sinfo)
2722 {
2723     FontgridInternalPageInfo *pi;
2724
2725     g_return_val_if_fail(fw != 0, FALSE);
2726
2727     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
2728
2729     /*
2730      * Set up the selection info to alert the application that the
2731      * base changed.
2732      */
2733     if (sinfo != 0) {
2734         /*
2735          * Initialize the selection info structure.
2736          */
2737         (void) memset((char *) sinfo, 0, sizeof(FontgridSelectionInfo));
2738
2739         if (pi->sel_start == pi->sel_end) {
2740             if (fw->font) {
2741                 if (!fw->unencoded)
2742                   sinfo->glyphs =
2743                       fontgrid_locate_glyph(fw->font->glyphs,
2744                                             fw->font->glyphs_used,
2745                                             pi->sel_start, TRUE);
2746                 else
2747                   sinfo->glyphs =
2748                       fontgrid_locate_glyph(fw->font->unencoded,
2749                                             fw->font->unencoded_used,
2750                                             pi->sel_start, TRUE);
2751                 if (sinfo->glyphs == 0) {
2752                     empty_glyph.encoding = pi->sel_start;
2753                     sinfo->glyphs = &empty_glyph;
2754                 }
2755                 sinfo->num_glyphs = 1;
2756             }
2757         } else {
2758             sinfo->glyphs = 0;
2759             sinfo->num_glyphs = 0;
2760         }
2761
2762         sinfo->start = pi->sel_start;
2763         sinfo->end = pi->sel_end;
2764         sinfo->base = fw->base;
2765         sinfo->unencoded = fw->unencoded;
2766         sinfo->reason = FONTGRID_START_SELECTION;
2767     }
2768
2769     return (pi->sel_start == -1) ? FALSE : TRUE;
2770 }
2771
2772 bdf_font_t *
2773 fontgrid_get_font(Fontgrid *fw)
2774 {
2775     g_return_val_if_fail(fw != 0, 0);
2776
2777     return fw->font;
2778 }
2779
2780 void
2781 fontgrid_set_font(Fontgrid *fw, bdf_font_t *font, gint32 initial_glyph)
2782 {
2783     GtkWidget *w;
2784     gint32 i, boundary;
2785     FontgridInternalPageInfo *pi;
2786     FontgridPageInfo pageinfo;
2787
2788     g_return_if_fail(fw != 0);
2789
2790     if (font == fw->font)
2791       return;
2792
2793     w = GTK_WIDGET(fw);
2794
2795     /*
2796      * Free up the existing font.
2797      */
2798     if (fw->font != 0)
2799       bdf_free_font(fw->font);
2800     fw->font = font;
2801
2802     /*
2803      * Make sure the encoded pages are the default for newly loaded fonts.
2804      */
2805     fw->unencoded = FALSE;
2806
2807     /*
2808      * Set the bits-per-pixel from the font.
2809      */
2810     fw->bpp = (font != 0) ? font->bpp : 1;
2811
2812     /*
2813      * Set the initial glyph code.
2814      */
2815     fw->initial_glyph = initial_glyph;
2816
2817     /*
2818      * Calculate the cell geometry and the rows and columns.
2819      */
2820     fontgrid_set_cell_geometry(fw);
2821     fontgrid_set_rows_cols(fw, 0);
2822
2823     /*
2824      * Initialize the page information.
2825      */
2826     pi = &fw->upage;
2827     pi->minpage = 0;
2828     pi->maxpage = 0xffff / fw->pagesize;
2829     pi->npage = pi->ppage = -1;
2830     pi->pageno = pi->bcode = 0;
2831     pi->sel_start = pi->sel_end = -1;
2832     (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2833     pi = &fw->npage;
2834     pi->minpage = 0;
2835     pi->maxpage = 0xffff / fw->pagesize;
2836     pi->npage = pi->ppage = -1;
2837     pi->pageno = pi->bcode = 0;
2838     pi->sel_start = pi->sel_end = -1;
2839     (void) memset((char *) pi->selmap, 0, sizeof(guint32) * 2048);
2840
2841     /*
2842      * Determine the page info from the initial glyph setting.
2843      */
2844     if (font != 0) {
2845         if (fw->initial_glyph == -1)
2846           fw->initial_glyph = (font->glyphs_used > 0) ?
2847               font->glyphs->encoding : 0;
2848
2849         pi = &fw->npage;
2850         pi->pageno = fw->initial_glyph / fw->pagesize;
2851         pi->bcode = pi->pageno * fw->pagesize;
2852         pi->sel_start = pi->sel_end = fw->initial_glyph;
2853         Select(fw->initial_glyph, pi->selmap);
2854         fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
2855
2856         /*
2857          * Set the min/max page numbers for the encoded glyphs.
2858          */
2859         if (font->glyphs_used > 0) {
2860             if (fw->noblanks) {
2861                 pi->minpage = font->glyphs->encoding / fw->pagesize;
2862                 pi->maxpage =
2863                     font->glyphs[font->glyphs_used-1].encoding / fw->pagesize;
2864             } else {
2865                 pi->minpage = 0;
2866                 pi->maxpage = 0xffff / fw->pagesize;
2867             }
2868         }
2869
2870         /*
2871          * Set the min/max page numbers for the unencoded glyphs.
2872          */
2873         if (font->unencoded_used > 0) {
2874             pi = &fw->upage;
2875
2876             if (fw->noblanks) {
2877                 pi->pageno = pi->minpage =
2878                     font->glyphs->encoding / fw->pagesize;
2879                 pi->maxpage =
2880                     font->unencoded[font->unencoded_used-1].encoding /
2881                     fw->pagesize;
2882                 pi->bcode = pi->pageno * fw->pagesize;
2883                 pi->ppage = -1;
2884
2885                 /*
2886                  * Lower boundary for the next page.
2887                  */
2888                 boundary = pi->bcode + fw->pagesize;
2889                 for (i = 0; i < font->unencoded_used &&
2890                          font->unencoded[i].encoding < boundary; i++) ;
2891                 pi->npage = (i == font->unencoded_used) ?
2892                     -1 : font->unencoded[i].encoding / fw->pagesize;
2893                   
2894             } else {
2895                 pi->pageno = pi->minpage = 0;
2896                 pi->maxpage = 0xffff / fw->pagesize;
2897                 pi->ppage = -1;
2898                 pi->npage = pi->pageno + 1;
2899             }
2900         }
2901     }
2902
2903     /*
2904      * Signal that a page change has taken place so the application can do
2905      * setup that it needs.
2906      */
2907     pageinfo.unencoded_page = fw->unencoded;
2908     pageinfo.encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
2909     pageinfo.unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
2910
2911     if (!fw->unencoded) {
2912         pageinfo.previous_page = fw->npage.ppage;
2913         pageinfo.current_page = fw->npage.pageno;
2914         pageinfo.next_page = fw->npage.npage;
2915     } else {
2916         pageinfo.previous_page = fw->upage.ppage;
2917         pageinfo.current_page = fw->upage.pageno;
2918         pageinfo.next_page = fw->upage.npage;
2919     }
2920
2921     g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
2922
2923     /*
2924      * Queue up a resize so the grid will change size.
2925      */
2926     gtk_widget_queue_resize(w);
2927 }
2928
2929 gchar *
2930 fontgrid_get_font_messages(Fontgrid *fw)
2931 {
2932     g_return_val_if_fail(fw != 0, 0);
2933
2934     return (fw->font) ? fw->font->acmsgs : 0;
2935 }
2936
2937 guint
2938 fontgrid_get_code_base(Fontgrid *fw)
2939 {
2940     g_return_val_if_fail(fw != 0, 0);
2941
2942     return fw->base;
2943 }
2944
2945 void
2946 fontgrid_set_code_base(Fontgrid *fw, guint base)
2947 {
2948     FontgridInternalPageInfo *pi;
2949     FontgridSelectionInfo sinfo;
2950
2951     g_return_if_fail(fw != 0);
2952
2953     switch (base) {
2954       case 8: case 10: case 16:
2955         if (fw->base != base) {
2956             fw->base = base;
2957             if (!fw->unencoded) {
2958                 pi = &fw->npage;
2959                 fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
2960                                     fw->npage.bcode + fw->pagesize,
2961                                     TRUE, FALSE);
2962             } else
2963               pi = &fw->upage;
2964
2965             /*
2966              * Set up the selection info to alert the application that the
2967              * base changed.
2968              */
2969             if (pi->sel_start == pi->sel_end) {
2970                 if (fw->font) {
2971                     if (!fw->unencoded)
2972                       sinfo.glyphs =
2973                           fontgrid_locate_glyph(fw->font->glyphs,
2974                                                 fw->font->glyphs_used,
2975                                                 pi->sel_start, TRUE);
2976                     else
2977                       sinfo.glyphs =
2978                           fontgrid_locate_glyph(fw->font->unencoded,
2979                                                 fw->font->unencoded_used,
2980                                                 pi->sel_start, TRUE);
2981                     if (sinfo.glyphs == 0) {
2982                         empty_glyph.encoding = pi->sel_start;
2983                         sinfo.glyphs = &empty_glyph;
2984                     }
2985                     sinfo.num_glyphs = 1;
2986                 }
2987             } else {
2988                 sinfo.glyphs = 0;
2989                 sinfo.num_glyphs = 0;
2990             }
2991
2992             sinfo.start = pi->sel_start;
2993             sinfo.end = pi->sel_end;
2994             sinfo.base = fw->base;
2995             sinfo.unencoded = fw->unencoded;
2996             sinfo.reason = FONTGRID_BASE_CHANGE;
2997             g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
2998                           &sinfo);
2999         }
3000         break;
3001     }
3002 }
3003
3004 GtkOrientation
3005 fontgrid_get_orientation(Fontgrid *fw)
3006 {
3007     g_return_val_if_fail(fw != 0, GTK_ORIENTATION_HORIZONTAL);
3008
3009     return fw->orientation;
3010 }
3011
3012 void
3013 fontgrid_set_orientation(Fontgrid *fw, GtkOrientation dir)
3014 {
3015     guint16 tmp;
3016
3017     g_return_if_fail(fw != 0);
3018
3019     if (dir != fw->orientation) {
3020         fw->orientation = dir;
3021
3022         /*
3023          * Need to swap rows and cols and attempt a resize if the object
3024          * has been constructed.
3025          */
3026         tmp = fw->cell_rows;
3027         fw->cell_rows = fw->cell_cols;
3028         fw->cell_cols = tmp;
3029
3030         gtk_widget_queue_resize(GTK_WIDGET(fw));
3031     }
3032 }
3033
3034 void
3035 fontgrid_get_page_info(Fontgrid *fw, FontgridPageInfo *pageinfo)
3036 {
3037     g_return_if_fail(fw != 0);
3038     g_return_if_fail(pageinfo != 0);
3039
3040     pageinfo->unencoded_page = fw->unencoded;
3041     pageinfo->encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
3042     pageinfo->unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
3043
3044     if (!fw->unencoded) {
3045         pageinfo->previous_page = fw->npage.ppage;
3046         pageinfo->current_page = fw->npage.pageno;
3047         pageinfo->next_page = fw->npage.npage;
3048     } else {
3049         pageinfo->previous_page = fw->upage.ppage;
3050         pageinfo->current_page = fw->upage.pageno;
3051         pageinfo->next_page = fw->upage.npage;
3052     }
3053 }
3054
3055 /*
3056  * This is the routine that does the majority of the work for updating
3057  * page changes.
3058  */
3059 static void
3060 fontgrid_page_change_update(Fontgrid *fw, FontgridInternalPageInfo *pi)
3061 {
3062     gint32 code;
3063     FontgridPageInfo pageinfo;
3064     FontgridSelectionInfo selinfo;
3065
3066     code = pi->sel_start - pi->bcode;
3067     pi->bcode = pi->pageno * fw->pagesize;
3068
3069     if (fw->from_keyboard) {
3070         fontgrid_deselect_all(fw);
3071         code += pi->bcode;
3072         pi->sel_start = pi->sel_end = code;
3073         Select(code, pi->selmap);
3074         fw->from_keyboard = FALSE;
3075     }
3076     fontgrid_neighbor_pages(fw, pi->pageno, &pi->ppage, &pi->npage);
3077
3078     fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode,
3079                         pi->bcode + (fw->pagesize - 1), TRUE, TRUE);
3080
3081     pageinfo.unencoded_page = fw->unencoded;
3082     pageinfo.encoded_glyphs = (fw->font) ? fw->font->glyphs_used : 0;
3083     pageinfo.unencoded_glyphs = (fw->font) ? fw->font->unencoded_used : 0;
3084
3085     pageinfo.previous_page = pi->ppage;
3086     pageinfo.current_page = pi->pageno;
3087     pageinfo.next_page = pi->npage;
3088
3089     g_signal_emit(G_OBJECT(fw), fontgrid_signals[TURN_TO_PAGE], 0, &pageinfo);
3090
3091     /*
3092      * If this was called from the keyboard, then indicate the changed
3093      * selection.
3094      */
3095     if (!fw->no_sel_callback && fw->from_keyboard) {
3096         selinfo.glyphs = 0;
3097         selinfo.num_glyphs = 1;
3098         if (fw->font) {
3099             selinfo.glyphs = (!fw->unencoded) ?
3100                 fontgrid_locate_glyph(fw->font->glyphs,
3101                                       fw->font->glyphs_used,
3102                                       code, TRUE) :
3103                 fontgrid_locate_glyph(fw->font->unencoded,
3104                                       fw->font->unencoded_used,
3105                                       code, TRUE);
3106         }
3107         if (selinfo.glyphs == 0) {
3108             empty_glyph.encoding = code;
3109             selinfo.glyphs = &empty_glyph;
3110         }
3111
3112         selinfo.reason = FONTGRID_START_SELECTION;
3113         selinfo.start = pi->sel_start;
3114         selinfo.end = pi->sel_end;
3115         selinfo.base = fw->base;
3116         selinfo.unencoded = fw->unencoded;
3117         g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3118                       &selinfo);
3119     }
3120 }
3121
3122 void
3123 fontgrid_goto_page(Fontgrid *fw, gint32 pageno)
3124 {
3125     guint32 mpage;
3126     FontgridInternalPageInfo *pi;
3127
3128     g_return_if_fail(fw != 0);
3129
3130     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3131
3132     mpage = 0xffff / fw->pagesize;
3133
3134     if (pageno < 0)
3135       pageno = 0;
3136     if (pageno > mpage)
3137       pageno = mpage;
3138
3139     if (pageno != pi->pageno) {
3140         pi->pageno = pageno;
3141         fontgrid_page_change_update(fw, pi);
3142     }
3143 }
3144
3145 void
3146 fontgrid_goto_code(Fontgrid *fw, gint32 code)
3147 {
3148     gint32 pageno;
3149     FontgridInternalPageInfo *pi;
3150     FontgridSelectionInfo selinfo;
3151
3152     g_return_if_fail(fw != 0);
3153
3154     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3155
3156     if (code < 0)
3157       code = 0;
3158     if (code > 0xffff)
3159       code = 0xffff;
3160
3161     pageno = code / fw->pagesize;
3162
3163     if (pageno != pi->pageno) {
3164         fw->no_sel_callback = TRUE;
3165         pi->pageno = pageno;
3166         fontgrid_page_change_update(fw, pi);
3167     }
3168
3169     fontgrid_deselect_all(fw);
3170     Select(code, pi->selmap);
3171     pi->sel_start = pi->sel_end = code;
3172     fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
3173
3174     selinfo.glyphs = 0;
3175     selinfo.num_glyphs = 1;
3176     if (fw->font) {
3177         selinfo.glyphs = (!fw->unencoded) ?
3178             fontgrid_locate_glyph(fw->font->glyphs,
3179                                   fw->font->glyphs_used,
3180                                   code, TRUE) :
3181             fontgrid_locate_glyph(fw->font->unencoded,
3182                                   fw->font->unencoded_used,
3183                                   code, TRUE);
3184     }
3185     if (selinfo.glyphs == 0) {
3186         empty_glyph.encoding = code;
3187         selinfo.glyphs = &empty_glyph;
3188     }
3189
3190     selinfo.reason = FONTGRID_START_SELECTION;
3191     selinfo.start = pi->sel_start;
3192     selinfo.end = pi->sel_end;
3193     selinfo.base = fw->base;
3194     selinfo.unencoded = fw->unencoded;
3195     g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
3196                   &selinfo);
3197 }
3198
3199 void
3200 fontgrid_goto_first_page(Fontgrid *fw)
3201 {
3202     FontgridInternalPageInfo *pi;
3203
3204     g_return_if_fail(fw != 0);
3205
3206     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3207
3208     if (pi->pageno == pi->minpage)
3209       return;
3210
3211     pi->pageno = pi->minpage;
3212     fontgrid_page_change_update(fw, pi);
3213 }
3214
3215 void
3216 fontgrid_goto_last_page(Fontgrid *fw)
3217 {
3218     FontgridInternalPageInfo *pi;
3219
3220     g_return_if_fail(fw != 0);
3221
3222     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3223
3224     if (pi->pageno == pi->maxpage)
3225       return;
3226
3227     pi->pageno = pi->maxpage;
3228     fontgrid_page_change_update(fw, pi);
3229 }
3230
3231 void
3232 fontgrid_goto_next_page(Fontgrid *fw)
3233 {
3234     FontgridInternalPageInfo *pi;
3235
3236     g_return_if_fail(fw != 0);
3237
3238     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3239
3240     if (pi->pageno == pi->maxpage)
3241       return;
3242
3243     pi->pageno = pi->npage;
3244     fontgrid_page_change_update(fw, pi);
3245 }
3246
3247 void
3248 fontgrid_goto_previous_page(Fontgrid *fw)
3249 {
3250     FontgridInternalPageInfo *pi;
3251
3252     g_return_if_fail(fw != 0);
3253
3254     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3255
3256     if (pi->pageno == pi->minpage)
3257       return;
3258
3259     pi->pageno = pi->ppage;
3260     fontgrid_page_change_update(fw, pi);
3261 }
3262
3263 gboolean
3264 fontgrid_viewing_unencoded(Fontgrid *fw)
3265 {
3266     g_return_val_if_fail(fw != 0, FALSE);
3267
3268     return fw->unencoded;
3269 }
3270
3271 void
3272 fontgrid_switch_encoding_view(Fontgrid *fw)
3273 {
3274     FontgridInternalPageInfo *pi;
3275
3276     g_return_if_fail(fw != 0);
3277
3278     fw->unencoded = !fw->unencoded;
3279     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3280     fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode, pi->bcode + fw->pagesize,
3281                         TRUE, TRUE);
3282 }
3283
3284 gchar *
3285 fontgrid_get_font_name(Fontgrid *fw)
3286 {
3287     g_return_val_if_fail(fw != 0, 0);
3288
3289     return (fw->font) ? fw->font->name : "";
3290 }
3291
3292 void
3293 fontgrid_set_font_name(Fontgrid *fw, gchar *name)
3294 {
3295     FontgridModificationInfo minfo;
3296
3297     g_return_if_fail(fw != 0);
3298     g_return_if_fail(fw->font != 0);
3299
3300     if (fw->font->name != 0)
3301       free(fw->font->name);
3302
3303     if (name == 0 || *name == 0)
3304       fw->font->name = bdf_make_xlfd_name(fw->font, g_get_prgname(),
3305                                           "Unknown");
3306     else
3307       fw->font->name = g_strdup(name);
3308
3309     bdf_set_modified(fw->font, 1);
3310
3311     minfo.reason = FONTGRID_MODIFIED;
3312     g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3313 }
3314
3315 gboolean
3316 fontgrid_get_font_modified(Fontgrid *fw)
3317 {
3318     g_return_val_if_fail(fw != 0, FALSE);
3319
3320     return (fw->font) ? ((fw->font->modified) ? TRUE : FALSE) : FALSE;
3321 }
3322
3323 void
3324 fontgrid_set_font_modified(Fontgrid *fw, gboolean mod)
3325 {
3326     FontgridInternalPageInfo *pi;
3327
3328     g_return_if_fail(fw != 0);
3329
3330     if (fw->font && fw->font->modified != mod) {
3331         bdf_set_modified(fw->font, mod);
3332
3333         if (mod == FALSE) {
3334             /*
3335              * Redraw all the labels to clear those that were showing as
3336              * modified.
3337              */
3338             pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3339             fontgrid_draw_cells(GTK_WIDGET(fw), pi->bcode,
3340                                 (pi->bcode + fw->pagesize) - 1, TRUE, FALSE);
3341         } else {
3342             /*
3343              * If the font is being marked as modified, then signal the
3344              * application of this state.
3345              */
3346             fprintf(stderr, "MOD\n");
3347         }
3348     }
3349 }
3350
3351 void
3352 fontgrid_set_unicode_glyph_names(Fontgrid *fw, FILE *in)
3353 {
3354     FontgridModificationInfo minfo;
3355
3356     g_return_if_fail(fw != 0);
3357     g_return_if_fail(in != 0);
3358
3359     if (bdf_set_unicode_glyph_names(in, fw->font, 0)) {
3360         /*
3361          * Redraw the labels.
3362          */
3363         fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3364                             fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3365         minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3366         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3367     }
3368 }
3369
3370 void
3371 fontgrid_set_adobe_glyph_names(Fontgrid *fw, FILE *in)
3372 {
3373     FontgridModificationInfo minfo;
3374
3375     g_return_if_fail(fw != 0);
3376     g_return_if_fail(in != 0);
3377
3378     if (bdf_set_adobe_glyph_names(in, fw->font, 0)) {
3379         /*
3380          * Redraw the labels.
3381          */
3382         fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3383                             fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3384         minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3385         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3386     }
3387 }
3388
3389 void
3390 fontgrid_set_code_glyph_names(Fontgrid *fw, gint ch)
3391 {
3392     FontgridModificationInfo minfo;
3393
3394     g_return_if_fail(fw != 0);
3395
3396     if (bdf_set_glyph_code_names(ch, fw->font, 0)) {
3397         /*
3398          * Redraw the labels.
3399          */
3400         fontgrid_draw_cells(GTK_WIDGET(fw), fw->npage.bcode,
3401                             fw->npage.bcode + fw->pagesize, TRUE, FALSE);
3402         minfo.reason = FONTGRID_GLYPH_NAMES_MODIFIED;
3403         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3404     }
3405 }
3406
3407 void
3408 fontgrid_make_xlfd_font_name(Fontgrid *fw)
3409 {
3410     FontgridModificationInfo minfo;
3411
3412     g_return_if_fail(fw != 0);
3413
3414     if ((minfo.name = bdf_make_xlfd_name(fw->font, "Foundry",
3415                                          "FaceName")) != 0) {
3416         minfo.reason = FONTGRID_NAME_MODIFIED;
3417         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3418     }
3419 }
3420
3421 void
3422 fontgrid_update_font_name_from_properties(Fontgrid *fw)
3423 {
3424     FontgridModificationInfo minfo;
3425
3426     g_return_if_fail(fw != 0);
3427
3428     if (bdf_has_xlfd_name(fw->font)) {
3429         bdf_update_name_from_properties(fw->font);
3430
3431         minfo.reason = FONTGRID_NAME_MODIFIED;
3432         minfo.name = fw->font->name;
3433         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3434     }
3435 }
3436
3437 void
3438 fontgrid_update_properties_from_font_name(Fontgrid *fw)
3439 {
3440     FontgridModificationInfo minfo;
3441
3442     g_return_if_fail(fw != 0);
3443
3444     if (bdf_update_properties_from_name(fw->font)) {
3445         minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3446         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3447     }
3448 }
3449
3450 void
3451 fontgrid_set_font_property(Fontgrid *fw, bdf_property_t *prop)
3452 {
3453     FontgridModificationInfo minfo;
3454     gboolean changed;
3455     bdf_property_t *p;
3456
3457     g_return_if_fail(fw != 0);
3458     g_return_if_fail(prop != 0);
3459
3460     changed = FALSE;
3461
3462     if ((p = bdf_get_font_property(fw->font, prop->name)) == 0)
3463       changed = TRUE;
3464     else if (p->format == prop->format) {
3465         switch (p->format) {
3466           case BDF_ATOM:
3467             /*
3468              * If the atoms are different or one is NULL and the other isn't,
3469              * then the property will be changed.
3470              */
3471             if ((p->value.atom && prop->value.atom &&
3472                  strcmp(p->value.atom, prop->value.atom) != 0) ||
3473                 p->value.atom != prop->value.atom)
3474               changed = TRUE;
3475             break;
3476           case BDF_INTEGER:
3477             if (p->value.int32 != prop->value.int32)
3478               changed = TRUE;
3479             break;
3480           case BDF_CARDINAL:
3481             if (p->value.card32 != prop->value.card32)
3482               changed = TRUE;
3483             break;
3484         }
3485     }
3486
3487     /*
3488      * If this causes no change, just return.
3489      */
3490     if (changed == FALSE)
3491       return;
3492
3493     bdf_add_font_property(fw->font, prop);
3494     minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3495     g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3496 }
3497
3498 void
3499 fontgrid_delete_font_property(Fontgrid *fw, gchar *prop_name)
3500 {
3501     FontgridModificationInfo minfo;
3502     bdf_property_t *p;
3503
3504     g_return_if_fail(fw != 0);
3505     g_return_if_fail(prop_name != 0);
3506
3507     /*
3508      * If the property doesn't exist, then just return.
3509      */
3510     if ((p = bdf_get_font_property(fw->font, prop_name)) == 0)
3511       return;
3512
3513     bdf_delete_font_property(fw->font, prop_name);
3514     minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3515     g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3516 }
3517
3518 guint32
3519 fontgrid_get_font_comments(Fontgrid *fw, gchar **comments)
3520 {
3521     g_return_val_if_fail(fw != 0, 0);
3522
3523     if (comments != 0)
3524       *comments = fw->font->comments;
3525
3526     return fw->font->comments_len;
3527 }
3528
3529 void
3530 fontgrid_set_font_comments(Fontgrid *fw, gchar *comments)
3531 {
3532     FontgridModificationInfo minfo;
3533     unsigned int len;
3534
3535     g_return_if_fail(fw != 0);
3536
3537     len = (comments) ? (unsigned int) strlen(comments) : 0;
3538     if (bdf_replace_comments(fw->font, comments, len)) {
3539         minfo.reason = FONTGRID_COMMENTS_MODIFIED;
3540         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3541     }
3542 }
3543
3544 gint
3545 fontgrid_get_font_spacing(Fontgrid *fw)
3546 {
3547     g_return_val_if_fail(fw != 0, -1);
3548
3549     return fw->font->spacing;
3550 }
3551
3552 void
3553 fontgrid_set_font_spacing(Fontgrid *fw, gint spacing)
3554 {
3555     FontgridModificationInfo minfo;
3556     bdf_property_t p;
3557
3558     g_return_if_fail(fw != 0);
3559
3560     if (spacing < BDF_PROPORTIONAL || spacing > BDF_CHARCELL ||
3561         fw->font->spacing == spacing)
3562       return;
3563
3564     p.name = "SPACING";
3565     p.format = BDF_ATOM;
3566     switch (spacing) {
3567       case BDF_PROPORTIONAL: p.value.atom = "P"; break;
3568       case BDF_MONOWIDTH: p.value.atom = "M"; break;
3569       case BDF_CHARCELL: p.value.atom = "C"; break;
3570     }
3571
3572     bdf_add_font_property(fw->font, &p);
3573     minfo.reason = FONTGRID_PROPERTIES_MODIFIED;
3574     g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3575 }
3576
3577 guint16
3578 fontgrid_get_font_device_width(Fontgrid *fw)
3579 {
3580     g_return_val_if_fail(fw != 0, 0);
3581
3582     return fw->font->monowidth;
3583 }
3584
3585 void
3586 fontgrid_set_font_device_width(Fontgrid *fw, guint16 dwidth)
3587 {
3588     FontgridModificationInfo minfo;
3589
3590     g_return_if_fail(fw != 0);
3591
3592     /*
3593      * Only set the global device width if this is not a proportional font or
3594      * if there the device width changed.
3595      */
3596     if (fw->font->spacing == BDF_PROPORTIONAL ||
3597         fw->font->monowidth == dwidth)
3598       return;
3599
3600     fw->font->monowidth = dwidth;
3601     fw->font->modified = 1;
3602
3603     minfo.reason = FONTGRID_DEVICE_WIDTH_MODIFIED;
3604     g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3605 }
3606
3607 void
3608 fontgrid_get_font_info(Fontgrid *fw, FontgridFontInfo *info)
3609 {
3610     g_return_if_fail(fw != 0);
3611     g_return_if_fail(fw->font != 0);
3612     g_return_if_fail(info != 0);
3613
3614     info->name = fw->font->name;
3615     info->comments = fw->font->comments;
3616     info->messages = fw->font->acmsgs;
3617     info->default_char = fw->font->default_glyph;
3618     info->monowidth = fw->font->monowidth;
3619     info->spacing = (guint16) fw->font->spacing;
3620     info->font_ascent = fw->font->font_ascent;
3621     info->font_descent = fw->font->font_descent;
3622     info->font_descent = fw->font->font_descent;
3623     info->resolution_x = fw->font->resolution_x;
3624     info->resolution_y = fw->font->resolution_y;
3625     info->bits_per_pixel = fw->font->bpp;
3626     memcpy((char *) &info->bbx, (char *) &fw->font->bbx, sizeof(bdf_bbx_t));
3627 }
3628
3629 void
3630 fontgrid_set_font_info(Fontgrid *fw, FontgridFontInfo *info)
3631 {
3632     int mod;
3633     bdf_font_t *f;
3634     bdf_property_t prop;
3635     FontgridModificationInfo minfo;
3636
3637     g_return_if_fail(fw != 0);
3638     g_return_if_fail(fw->font != 0);
3639     g_return_if_fail(info != 0);
3640
3641     f = fw->font;
3642
3643     minfo.reason = FONTGRID_MODIFIED;
3644
3645     /*
3646      * Do some special stuff with the modified field so we know whether to
3647      * call the modified callback or not.
3648      */
3649     mod = f->modified;
3650     f->modified = 0;
3651
3652     /*
3653      * Handle the default character field.  If it happens to be -1, then
3654      * delete the font property.  Otherwise add it.
3655      */
3656     if (info->default_char < 0)
3657       bdf_delete_font_property(f, "DEFAULT_CHAR");
3658     else {
3659         prop.name = "DEFAULT_CHAR";
3660         prop.format = BDF_CARDINAL;
3661         prop.value.card32 = info->default_char;
3662         bdf_add_font_property(f, &prop);
3663     }
3664
3665     prop.name = "FONT_ASCENT";
3666     prop.format = BDF_INTEGER;
3667     prop.value.int32 = info->font_ascent;
3668     bdf_add_font_property(f, &prop);
3669
3670     prop.name = "FONT_DESCENT";
3671     prop.format = BDF_INTEGER;
3672     prop.value.int32 = info->font_descent;
3673     bdf_add_font_property(f, &prop);
3674
3675     prop.name = "RESOLUTION_X";
3676     prop.format = BDF_CARDINAL;
3677     prop.value.int32 = info->resolution_x;
3678     bdf_add_font_property(f, &prop);
3679
3680     prop.name = "RESOLUTION_Y";
3681     prop.format = BDF_CARDINAL;
3682     prop.value.int32 = info->resolution_y;
3683     bdf_add_font_property(f, &prop);
3684
3685     prop.name = "SPACING";
3686     prop.format = BDF_ATOM;
3687     prop.value.atom = 0;
3688     switch (info->spacing) {
3689       case BDF_PROPORTIONAL: prop.value.atom = "P"; break;
3690       case BDF_MONOWIDTH: prop.value.atom = "M"; break;
3691       case BDF_CHARCELL: prop.value.atom = "C"; break;
3692     }
3693     if (prop.value.atom != 0)
3694       bdf_add_font_property(f, &prop);
3695
3696     /*
3697      * If the font was modified, and has an XLFD name, make sure the XLFD name
3698      * gets updated from the properties and the appropriate callback is
3699      * called.
3700      */
3701     if (f->modified && bdf_has_xlfd_name(f))
3702       fontgrid_update_font_name_from_properties(fw);
3703
3704     /*
3705      * Now determine if the monowidth field will have a resize affect on
3706      * things.
3707      */
3708     if (f->spacing != BDF_PROPORTIONAL) {
3709         if (f->monowidth == 0) {
3710             /*
3711              * Handle the special case of a proportional font being changed to
3712              * some other spacing.
3713              */
3714             f->monowidth = f->bbx.width;
3715             f->modified = 1;
3716         }
3717         if (info->monowidth != f->monowidth) {
3718             /*
3719              * Go ahead and queue up a resize in case the monowidth
3720              * really does change the size.
3721              */
3722             gtk_widget_queue_resize(GTK_WIDGET(fw));
3723             f->monowidth = f->bbx.width = info->monowidth;
3724             f->modified = 1;
3725         }
3726     }
3727     if (f->modified)
3728       g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3729     f->modified |= mod;
3730 }
3731
3732 void
3733 fontgrid_translate_glyphs(Fontgrid *fw, gint16 dx, gint16 dy,
3734                           gboolean all_glyphs)
3735 {
3736     GtkWidget *w = (GtkWidget *) fw;
3737     gint32 start, end;
3738     FontgridInternalPageInfo *pi;
3739     FontgridModificationInfo minfo;
3740
3741     g_return_if_fail(fw != 0);
3742
3743     pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3744
3745     if (all_glyphs) {
3746         start = pi->minpage * fw->pagesize;
3747         end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3748     } else {
3749         start = pi->sel_start;
3750         end = pi->sel_end;
3751     }
3752
3753     if (bdf_translate_glyphs(fw->font, dx, dy, start, end, 0, 0,
3754                              fw->unencoded)) {
3755         gtk_widget_queue_resize(w);
3756         if (GTK_WIDGET_REALIZED(w))
3757           gdk_window_clear(w->window);
3758
3759         gtk_widget_queue_resize(w);
3760         if (GTK_WIDGET_REALIZED(w))
3761           gdk_window_clear(w->window);
3762
3763         minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3764         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3765     }
3766 }
3767
3768 void
3769 fontgrid_rotate_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3770 {
3771     GtkWidget *w = (GtkWidget *) fw;
3772     gint32 start, end;
3773     FontgridInternalPageInfo *pi;
3774     FontgridModificationInfo minfo;
3775
3776     g_return_if_fail(fw != 0);
3777
3778     pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3779
3780     if (all_glyphs) {
3781         start = pi->minpage * fw->pagesize;
3782         end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3783     } else {
3784         start = pi->sel_start;
3785         end = pi->sel_end;
3786     }
3787
3788     if (bdf_rotate_glyphs(fw->font, degrees, start, end, 0, 0,
3789                           fw->unencoded)) {
3790         gtk_widget_queue_resize(w);
3791         if (GTK_WIDGET_REALIZED(w))
3792           gdk_window_clear(w->window);
3793
3794         minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3795         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3796     }
3797 }
3798
3799 void
3800 fontgrid_shear_glyphs(Fontgrid *fw, gint16 degrees, gboolean all_glyphs)
3801 {
3802     GtkWidget *w = (GtkWidget *) fw;
3803     gint32 start, end;
3804     FontgridInternalPageInfo *pi;
3805     FontgridModificationInfo minfo;
3806
3807     g_return_if_fail(fw != 0);
3808
3809     pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3810
3811     if (all_glyphs) {
3812         start = pi->minpage * fw->pagesize;
3813         end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3814     } else {
3815         start = pi->sel_start;
3816         end = pi->sel_end;
3817     }
3818
3819     if (bdf_shear_glyphs(fw->font, degrees, start, end, 0, 0,
3820                           fw->unencoded)) {
3821         gtk_widget_queue_resize(w);
3822         if (GTK_WIDGET_REALIZED(w))
3823           gdk_window_clear(w->window);
3824
3825         minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3826         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3827     }
3828 }
3829
3830 void
3831 fontgrid_embolden_glyphs(Fontgrid *fw, gboolean all_glyphs)
3832 {
3833     GtkWidget *w = (GtkWidget *) fw;
3834     gint resize;
3835     gint32 start, end;
3836     FontgridInternalPageInfo *pi;
3837     FontgridModificationInfo minfo;
3838
3839     g_return_if_fail(fw != 0);
3840
3841     pi = (!fw->unencoded) ? &fw->npage: &fw->upage;
3842
3843     if (all_glyphs) {
3844         start = pi->minpage * fw->pagesize;
3845         end = (pi->maxpage * fw->pagesize) + fw->pagesize;
3846     } else {
3847         start = pi->sel_start;
3848         end = pi->sel_end;
3849     }
3850
3851     resize = 0;
3852     if (bdf_embolden_glyphs(fw->font, start, end, 0, 0,
3853                             fw->unencoded, &resize)) {
3854         if (resize) {
3855             gtk_widget_queue_resize(w);
3856             if (GTK_WIDGET_REALIZED(w))
3857               gdk_window_clear(w->window);
3858         } else
3859           /*
3860            * Just redisplay the selection.
3861            */
3862           fontgrid_draw_cells(w, start, end, TRUE, TRUE);
3863
3864         minfo.reason = FONTGRID_GLYPHS_MODIFIED;
3865         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
3866     }
3867 }
3868
3869 gboolean
3870 fontgrid_clipboard_empty(Fontgrid *fw)
3871 {
3872     GdkWindow *owner;
3873     gboolean empty = TRUE;
3874     GdkAtom atype;
3875     gint aformat, nitems;
3876     guchar *data;
3877
3878     g_return_val_if_fail(fw != 0, empty);
3879
3880     if ((owner = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0)
3881       return empty;
3882
3883     /*
3884      * Check to see if the clipboard contents are empty or not.
3885      *
3886      * This is handled specially to allow determination of this without
3887      * using up what might be a lot of memory to get the whole contents.  It
3888      * will have to be changed for Windows.
3889      */
3890     if (gdk_property_get(owner, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
3891                          0, 4, FALSE, &atype, &aformat, &nitems, &data)) {
3892         if (nitems > 0) {
3893             empty = FALSE;
3894             free((char *) data);
3895         }
3896     }
3897
3898     return empty;
3899 }
3900
3901 static unsigned char *
3902 fontgrid_encode_selection(Fontgrid *fw, guint32 *bytes)
3903 {
3904     FontgridInternalPageInfo *pi;
3905     bdf_glyph_t *gp;
3906     bdf_glyphlist_t *gl;
3907     guint16 a;
3908     guint32 i, nlen, bcount;
3909     guchar *sel, *sp;
3910
3911     *bytes = 0;
3912
3913     gl = &fw->clipboard;
3914     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
3915     bdf_copy_glyphs(fw->font, pi->sel_start, pi->sel_end, gl, fw->unencoded);
3916
3917     /*
3918      * Calculate the number of bytes that will be needed for everything except
3919      * the name strings and the bitmap data.
3920      */
3921     bcount = (sizeof(unsigned int) << 1) + (6 * sizeof(unsigned short)) +
3922         (((6 * sizeof(unsigned short)) + sizeof(unsigned int)) *
3923          gl->glyphs_used);
3924
3925     /*
3926      * Figure out how much extra will be needed for the names, bitmaps, and
3927      * PSF Unicode mappings.
3928      */
3929     for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3930         nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
3931         /*
3932          * The extra 2 bytes is for encoding the number of bytes used for the
3933          * Unicode mappings, even if it is 0.  This could be a problem later
3934          * if a set of mappings legitimately exceeds 2^16 in length.
3935          */
3936         bcount += nlen + gp->bytes + 2 + gp->unicode.map_used;
3937     }
3938
3939     /*
3940      * Allocate the storage space needed for the encoded form.
3941      */
3942     sel = sp = g_malloc(bcount);
3943
3944     /*
3945      * Set the returned byte count.
3946      */
3947     *bytes = bcount;
3948
3949     /*
3950      * Encode the 20-byte header.
3951      */
3952     a = (guint16) gl->bpp;
3953     *sp++ = (a >> 8) & 0xff;
3954     *sp++ = a & 0xff;
3955
3956     nlen = (guint32) gl->start;
3957     *sp++ = (nlen >> 24) & 0xff;
3958     *sp++ = (nlen >> 16) & 0xff;
3959     *sp++ = (nlen >> 8) & 0xff;
3960     *sp++ = nlen & 0xff;
3961
3962     nlen = (guint32) gl->end;
3963     *sp++ = (nlen >> 24) & 0xff;
3964     *sp++ = (nlen >> 16) & 0xff;
3965     *sp++ = (nlen >> 8) & 0xff;
3966     *sp++ = nlen & 0xff;
3967
3968     a = (guint16) gl->glyphs_used;
3969     *sp++ = (a >> 8) & 0xff;
3970     *sp++ = a & 0xff;
3971
3972     a = (guint16) gl->bbx.width;
3973     *sp++ = (a >> 8) & 0xff;
3974     *sp++ = a & 0xff;
3975
3976     a = (guint16) gl->bbx.x_offset;
3977     *sp++ = (a >> 8) & 0xff;
3978     *sp++ = a & 0xff;
3979
3980     a = (guint16) gl->bbx.ascent;
3981     *sp++ = (a >> 8) & 0xff;
3982     *sp++ = a & 0xff;
3983
3984     a = (guint16) gl->bbx.descent;
3985     *sp++ = (a >> 8) & 0xff;
3986     *sp++ = a & 0xff;
3987
3988     /*
3989      * Go through each glyph entry and encode the data.
3990      */
3991     for (i = 0, gp = gl->glyphs; i < gl->glyphs_used; i++, gp++) {
3992         /*
3993          * Encode the glyph encoding.
3994          */
3995         nlen = (guint32) gp->encoding;
3996         *sp++ = (nlen >> 24) & 0xff;
3997         *sp++ = (nlen >> 16) & 0xff;
3998         *sp++ = (nlen >> 8) & 0xff;
3999         *sp++ = nlen & 0xff;
4000
4001         /*
4002          * Encode the glyph device width.
4003          */
4004         a = (guint16) gp->dwidth;
4005         *sp++ = (a >> 8) & 0xff;
4006         *sp++ = a & 0xff;
4007
4008         /*
4009          * Encode the glyph name length.
4010          */
4011         nlen = (gp->name) ? (guint32) (strlen(gp->name) + 1) : 0;
4012         a = (guint16) nlen;
4013         *sp++ = (a >> 8) & 0xff;
4014         *sp++ = a & 0xff;
4015
4016         /*
4017          * Encode the four bounding box values needed.
4018          */
4019         a = (guint16) gp->bbx.width;
4020         *sp++ = (a >> 8) & 0xff;
4021         *sp++ = a & 0xff;
4022
4023         a = (guint16) gp->bbx.x_offset;
4024         *sp++ = (a >> 8) & 0xff;
4025         *sp++ = a & 0xff;
4026
4027         a = (guint16) gp->bbx.ascent;
4028         *sp++ = (a >> 8) & 0xff;
4029         *sp++ = a & 0xff;
4030
4031         a = (guint16) gp->bbx.descent;
4032         *sp++ = (a >> 8) & 0xff;
4033         *sp++ = a & 0xff;
4034
4035         /*
4036          * Encode the name if it exists.
4037          */
4038         if (nlen > 0) {
4039             (void) memcpy((char *) sp, gp->name, nlen);
4040             sp += nlen;
4041         }
4042
4043         /*
4044          * Encode the bitmap.
4045          */
4046         if (gp->bytes > 0) {
4047             (void) memcpy((char *) sp, (char *) gp->bitmap, gp->bytes);
4048             sp += gp->bytes;
4049         }
4050
4051         /*
4052          * Encode the PSF Unicode mappings.  Even if there aren't any, add
4053          * the encoding.
4054          */
4055         *sp++ = (gp->unicode.map_used >> 8) & 0xff;
4056         *sp++ = gp->unicode.map_used & 0xff;
4057         if (gp->unicode.map_used > 0) {
4058             (void) memcpy((char *) sp, (char *) gp->unicode.map,
4059                           sizeof(unsigned char) * gp->unicode.map_used);
4060             sp += gp->unicode.map_used;
4061         }
4062     }
4063
4064     /*
4065      * Return the selection encoded as a byte stream.
4066      */
4067     return sel;
4068 }
4069
4070 #define GETSHORT(s) ((s[0] << 8) | s[1])
4071 #define GETLONG(s) ((s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3])
4072
4073 static void
4074 fontgrid_decode_selection(Fontgrid *fw, guchar *sel)
4075 {
4076     guint32 i, range, nlen;
4077     bdf_glyph_t *gp;
4078     bdf_glyphlist_t *gl;
4079
4080     if (sel == 0)
4081       return;
4082
4083     gl = &fw->clipboard;
4084
4085     /*
4086      * Clear out the bitmaps and names from the existing glyphs.
4087      */
4088     for (gp = gl->glyphs, i = 0; i < gl->glyphs_size; i++, gp++) {
4089         if (gp->name != 0)
4090           free(gp->name);
4091         if (gp->bytes > 0)
4092           free((char *) gp->bitmap);
4093     }
4094
4095     /*
4096      * Extract the glyph list bits per pixel.
4097      */
4098     gl->bpp = GETSHORT(sel);
4099     sel += 2;
4100
4101     /*
4102      * Extract the glyph list starting and ending encodings.
4103      */
4104     gl->start = (int) GETLONG(sel);
4105     sel += 4;
4106
4107     gl->end = (int) GETLONG(sel);
4108     sel += 4;
4109
4110     /*
4111      * Extract the number of encoded glyphs.
4112      */
4113     range = (guint32) GETSHORT(sel);
4114     sel += 2;
4115
4116     /*
4117      * Resize the internal glyph list clipboard if necessary.
4118      */
4119     if (range > gl->glyphs_size) {
4120         if (gl->glyphs_size == 0)
4121           gl->glyphs = (bdf_glyph_t *) malloc(sizeof(bdf_glyph_t) * range);
4122         else
4123           gl->glyphs = (bdf_glyph_t *) realloc((char *) gl->glyphs,
4124                                                sizeof(bdf_glyph_t) * range);
4125         gl->glyphs_size = range;
4126     }
4127
4128     /*
4129      * Initialize the glyph list.
4130      */
4131     (void) memset((char *) &gl->bbx, 0, sizeof(bdf_bbx_t));
4132     (void) memset((char *) gl->glyphs, 0,
4133                   sizeof(bdf_glyph_t) * gl->glyphs_size);
4134
4135     gl->glyphs_used = range;
4136
4137     /*
4138      * Decode the overall metrics of the glyph list.
4139      */
4140     gl->bbx.width = GETSHORT(sel);
4141     sel += 2;
4142     gl->bbx.x_offset = GETSHORT(sel);
4143     sel += 2;
4144     gl->bbx.ascent = GETSHORT(sel);
4145     sel += 2;
4146     gl->bbx.descent = GETSHORT(sel);
4147     sel += 2;
4148     gl->bbx.height = gl->bbx.ascent + gl->bbx.descent;
4149     gl->bbx.y_offset = -gl->bbx.descent;
4150
4151     /*
4152      * Decode the glyphs.
4153      */
4154     for (i = 0, gp = gl->glyphs; i < range; i++, gp++) {
4155         /*
4156          * Get the glyph encoding.
4157          */
4158         gp->encoding = (int) GETLONG(sel);
4159         sel += 4;
4160
4161         /*
4162          * Get the device width.
4163          */
4164         gp->dwidth = GETSHORT(sel);
4165         sel += 2;
4166
4167         /*
4168          * Get the name length.
4169          */
4170         nlen = GETSHORT(sel);
4171         sel += 2;
4172
4173         /*
4174          * Get the bounding box.
4175          */
4176         gp->bbx.width = GETSHORT(sel);
4177         sel += 2;
4178         gp->bbx.x_offset = GETSHORT(sel);
4179         sel += 2;
4180         gp->bbx.ascent = GETSHORT(sel);
4181         sel += 2;
4182         gp->bbx.descent = GETSHORT(sel);
4183         sel += 2;
4184         gp->bbx.height = gp->bbx.ascent + gp->bbx.descent;
4185         gp->bbx.y_offset = -gp->bbx.descent;
4186
4187         /*
4188          * Get the name.
4189          */
4190         if (nlen > 0) {
4191             gp->name = (char *) malloc(nlen);
4192             (void) memcpy(gp->name, (char *) sel, nlen);
4193             sel += nlen;
4194         }
4195
4196         /*
4197          * Get the bitmap.
4198          */
4199
4200         switch (gl->bpp) {
4201           case 1:
4202             gp->bytes = ((gp->bbx.width + 7) >> 3) * gp->bbx.height;
4203             break;
4204           case 2:
4205             gp->bytes = (((gp->bbx.width << 1) + 7) >> 3) * gp->bbx.height;
4206             break;
4207           case 4:
4208             gp->bytes = (((gp->bbx.width << 2) + 7) >> 3) * gp->bbx.height;
4209             break;
4210           case 8:
4211             gp->bytes = gp->bbx.width * gp->bbx.height;
4212             break;
4213         }
4214
4215         if (gp->bytes > 0) {
4216             gp->bitmap = (unsigned char *) malloc(gp->bytes);
4217             (void) memcpy((char *) gp->bitmap, (char *) sel, gp->bytes);
4218             sel += gp->bytes;
4219         }
4220
4221         /*
4222          * Get the Unicode mappings.
4223          */
4224         gp->unicode.map_used = GETSHORT(sel);
4225         sel += 2;
4226         if (gp->unicode.map_used > 0) {
4227             gp->unicode.map_size = ((gp->unicode.map_used >> 2) + 
4228                                     ((gp->unicode.map_used & 3) ? 1 : 0)) << 2;
4229             gp->unicode.map = (unsigned char *) malloc(gp->unicode.map_size);
4230             (void) memcpy((char *) gp->unicode.map, (char *) sel,
4231                           gp->unicode.map_used);
4232             sel += gp->unicode.map_used;
4233         }
4234     }
4235 }
4236
4237 /*
4238  * This function assumes the fontgrid is realized so a GdkWindow exists.
4239  */
4240 void
4241 fontgrid_copy_selection(Fontgrid *fw)
4242 {
4243     GtkWidget *w;
4244     GdkWindow *win;
4245     guint32 bytes;
4246     guchar *sel;
4247
4248     g_return_if_fail(fw != 0);
4249
4250     w = GTK_WIDGET(fw);
4251
4252     /*
4253      * Make sure the widget owns the clipboard property.
4254      */
4255     if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0 ||
4256         win != w->window)
4257       gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4258                               FALSE);
4259
4260     /*
4261      * Encode the selection as a byte stream for the clipboard.
4262      */
4263     if ((sel = fontgrid_encode_selection(fw, &bytes)) == 0)
4264       return;
4265
4266     gdk_property_change(w->window, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4267                         8, GDK_PROP_MODE_REPLACE, sel, (gint) bytes);
4268
4269     /*
4270      * Free the data because the property now has control over it.
4271      */
4272     g_free(sel);
4273 }
4274
4275 void
4276 fontgrid_cut_selection(Fontgrid *fw)
4277 {
4278     gint32 code, start, end;
4279     bdf_glyph_t *gp;
4280     FontgridInternalPageInfo *pi;
4281     FontgridModificationInfo minfo;
4282     FontgridSelectionInfo sinfo;
4283
4284     g_return_if_fail(fw != 0);
4285
4286     fontgrid_copy_selection(fw);
4287
4288     pi = (!fw->unencoded) ? &fw->npage : &fw->upage;
4289     code = pi->sel_start;
4290
4291     if (bdf_delete_glyphs(fw->font, pi->sel_start, pi->sel_end,
4292                           fw->unencoded)) {
4293         start = pi->sel_start;
4294         end = pi->sel_end;
4295
4296         fontgrid_deselect_all(fw);
4297         Select(code, pi->selmap);
4298         pi->sel_start = pi->sel_end = code;
4299         fontgrid_draw_cells(GTK_WIDGET(fw), start, end, TRUE, TRUE);
4300
4301         /*
4302          * Set up and emit the modified signal.
4303          */
4304         minfo.reason = FONTGRID_GLYPHS_DELETED;
4305         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4306
4307         /*
4308          * Set up and call the selection start signal.
4309          */
4310         gp = (!fw->unencoded) ?
4311             fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4312                                   code, TRUE) :
4313             fontgrid_locate_glyph(fw->font->unencoded,
4314                                   fw->font->unencoded_used, code, TRUE);
4315         if (gp == 0) {
4316             empty_glyph.encoding = code;
4317             gp = &empty_glyph;
4318         }
4319
4320         sinfo.glyphs = gp;
4321         sinfo.num_glyphs = 1;
4322         sinfo.start = sinfo.end = code;
4323         sinfo.base = fw->base;
4324         sinfo.unencoded = fw->unencoded;
4325         sinfo.reason = FONTGRID_START_SELECTION;
4326         g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4327                       &sinfo);
4328     }
4329 }
4330
4331 void
4332 fontgrid_paste_selection(Fontgrid *fw, FontgridPasteType paste_type)
4333 {
4334     GtkWidget *w = GTK_WIDGET(fw);
4335     GdkWindow *win;
4336     GdkAtom atype;
4337     gint afmt, nitems, unenc, doresize;
4338     gint32 i;
4339     unsigned int ng;
4340     guchar *data;
4341     bdf_font_t *font;
4342     bdf_glyph_t *gp;
4343     bdf_glyphlist_t *gl;
4344     FontgridInternalPageInfo *pi;
4345     bdf_glyphlist_t overflow;
4346     FontgridModificationInfo minfo;
4347     FontgridSelectionInfo sinfo;
4348
4349     g_return_if_fail(fw != 0);
4350     g_return_if_fail(GTK_WIDGET_REALIZED(w));
4351
4352     if ((win = gdk_selection_owner_get(FONTGRID_CLIPBOARD)) == 0) {
4353         gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD,
4354                                 GDK_CURRENT_TIME, FALSE);
4355         /*
4356          * Return here because there was no owner of the selection.
4357          */
4358         return;
4359     }
4360
4361     doresize = 0;
4362     unenc = fw->unencoded;
4363
4364     pi = (!unenc) ? &fw->npage : &fw->upage;
4365
4366     nitems = 0;
4367     (void) gdk_property_get(win, FONTGRID_CLIPBOARD, FONTGRID_GLYPHLIST,
4368                             0, 102400, FALSE, &atype, &afmt, &nitems, &data);
4369
4370     /*
4371      * Attempt to own the clipboard after getting the value if this widget
4372      * does not own it.
4373      */
4374     if (win != w->window)
4375       gdk_selection_owner_set(w->window, FONTGRID_CLIPBOARD, GDK_CURRENT_TIME,
4376                               FALSE);
4377
4378     if (nitems > 0) {
4379         font = fw->font;
4380         gl = &fw->clipboard;
4381
4382         /*
4383          * Convert the encoded selection into a glyph list in the internal
4384          * glyph list clipboard.
4385          */
4386         fontgrid_decode_selection(fw, data);
4387
4388         /*
4389          * If the paste is occuring in the unencoded section, make sure the
4390          * paste is appended as opposed to being inserted.  Also turn off
4391          * the selected cell before doing the paste.
4392          */
4393         if (unenc) {
4394             fontgrid_deselect_all(fw);
4395             pi->sel_start = font->unencoded_used;
4396             gl->start = 0;
4397             gl->end = gl->glyphs_used - 1;
4398         }
4399
4400         /*
4401          * Set the end point of the selection.
4402          */
4403         pi->sel_end = pi->sel_start + (gl->end - gl->start);
4404
4405         /*
4406          * First, check to see if pasting the glyphs will exceed the maximum
4407          * encoding value of 0xffff.  If some of them do, then transfer the
4408          * extra glyphs to the unencoded area before doing anything else.
4409          * This means that a new glyph list needs to be constructed to do the
4410          * insert into the unencoded area.
4411          */
4412         if (!unenc && pi->sel_end > 0xffff) {
4413             /*
4414              * Determine if any of the glyphs would actually get encoded after
4415              * 0xffff or if those are all empty glyphs.
4416              */
4417             for (ng = 0, gp = gl->glyphs; ng < gl->glyphs_used; ng++, gp++) {
4418                 if (pi->sel_start + (gp->encoding - gl->start) > 0xffff)
4419                   /*
4420                    * The glyph list does contain glyphs that will overflow.
4421                    */
4422                   break;
4423             }
4424
4425             if (ng < gl->glyphs_used) {
4426                 /*
4427                  * Construct a new glyph list containing only the glyphs that
4428                  * overflow the 0xffff boundary.  There is no need to
4429                  * recalculate the bounding box for the new glyph list.  Any
4430                  * resize will be handled correctly anyway.
4431                  */
4432                 (void) memcpy((char *) &overflow.bbx, (char *) &gl->bbx,
4433                               sizeof(bdf_bbx_t));
4434                 overflow.bpp = font->bpp;
4435                 overflow.glyphs_used = gl->glyphs_used - ng;
4436                 overflow.glyphs = gp;
4437                 overflow.start = 0;
4438                 overflow.end = overflow.glyphs_used - 1;
4439
4440                 /*
4441                  * Add the glyphs to the unencoded area.
4442                  */
4443                 doresize = bdf_replace_glyphs(font, font->unencoded_used,
4444                                               &overflow, 1);
4445             }
4446
4447             /*
4448              * Adjust the glyph list and selection to fit within the 0xffff
4449              * limit before pasting the glyphs into the font.
4450              */
4451             gl->glyphs_used = ng;
4452             gl->end -= pi->sel_end - 0xffff;
4453             pi->sel_end = 0xffff;
4454         }
4455
4456         /*
4457          * If the grid is in insert mode, then determine if moving glyphs
4458          * forward from the insert location would cause an overflow.
4459          */
4460         if (!unenc &&
4461             (!fw->overwrite || paste_type == FONTGRID_INSERT_PASTE)) {
4462             doresize += bdf_insert_glyphs(font, pi->sel_start, gl);
4463             /*
4464              * Force a page recalculation to be done so the application can
4465              * update if needed.
4466              */
4467             fontgrid_goto_page(fw, fw->npage.pageno);
4468         } else if (paste_type == FONTGRID_MERGE_PASTE)
4469           doresize += bdf_merge_glyphs(font, pi->sel_start, gl, unenc);
4470         else
4471           doresize += bdf_replace_glyphs(font, pi->sel_start, gl, unenc);
4472
4473         /*
4474          * If the paste has more than one glyph, make sure the whole
4475          * range is selected.
4476          */
4477         for (i = pi->sel_start; i <= pi->sel_end; i++)
4478           Select(i, pi->selmap);
4479
4480         /*
4481          * If the incoming glyphs changed the font bounding box, then
4482          * determine the new geometry and attempt a resize.
4483          */
4484         if (doresize) {
4485             fontgrid_set_cell_geometry(fw);
4486             fontgrid_set_rows_cols(fw, 0);
4487             gtk_widget_queue_resize(w);
4488         } else
4489           fontgrid_draw_cells(w, pi->sel_start, pi->sel_end, TRUE, TRUE);
4490
4491         /*
4492          * Update the number of pages used.
4493          */
4494         if (unenc) {
4495             if (fw->noblanks) {
4496                 if (font->unencoded_used == 0)
4497                   pi->maxpage = 0;
4498                 else {
4499                     gp = font->unencoded + (font->unencoded_used - 1);
4500                     pi->maxpage = gp->encoding / fw->pagesize;
4501                 }
4502             }
4503         } else {
4504             if (fw->noblanks) {
4505                 if (font->glyphs_used == 0)
4506                   pi->maxpage = 0;
4507                 else {
4508                     gp = font->glyphs + (font->glyphs_used - 1);
4509                     pi->maxpage = gp->encoding / fw->pagesize;
4510                 }
4511             }
4512         }
4513
4514         /*
4515          * Set up and call the modified callback.
4516          */
4517         /*
4518          * Set up and emit the modified signal.
4519          */
4520         minfo.reason = FONTGRID_GLYPHS_PASTED;
4521         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &minfo);
4522
4523         if (pi->sel_start == pi->sel_end) {
4524             /*
4525              * Set up and call the selection start signal.
4526              */
4527             gp = (!fw->unencoded) ?
4528                 fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4529                                       pi->sel_start, TRUE) :
4530                 fontgrid_locate_glyph(fw->font->unencoded,
4531                                       fw->font->unencoded_used, pi->sel_start,
4532                                       TRUE);
4533             if (gp == 0) {
4534                 empty_glyph.encoding = pi->sel_start;
4535                 gp = &empty_glyph;
4536             }
4537
4538             sinfo.glyphs = gp;
4539             sinfo.num_glyphs = 1;
4540         } else {
4541             sinfo.glyphs = 0;
4542             sinfo.num_glyphs = 0;
4543         }
4544         sinfo.start = pi->sel_start;
4545         sinfo.end = pi->sel_end;
4546         sinfo.base = fw->base;
4547         sinfo.unencoded = fw->unencoded;
4548         sinfo.reason = FONTGRID_START_SELECTION;
4549         g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4550                       &sinfo);
4551
4552         /*
4553          * And last, since the change of the selection owner caused the
4554          * clipboard to lose its data, add the data to it again so
4555          * it can be pasted in some other font editor.
4556          */
4557         gdk_property_change(w->window, FONTGRID_CLIPBOARD,
4558                             FONTGRID_GLYPHLIST, 8, GDK_PROP_MODE_REPLACE,
4559                             data, (gint) nitems);
4560
4561         g_free((char *) data);
4562     }
4563 }
4564
4565 void
4566 fontgrid_update_metrics(Fontgrid *fw, bdf_metrics_t *metrics)
4567 {
4568     FontgridModificationInfo mi;
4569
4570     g_return_if_fail(fw != 0);
4571     g_return_if_fail(fw->font != 0);
4572
4573     if (bdf_set_font_bbx(fw->font, metrics)) {
4574         /*
4575          * Need to resize.
4576          */
4577
4578         /*
4579          * Calculate the cell geometry and the rows and columns.
4580          */
4581         fontgrid_set_cell_geometry(fw);
4582         fontgrid_set_rows_cols(fw, 0);
4583
4584         gtk_widget_queue_resize(GTK_WIDGET(fw));
4585
4586         mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4587         mi.name = 0;
4588         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4589     }
4590 }
4591
4592 void
4593 fontgrid_update_glyph(Fontgrid *fw, bdf_glyph_t *glyph, gboolean unencoded)
4594 {
4595     FontgridInternalPageInfo *pi;
4596     bdf_glyph_t *gp;
4597     bdf_glyphlist_t gl;
4598     FontgridModificationInfo mi;
4599
4600     g_return_if_fail(fw != 0);
4601     g_return_if_fail(fw->font != 0);
4602
4603     gl.bpp = fw->font->bpp;
4604     gl.start = gl.end = glyph->encoding;
4605     gl.glyphs = glyph;
4606     gl.glyphs_used = 1;
4607     memcpy((char *) &gl.bbx, (char *) &glyph->bbx, sizeof(bdf_bbx_t));
4608
4609     if (bdf_replace_glyphs(fw->font, glyph->encoding, &gl, unencoded)) {
4610         /*
4611          * The font geometry was changed by the glyph being pasted.
4612          * A resize will be needed.
4613          */
4614
4615         /*
4616          * Calculate the cell geometry and the rows and columns.
4617          */
4618         fontgrid_set_cell_geometry(fw);
4619         fontgrid_set_rows_cols(fw, 0);
4620
4621         gtk_widget_queue_resize(GTK_WIDGET(fw));
4622
4623         mi.reason = FONTGRID_FONT_METRICS_MODIFIED;
4624         mi.name = 0;
4625         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4626     } else
4627       /*
4628        * Simply redraw the cells that were modified.
4629        */
4630       fontgrid_draw_cells(GTK_WIDGET(fw), glyph->encoding, glyph->encoding,
4631                           TRUE, TRUE);
4632
4633     pi = (fw->unencoded) ? &fw->upage : &fw->npage;
4634     if (unencoded) {
4635         if (fw->noblanks) {
4636             if (fw->font->unencoded_used == 0)
4637               pi->maxpage = 0;
4638             else {
4639                 gp = fw->font->unencoded + (fw->font->unencoded_used - 1);
4640                 pi->maxpage = gp->encoding / fw->pagesize;
4641             }
4642         }
4643     } else {
4644         if (fw->noblanks) {
4645             if (fw->font->glyphs_used == 0)
4646               pi->maxpage = 0;
4647             else {
4648                 gp = fw->font->glyphs + (fw->font->glyphs_used - 1);
4649                 pi->maxpage = gp->encoding / fw->pagesize;
4650             }
4651         }
4652     }
4653
4654     mi.reason = FONTGRID_GLYPHS_MODIFIED;
4655     mi.name = 0;
4656     mi.start = mi.end = glyph->encoding;
4657     mi.unencoded = fw->unencoded;
4658     g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4659 }
4660
4661 void
4662 fontgrid_update_psf_mappings(Fontgrid *fw, gint32 encoding,
4663                              bdf_psf_unimap_t *mappings)
4664 {
4665     FontgridModificationInfo mi;
4666
4667     g_return_if_fail(fw != 0);
4668     g_return_if_fail(fw->font != 0);
4669
4670     if (bdf_replace_mappings(fw->font, encoding, mappings, fw->unencoded)) {
4671         mi.reason = FONTGRID_PSF_MAPPINGS_MODIFIED;
4672         mi.name = 0;
4673         mi.start = mi.end = encoding;
4674         mi.unencoded = fw->unencoded;
4675         g_signal_emit(G_OBJECT(fw), fontgrid_signals[MODIFIED], 0, &mi);
4676     }
4677 }
4678
4679 gboolean
4680 fontgrid_select_next_glyph(Fontgrid *fw, gint32 code)
4681 {
4682     bdf_glyph_t *gp;
4683     gint32 pageno;
4684     guint32 count;
4685     FontgridInternalPageInfo *pi;
4686     FontgridSelectionInfo sinfo;
4687
4688     g_return_val_if_fail(fw != NULL, FALSE);
4689     g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4690
4691     if (!fw->unencoded) {
4692         pi = &fw->npage;
4693         gp = (fw->font && fw->font->glyphs_used) ?
4694             (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4695     } else {
4696         pi = &fw->upage;
4697         gp = (fw->font && fw->font->unencoded_used) ?
4698             (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4699     }
4700
4701     if ((count = fw->count) == 0)
4702       count = 1;
4703
4704     /*
4705      * Make sure that when on the unencoded pages, the final glyph is
4706      * the limit unlike the encoded pages where the max value is 0xffff.
4707      */
4708     if ((fw->unencoded &&
4709          (gp == 0 || code == gp->encoding)) ||
4710         code == 0xffff) {
4711         gdk_beep();
4712         return FALSE;
4713     }
4714
4715     if (fw->orientation == GTK_ORIENTATION_VERTICAL)
4716       code += (fw->cell_rows * count);
4717     else
4718       code += count;
4719
4720     if (fw->unencoded && code > gp->encoding)
4721       code = gp->encoding;
4722     else if (code > 0xffff)
4723       code = 0xffff;
4724
4725     fontgrid_deselect_all(fw);
4726
4727     pageno = code / fw->pagesize;
4728     if (pageno != pi->pageno) {
4729         fw->no_sel_callback = TRUE;
4730         fontgrid_goto_page(fw, pageno);
4731     }
4732
4733     pi->sel_start = pi->sel_end = code;
4734     Select(code, pi->selmap);
4735     fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4736
4737     /*
4738      * Reset the count.
4739      */
4740     fw->count = 0;
4741
4742     /*
4743      * Set up and emit the selection start signal.
4744      */
4745     if (!fw->unencoded)
4746       gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4747                                  code, TRUE);
4748     else
4749       gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4750                                  code, TRUE);
4751     if (gp == 0) {
4752         empty_glyph.encoding = code;
4753         gp = &empty_glyph;
4754     }
4755     sinfo.glyphs = gp;
4756     sinfo.num_glyphs = 1;
4757     sinfo.start = pi->sel_start;
4758     sinfo.end = pi->sel_end;
4759     sinfo.base = fw->base;
4760     sinfo.unencoded = fw->unencoded;
4761
4762     sinfo.reason = FONTGRID_START_SELECTION;
4763     g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4764                   &sinfo);
4765     return TRUE;
4766 }
4767
4768 gboolean
4769 fontgrid_select_previous_glyph(Fontgrid *fw, gint32 code)
4770 {
4771     bdf_glyph_t *gp;
4772     gint32 pageno;
4773     guint32 count;
4774     FontgridInternalPageInfo *pi;
4775     FontgridSelectionInfo sinfo;
4776
4777     g_return_val_if_fail(fw != NULL, FALSE);
4778     g_return_val_if_fail(IS_FONTGRID(fw), FALSE);
4779
4780     if (!fw->unencoded) {
4781         pi = &fw->npage;
4782         gp = (fw->font && fw->font->glyphs_used) ?
4783             (fw->font->glyphs + (fw->font->glyphs_used - 1)) : 0;
4784     } else {
4785         pi = &fw->upage;
4786         gp = (fw->font && fw->font->unencoded_used) ?
4787             (fw->font->unencoded + (fw->font->unencoded_used - 1)) : 0;
4788     }
4789
4790     if ((count = fw->count) == 0)
4791       count = 1;
4792
4793     if (code == 0) {
4794         gdk_beep();
4795         return FALSE;
4796     }
4797
4798     if (fw->orientation == GTK_ORIENTATION_VERTICAL)
4799       code -= (fw->cell_rows * count);
4800     else
4801       code -= count;
4802
4803     if (code < 0)
4804       code = 0;
4805
4806     fontgrid_deselect_all(fw);
4807
4808     pageno = code / fw->pagesize;
4809     if (pageno != pi->pageno) {
4810         fw->no_sel_callback = TRUE;
4811         fontgrid_goto_page(fw, pageno);
4812     }
4813
4814     pi->sel_start = pi->sel_end = code;
4815     Select(code, pi->selmap);
4816     fontgrid_draw_cells(GTK_WIDGET(fw), code, code, FALSE, TRUE);
4817
4818     /*
4819      * Reset the count.
4820      */
4821     fw->count = 0;
4822
4823     /*
4824      * Set up and emit the selection start signal.
4825      */
4826     if (!fw->unencoded)
4827       gp = fontgrid_locate_glyph(fw->font->glyphs, fw->font->glyphs_used,
4828                                  code, TRUE);
4829     else
4830       gp = fontgrid_locate_glyph(fw->font->unencoded, fw->font->unencoded_used,
4831                                  code, TRUE);
4832     if (gp == 0) {
4833         empty_glyph.encoding = code;
4834         gp = &empty_glyph;
4835     }
4836     sinfo.glyphs = gp;
4837     sinfo.num_glyphs = 1;
4838     sinfo.start = pi->sel_start;
4839     sinfo.end = pi->sel_end;
4840     sinfo.base = fw->base;
4841     sinfo.unencoded = fw->unencoded;
4842
4843     sinfo.reason = FONTGRID_START_SELECTION;
4844     g_signal_emit(G_OBJECT(fw), fontgrid_signals[SELECTION_START], 0,
4845                   &sinfo);
4846     return TRUE;
4847 }