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