/*
* To do:
*
- * - import flags to do VT100 double-width, and import the icky
- * pixmap stretch code for it.
+ * - import flags to do VT100 double-width; import the icky
+ * pixmap stretch code on to the X11 side, and do something
+ * nicer in Pango.
*
- * - add the Pango back end!
+ * - unified font selector dialog, arrgh!
*/
/*
/*
* `Methods' of the `class'.
*/
- unifont *(*create)(char *name, int wide, int bold,
+ unifont *(*create)(GtkWidget *widget, char *name, int wide, int bold,
int shadowoffset, int shadowalways);
void (*destroy)(unifont *font);
void (*draw_text)(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len, int wide,
- int bold);
+ int bold, int cellwidth);
/*
* `Static data members' of the `class'.
*/
static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len,
- int wide, int bold);
-static unifont *x11font_create(char *name, int wide, int bold,
+ int wide, int bold, int cellwidth);
+static unifont *x11font_create(GtkWidget *widget, char *name,
+ int wide, int bold,
int shadowoffset, int shadowalways);
static void x11font_destroy(unifont *font);
* whether we use gdk_draw_text_wc() or gdk_draw_text().
*/
int sixteen_bit;
- /*
- * Font charsets. public_charset and real_charset can differ
- * for X11 fonts, because many X fonts use CS_ISO8859_1_X11.
- */
- int public_charset, real_charset;
/*
* Data passed in to unifont_create().
*/
}
}
-static unifont *x11font_create(char *name, int wide, int bold,
+static unifont *x11font_create(GtkWidget *widget, char *name,
+ int wide, int bold,
int shadowoffset, int shadowalways)
{
struct x11font *xfont;
static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len,
- int wide, int bold)
+ int wide, int bold, int cellwidth)
{
struct x11font *xfont = (struct x11font *)font;
int sfid;
}
}
+/* ----------------------------------------------------------------------
+ * Pango font implementation.
+ */
+
+static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
+ int x, int y, const char *string, int len,
+ int wide, int bold, int cellwidth);
+static unifont *pangofont_create(GtkWidget *widget, char *name,
+ int wide, int bold,
+ int shadowoffset, int shadowalways);
+static void pangofont_destroy(unifont *font);
+
+struct pangofont {
+ struct unifont u;
+ /*
+ * Pango objects.
+ */
+ PangoFontDescription *desc;
+ PangoFontset *fset;
+ /*
+ * The containing widget.
+ */
+ GtkWidget *widget;
+ /*
+ * Data passed in to unifont_create().
+ */
+ int bold, shadowoffset, shadowalways;
+};
+
+static const struct unifont_vtable pangofont_vtable = {
+ pangofont_create,
+ pangofont_destroy,
+ pangofont_draw_text,
+ "pango"
+};
+
+static unifont *pangofont_create(GtkWidget *widget, char *name,
+ int wide, int bold,
+ int shadowoffset, int shadowalways)
+{
+ struct pangofont *pfont;
+ PangoContext *ctx;
+ PangoFontMap *map;
+ PangoFontDescription *desc;
+ PangoFontset *fset;
+ PangoFontMetrics *metrics;
+
+ desc = pango_font_description_from_string(name);
+ if (!desc)
+ return NULL;
+ ctx = gtk_widget_get_pango_context(widget);
+ if (!ctx) {
+ pango_font_description_free(desc);
+ return NULL;
+ }
+ map = pango_context_get_font_map(ctx);
+ if (!map) {
+ pango_font_description_free(desc);
+ return NULL;
+ }
+ fset = pango_font_map_load_fontset(map, ctx, desc,
+ pango_context_get_language(ctx));
+ if (!fset) {
+ pango_font_description_free(desc);
+ return NULL;
+ }
+ metrics = pango_fontset_get_metrics(fset);
+ if (!metrics ||
+ pango_font_metrics_get_approximate_digit_width(metrics) == 0) {
+ pango_font_description_free(desc);
+ g_object_unref(fset);
+ return NULL;
+ }
+
+ pfont = snew(struct pangofont);
+ pfont->u.vt = &pangofont_vtable;
+ pfont->u.width =
+ PANGO_PIXELS(pango_font_metrics_get_approximate_digit_width(metrics));
+ pfont->u.ascent = PANGO_PIXELS(pango_font_metrics_get_ascent(metrics));
+ pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
+ pfont->u.height = pfont->u.ascent + pfont->u.descent;
+ /* The Pango API is hardwired to UTF-8 */
+ pfont->u.public_charset = CS_UTF8;
+ pfont->u.real_charset = CS_UTF8;
+ pfont->desc = desc;
+ pfont->fset = fset;
+ pfont->widget = widget;
+ pfont->bold = bold;
+ pfont->shadowoffset = shadowoffset;
+ pfont->shadowalways = shadowalways;
+
+ return (unifont *)pfont;
+}
+
+static void pangofont_destroy(unifont *font)
+{
+ struct pangofont *pfont = (struct pangofont *)font;
+ pfont = pfont; /* FIXME */
+ pango_font_description_free(pfont->desc);
+ g_object_unref(pfont->fset);
+ sfree(font);
+}
+
+static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
+ int x, int y, const char *string, int len,
+ int wide, int bold, int cellwidth)
+{
+ struct pangofont *pfont = (struct pangofont *)font;
+ PangoLayout *layout;
+ PangoRectangle rect;
+ int shadowbold = FALSE;
+
+ if (wide)
+ cellwidth *= 2;
+
+ y -= pfont->u.ascent;
+
+ layout = pango_layout_new(gtk_widget_get_pango_context(pfont->widget));
+ pango_layout_set_font_description(layout, pfont->desc);
+ if (bold > pfont->bold) {
+ if (pfont->shadowalways)
+ shadowbold = TRUE;
+ else {
+ PangoFontDescription *desc2 =
+ pango_font_description_copy_static(pfont->desc);
+ pango_font_description_set_weight(desc2, PANGO_WEIGHT_BOLD);
+ pango_layout_set_font_description(layout, desc2);
+ }
+ }
+
+ while (len > 0) {
+ int clen;
+
+ /*
+ * Extract a single UTF-8 character from the string.
+ */
+ clen = 1;
+ while (clen < len &&
+ (unsigned char)string[clen] >= 0x80 &&
+ (unsigned char)string[clen] < 0xC0)
+ clen++;
+
+ pango_layout_set_text(layout, string, clen);
+ pango_layout_get_pixel_extents(layout, NULL, &rect);
+ gdk_draw_layout(target, gc, x + (cellwidth - rect.width)/2,
+ y + (pfont->u.height - rect.height)/2, layout);
+ if (shadowbold)
+ gdk_draw_layout(target, gc, x + (cellwidth - rect.width)/2 + pfont->shadowoffset,
+ y + (pfont->u.height - rect.height)/2, layout);
+
+ len -= clen;
+ string += clen;
+ x += cellwidth;
+ }
+
+ g_object_unref(layout);
+}
+
/* ----------------------------------------------------------------------
* Outermost functions which do the vtable dispatch.
*/
* the font name.
*/
static const struct unifont_vtable *unifont_types[] = {
+ &pangofont_vtable,
&x11font_vtable,
};
-unifont *unifont_create(char *name, int wide, int bold,
+unifont *unifont_create(GtkWidget *widget, char *name, int wide, int bold,
int shadowoffset, int shadowalways)
{
int colonpos = strcspn(name, ":");
}
if (i == lenof(unifont_types))
return NULL; /* prefix not recognised */
- return unifont_types[i]->create(name+colonpos+1, wide, bold,
+ return unifont_types[i]->create(widget, name+colonpos+1, wide, bold,
shadowoffset, shadowalways);
} else {
/*
* No colon prefix, so just go through all the subclasses.
*/
for (i = 0; i < lenof(unifont_types); i++) {
- unifont *ret = unifont_types[i]->create(name, wide, bold,
+ unifont *ret = unifont_types[i]->create(widget, name, wide, bold,
shadowoffset,
shadowalways);
if (ret)
void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
int x, int y, const char *string, int len,
- int wide, int bold)
+ int wide, int bold, int cellwidth)
{
- font->vt->draw_text(target, gc, font, x, y, string, len, wide, bold);
+ font->vt->draw_text(target, gc, font, x, y, string, len,
+ wide, bold, cellwidth);
}
/* Since Default Background may have changed, ensure that space
* between text area and window border is refreshed. */
set_window_background(inst);
- if (inst->area) {
+ if (inst->area && inst->area->window) {
draw_backing_rect(inst);
gtk_widget_queue_draw(inst->area);
}
unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid],
x*inst->font_width+inst->cfg.window_border,
y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent,
- gcs, mblen, widefactor > 1, bold);
+ gcs, mblen, widefactor > 1, bold, inst->font_width);
}
sfree(gcs);
if (inst->fonts[3])
unifont_destroy(inst->fonts[3]);
- inst->fonts[0] = unifont_create(inst->cfg.font.name, FALSE, FALSE,
+ inst->fonts[0] = unifont_create(inst->area, inst->cfg.font.name,
+ FALSE, FALSE,
inst->cfg.shadowboldoffset,
inst->cfg.shadowbold);
if (!inst->fonts[0]) {
if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) {
inst->fonts[1] = NULL;
} else {
- inst->fonts[1] = unifont_create(inst->cfg.boldfont.name, FALSE, TRUE,
+ inst->fonts[1] = unifont_create(inst->area, inst->cfg.boldfont.name,
+ FALSE, TRUE,
inst->cfg.shadowboldoffset,
inst->cfg.shadowbold);
if (!inst->fonts[1]) {
}
if (inst->cfg.widefont.name[0]) {
- inst->fonts[2] = unifont_create(inst->cfg.widefont.name, TRUE, FALSE,
+ inst->fonts[2] = unifont_create(inst->area, inst->cfg.widefont.name,
+ TRUE, FALSE,
inst->cfg.shadowboldoffset,
inst->cfg.shadowbold);
if (!inst->fonts[2]) {
if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) {
inst->fonts[3] = NULL;
} else {
- inst->fonts[3] = unifont_create(inst->cfg.wideboldfont.name, TRUE,
+ inst->fonts[3] = unifont_create(inst->area,
+ inst->cfg.wideboldfont.name, TRUE,
TRUE, inst->cfg.shadowboldoffset,
inst->cfg.shadowbold);
if (!inst->fonts[3]) {
if (!utf8_string_atom)
utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE);
+ inst->area = gtk_drawing_area_new();
+
setup_fonts_ucs(inst);
init_cutbuffers();
inst->width = inst->cfg.width;
inst->height = inst->cfg.height;
- inst->area = gtk_drawing_area_new();
gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area),
inst->font_width * inst->cfg.width + 2*inst->cfg.window_border,
inst->font_height * inst->cfg.height + 2*inst->cfg.window_border);