]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Implemented a Pango back end. GTK 2 PuTTY can now switch seamlessly
authorSimon Tatham <anakin@pobox.com>
Sat, 22 Mar 2008 18:11:17 +0000 (18:11 +0000)
committerSimon Tatham <anakin@pobox.com>
Sat, 22 Mar 2008 18:11:17 +0000 (18:11 +0000)
back and forth between X fonts and Pango fonts, provided you're
willing to type in the names of the former by hand.

[originally from svn r7937]

unix/gtkfont.c
unix/gtkfont.h
unix/gtkwin.c

index 8fabdd23d9f696b2435d6ca119dc2f0695ab68de..24c19dbf8192113ca3c0d04bfd66e929ef12828d 100644 (file)
 /*
  * 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!
  */
 
 /*
@@ -56,12 +57,12 @@ struct unifont_vtable {
     /*
      * `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'.
      */
@@ -74,8 +75,9 @@ struct unifont_vtable {
 
 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);
 
@@ -99,11 +101,6 @@ struct x11font {
      * 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().
      */
@@ -181,7 +178,8 @@ static int x11_font_width(GdkFont *font, int sixteen_bit)
     }
 }
 
-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;
@@ -299,7 +297,7 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid)
 
 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;
@@ -374,6 +372,164 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
     }
 }
 
+/* ----------------------------------------------------------------------
+ * 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.
  */
@@ -385,9 +541,10 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
  * 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, ":");
@@ -405,14 +562,14 @@ unifont *unifont_create(char *name, int wide, int bold,
        }
        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)
@@ -429,7 +586,8 @@ void unifont_destroy(unifont *font)
 
 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);
 }
index 9cb6678393ae483f567e81a6300f7981b0ea28ee..5c36fee5395b5ea423eb6b089b1421f66f8d0906 100644 (file)
@@ -36,11 +36,11 @@ typedef struct unifont {
     int width, height, ascent, descent;
 } unifont;
 
-unifont *unifont_create(char *name, int wide, int bold,
+unifont *unifont_create(GtkWidget *widget, char *name, int wide, int bold,
                        int shadowoffset, int shadowalways);
 void unifont_destroy(unifont *font);
 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);
 
 #endif /* PUTTY_GTKFONT_H */
index 2972dba11a5fba3145cb3fd712f638445ff58198..5e4c694686ded2127ea8809197cef7f2f8f74a45 100644 (file)
@@ -1455,7 +1455,7 @@ void palette_reset(void *frontend)
     /* 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);
     }
@@ -2026,7 +2026,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
            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);
@@ -2618,7 +2618,8 @@ void setup_fonts_ucs(struct gui_data *inst)
     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]) {
@@ -2630,7 +2631,8 @@ void setup_fonts_ucs(struct gui_data *inst)
     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]) {
@@ -2641,7 +2643,8 @@ void setup_fonts_ucs(struct gui_data *inst)
     }
 
     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]) {
@@ -2656,7 +2659,8 @@ void setup_fonts_ucs(struct gui_data *inst)
     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]) {
@@ -3320,6 +3324,8 @@ int pt_main(int argc, char **argv)
     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();
 
@@ -3333,7 +3339,6 @@ int pt_main(int argc, char **argv)
     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);