mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-25 01:02:24 +00:00
Refactor the GTK drawing system to do both GDK and Cairo.
We're going to have to use Cairo in the GTK3 port, because that's all GTK3 supports; but we still need old-style GDK for GTK1 support, and also for performance reasons in GTK2 (see below). Hence, this change completely restructures GTK PuTTY's drawing code so that there's a central 'drawing context' structure which contains a type code indicating GDK or Cairo, and then either some GDK gubbins or some Cairo gubbins as appropriate; all actual drawing is abstracted through a set of routines which test the type code in that structure and do one thing or another. And because the type code is tested at run time, both sets of drawing primitives can be compiled in at once, and where possible, they will be. X server-side bitmap fonts are still supported in the Cairo world, but because Cairo drawing is entirely client-side, they have to work by cheekily downloading each glyph bitmap from the server when it's first needed, and building up a client-side cache of 'cairo_surface_t's containing the bitmaps with which we then draw on the window. This technique works, but it's rather slow; hence, even in GTK2, we keep the GDK drawing back end compiled in, and switch over to it when the main selected font is a bitmap one. One visible effect of the new Cairo routines is in the double-width and double-height text you can get by sending ESC # 3, ESC # 4 and ESC # 6 escape sequences. In GDK, that's always been done by a really horrible process of manually scaling the bitmap, server-side, column by column and row by row, causing each pixel to be exactly doubled or quadrupled. But in Cairo, we can just set a transformation matrix, and then that takes effect _before_ the scalable fonts are rendered - so the results are visibly nicer, and use all the available resolution. (Sadly, if you're using a server-side bitmap font as your primary one, then the GDK backend will be selected for all drawing in the terminal as a whole - so in that situation, even fallback characters absent from the primary font and rendered by Pango will get the old GDK scaling treatment. It's only if your main font is scalable, so that the Cairo backend is selected, that DW/DH characters will come out looking nice.)
This commit is contained in:
parent
0f60287f66
commit
f750a18587
@ -14,6 +14,7 @@
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#endif
|
||||
|
||||
#include "gtkfont.h"
|
||||
#include "gtkcompat.h"
|
||||
|
||||
#include "misc.h"
|
||||
@ -22,7 +23,9 @@
|
||||
|
||||
struct drawing_area_ctx {
|
||||
GtkWidget *area;
|
||||
#ifndef DRAW_DEFAULT_CAIRO
|
||||
GdkColor *cols;
|
||||
#endif
|
||||
int width, height, current;
|
||||
};
|
||||
|
||||
@ -33,8 +36,10 @@ struct askpass_ctx {
|
||||
#if GTK_CHECK_VERSION(2,0,0)
|
||||
GtkIMContext *imc;
|
||||
#endif
|
||||
#ifndef DRAW_DEFAULT_CAIRO
|
||||
GdkColormap *colmap;
|
||||
GdkColor cols[2];
|
||||
#endif
|
||||
char *passphrase;
|
||||
int passlen, passsize;
|
||||
};
|
||||
@ -164,16 +169,35 @@ static gint configure_area(GtkWidget *widget, GdkEventConfigure *event,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#ifdef DRAW_DEFAULT_CAIRO
|
||||
static void askpass_redraw_cairo(cairo_t *cr, struct drawing_area_ctx *ctx)
|
||||
{
|
||||
cairo_set_source_rgb(cr, 1-ctx->current, 1-ctx->current, 1-ctx->current);
|
||||
cairo_paint(cr);
|
||||
}
|
||||
#else
|
||||
static void askpass_redraw_gdk(GdkWindow *win, struct drawing_area_ctx *ctx)
|
||||
{
|
||||
GdkGC *gc = gdk_gc_new(win);
|
||||
gdk_gc_set_foreground(gc, &ctx->cols[ctx->current]);
|
||||
gdk_draw_rectangle(win, gc, TRUE, 0, 0, ctx->width, ctx->height);
|
||||
gdk_gc_unref(gc);
|
||||
}
|
||||
#endif
|
||||
|
||||
static gint expose_area(GtkWidget *widget, GdkEventExpose *event,
|
||||
gpointer data)
|
||||
{
|
||||
struct drawing_area_ctx *ctx = (struct drawing_area_ctx *)data;
|
||||
|
||||
GdkGC *gc = gdk_gc_new(gtk_widget_get_window(ctx->area));
|
||||
gdk_gc_set_foreground(gc, &ctx->cols[ctx->current]);
|
||||
gdk_draw_rectangle(gtk_widget_get_window(widget), gc, TRUE,
|
||||
0, 0, ctx->width, ctx->height);
|
||||
gdk_gc_unref(gc);
|
||||
#ifdef DRAW_DEFAULT_CAIRO
|
||||
cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(ctx->area));
|
||||
askpass_redraw_cairo(cr, ctx);
|
||||
cairo_destroy(cr);
|
||||
#else
|
||||
askpass_redraw_gdk(gtk_widget_get_window(ctx->area), ctx);
|
||||
#endif
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -216,7 +240,6 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx,
|
||||
const char *prompt_text)
|
||||
{
|
||||
int i;
|
||||
gboolean success[2];
|
||||
|
||||
ctx->passlen = 0;
|
||||
ctx->passsize = 2048;
|
||||
@ -235,16 +258,23 @@ static const char *gtk_askpass_setup(struct askpass_ctx *ctx,
|
||||
#if GTK_CHECK_VERSION(2,0,0)
|
||||
ctx->imc = gtk_im_multicontext_new();
|
||||
#endif
|
||||
ctx->colmap = gdk_colormap_get_system();
|
||||
ctx->cols[0].red = ctx->cols[0].green = ctx->cols[0].blue = 0xFFFF;
|
||||
ctx->cols[1].red = ctx->cols[1].green = ctx->cols[1].blue = 0;
|
||||
gdk_colormap_alloc_colors(ctx->colmap, ctx->cols, 2,
|
||||
FALSE, TRUE, success);
|
||||
if (!success[0] | !success[1])
|
||||
return "unable to allocate colours";
|
||||
#ifndef DRAW_DEFAULT_CAIRO
|
||||
{
|
||||
gboolean success[2];
|
||||
ctx->colmap = gdk_colormap_get_system();
|
||||
ctx->cols[0].red = ctx->cols[0].green = ctx->cols[0].blue = 0xFFFF;
|
||||
ctx->cols[1].red = ctx->cols[1].green = ctx->cols[1].blue = 0;
|
||||
gdk_colormap_alloc_colors(ctx->colmap, ctx->cols, 2,
|
||||
FALSE, TRUE, success);
|
||||
if (!success[0] | !success[1])
|
||||
return "unable to allocate colours";
|
||||
}
|
||||
#endif
|
||||
for (i = 0; i < N_DRAWING_AREAS; i++) {
|
||||
ctx->drawingareas[i].area = gtk_drawing_area_new();
|
||||
#ifndef DRAW_DEFAULT_CAIRO
|
||||
ctx->drawingareas[i].cols = ctx->cols;
|
||||
#endif
|
||||
ctx->drawingareas[i].current = 0;
|
||||
ctx->drawingareas[i].width = ctx->drawingareas[i].height = 0;
|
||||
/* It would be nice to choose this size in some more
|
||||
|
580
unix/gtkfont.c
580
unix/gtkfont.c
@ -84,9 +84,9 @@ struct unifont_vtable {
|
||||
int bold, int shadowoffset, int shadowalways);
|
||||
void (*destroy)(unifont *font);
|
||||
int (*has_glyph)(unifont *font, wchar_t glyph);
|
||||
void (*draw_text)(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len, int wide,
|
||||
int bold, int cellwidth);
|
||||
void (*draw_text)(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
void (*enum_fonts)(GtkWidget *widget,
|
||||
fontsel_add_entry callback, void *callback_ctx);
|
||||
char *(*canonify_fontname)(GtkWidget *widget, const char *name, int *size,
|
||||
@ -108,9 +108,9 @@ struct unifont_vtable {
|
||||
*/
|
||||
|
||||
static int x11font_has_glyph(unifont *font, wchar_t glyph);
|
||||
static void x11font_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
static void x11font_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
static unifont *x11font_create(GtkWidget *widget, const char *name,
|
||||
int wide, int bold,
|
||||
int shadowoffset, int shadowalways);
|
||||
@ -123,20 +123,61 @@ static char *x11font_canonify_fontname(GtkWidget *widget, const char *name,
|
||||
static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
|
||||
int size);
|
||||
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
struct cairo_cached_glyph {
|
||||
cairo_surface_t *surface;
|
||||
unsigned char *bitmap;
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Structure storing a single physical XFontStruct, plus associated
|
||||
* data.
|
||||
*/
|
||||
typedef struct x11font_individual {
|
||||
/* The XFontStruct itself. */
|
||||
XFontStruct *xfs;
|
||||
|
||||
/*
|
||||
* The `allocated' flag indicates whether we've tried to fetch
|
||||
* this subfont already (thus distinguishing xfs==NULL because we
|
||||
* haven't tried yet from xfs==NULL because we tried and failed,
|
||||
* so that we don't keep trying and failing subsequently).
|
||||
*/
|
||||
int allocated;
|
||||
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
/*
|
||||
* A cache of glyph bitmaps downloaded from the X server when
|
||||
* we're in Cairo rendering mode. If glyphcache itself is
|
||||
* non-NULL, then entries in [0,nglyphs) are expected to be
|
||||
* initialised to either NULL or a bitmap pointer.
|
||||
*/
|
||||
struct cairo_cached_glyph *glyphcache;
|
||||
int nglyphs;
|
||||
|
||||
/*
|
||||
* X server paraphernalia for actually downloading the glyphs.
|
||||
*/
|
||||
Pixmap pixmap;
|
||||
GC gc;
|
||||
int pixwidth, pixheight, pixoriginx, pixoriginy;
|
||||
|
||||
/*
|
||||
* Paraphernalia for loading the resulting bitmaps into Cairo.
|
||||
*/
|
||||
int rowsize, allsize, indexflip;
|
||||
#endif
|
||||
|
||||
} x11font_individual;
|
||||
|
||||
struct x11font {
|
||||
struct unifont u;
|
||||
/*
|
||||
* Actual font objects. We store a number of these, for
|
||||
* Individual physical X fonts. We store a number of these, for
|
||||
* automatically guessed bold and wide variants.
|
||||
*
|
||||
* The parallel array `allocated' indicates whether we've
|
||||
* tried to fetch a subfont already (thus distinguishing NULL
|
||||
* because we haven't tried yet from NULL because we tried and
|
||||
* failed, so that we don't keep trying and failing
|
||||
* subsequently).
|
||||
*/
|
||||
XFontStruct *fonts[4];
|
||||
int allocated[4];
|
||||
x11font_individual fonts[4];
|
||||
/*
|
||||
* `sixteen_bit' is true iff the font object is indexed by
|
||||
* values larger than a byte. That is, this flag tells us
|
||||
@ -381,9 +422,14 @@ static unifont *x11font_create(GtkWidget *widget, const char *name,
|
||||
xfont->u.height = xfont->u.ascent + xfont->u.descent;
|
||||
xfont->u.public_charset = pubcs;
|
||||
xfont->u.want_fallback = TRUE;
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
xfont->u.preferred_drawtype = DRAWTYPE_GDK;
|
||||
#elif defined DRAW_TEXT_CAIRO
|
||||
xfont->u.preferred_drawtype = DRAWTYPE_CAIRO;
|
||||
#else
|
||||
#error No drawtype available at all
|
||||
#endif
|
||||
xfont->real_charset = realcs;
|
||||
xfont->fonts[0] = xfs;
|
||||
xfont->allocated[0] = TRUE;
|
||||
xfont->sixteen_bit = sixteen_bit;
|
||||
xfont->variable = variable;
|
||||
xfont->wide = wide;
|
||||
@ -391,10 +437,18 @@ static unifont *x11font_create(GtkWidget *widget, const char *name,
|
||||
xfont->shadowoffset = shadowoffset;
|
||||
xfont->shadowalways = shadowalways;
|
||||
|
||||
for (i = 1; i < lenof(xfont->fonts); i++) {
|
||||
xfont->fonts[i] = NULL;
|
||||
xfont->allocated[i] = FALSE;
|
||||
for (i = 0; i < lenof(xfont->fonts); i++) {
|
||||
xfont->fonts[i].xfs = NULL;
|
||||
xfont->fonts[i].allocated = FALSE;
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
xfont->fonts[i].glyphcache = NULL;
|
||||
xfont->fonts[i].nglyphs = 0;
|
||||
xfont->fonts[i].pixmap = None;
|
||||
xfont->fonts[i].gc = None;
|
||||
#endif
|
||||
}
|
||||
xfont->fonts[0].xfs = xfs;
|
||||
xfont->fonts[0].allocated = TRUE;
|
||||
|
||||
return (unifont *)xfont;
|
||||
}
|
||||
@ -405,9 +459,24 @@ static void x11font_destroy(unifont *font)
|
||||
struct x11font *xfont = (struct x11font *)font;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < lenof(xfont->fonts); i++)
|
||||
if (xfont->fonts[i])
|
||||
XFreeFont(disp, xfont->fonts[i]);
|
||||
for (i = 0; i < lenof(xfont->fonts); i++) {
|
||||
if (xfont->fonts[i].xfs)
|
||||
XFreeFont(disp, xfont->fonts[i].xfs);
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (xfont->fonts[i].gc != None)
|
||||
XFreeGC(disp, xfont->fonts[i].gc);
|
||||
if (xfont->fonts[i].pixmap != None)
|
||||
XFreePixmap(disp, xfont->fonts[i].pixmap);
|
||||
if (xfont->fonts[i].glyphcache) {
|
||||
int j;
|
||||
for (j = 0; j < xfont->fonts[i].nglyphs; j++) {
|
||||
cairo_surface_destroy(xfont->fonts[i].glyphcache[j].surface);
|
||||
sfree(xfont->fonts[i].glyphcache[j].bitmap);
|
||||
}
|
||||
sfree(xfont->fonts[i].glyphcache);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
sfree(font);
|
||||
}
|
||||
|
||||
@ -415,11 +484,11 @@ static void x11_alloc_subfont(struct x11font *xfont, int sfid)
|
||||
{
|
||||
Display *disp = GDK_DISPLAY();
|
||||
char *derived_name = x11_guess_derived_font_name
|
||||
(xfont->fonts[0], sfid & 1, !!(sfid & 2));
|
||||
xfont->fonts[sfid] = XLoadQueryFont(disp, derived_name);
|
||||
xfont->allocated[sfid] = TRUE;
|
||||
(xfont->fonts[0].xfs, sfid & 1, !!(sfid & 2));
|
||||
xfont->fonts[sfid].xfs = XLoadQueryFont(disp, derived_name);
|
||||
xfont->fonts[sfid].allocated = TRUE;
|
||||
sfree(derived_name);
|
||||
/* Note that xfont->fonts[sfid] may still be NULL, if XLQF failed. */
|
||||
/* Note that xfont->fonts[sfid].xfs may still be NULL, if XLQF failed. */
|
||||
}
|
||||
|
||||
static int x11font_has_glyph(unifont *font, wchar_t glyph)
|
||||
@ -431,7 +500,8 @@ static int x11font_has_glyph(unifont *font, wchar_t glyph)
|
||||
* This X font has 16-bit character indices, which means
|
||||
* we can directly use our Unicode input value.
|
||||
*/
|
||||
return x11_font_has_glyph(xfont->fonts[0], glyph >> 8, glyph & 0xFF);
|
||||
return x11_font_has_glyph(xfont->fonts[0].xfs,
|
||||
glyph >> 8, glyph & 0xFF);
|
||||
} else {
|
||||
/*
|
||||
* This X font has 8-bit indices, so we must convert to the
|
||||
@ -443,7 +513,7 @@ static int x11font_has_glyph(unifont *font, wchar_t glyph)
|
||||
if (sblen == 0 || !sbstring[0])
|
||||
return FALSE; /* not even in the charset */
|
||||
|
||||
return x11_font_has_glyph(xfont->fonts[0], 0,
|
||||
return x11_font_has_glyph(xfont->fonts[0].xfs, 0,
|
||||
(unsigned char)sbstring[0]);
|
||||
}
|
||||
}
|
||||
@ -452,56 +522,243 @@ static int x11font_has_glyph(unifont *font, wchar_t glyph)
|
||||
#define GDK_DRAWABLE_XID(d) GDK_WINDOW_XWINDOW(d) /* GTK1's name for this */
|
||||
#endif
|
||||
|
||||
static void x11font_really_draw_text_16(GdkDrawable *target, XFontStruct *xfs,
|
||||
GC gc, int x, int y,
|
||||
const XChar2b *string, int nchars,
|
||||
int shadowoffset,
|
||||
int fontvariable, int cellwidth)
|
||||
static int x11font_width_16(unifont_drawctx *ctx, x11font_individual *xfi,
|
||||
const void *vstring, int start, int length)
|
||||
{
|
||||
Display *disp = GDK_DISPLAY();
|
||||
int step, nsteps, centre;
|
||||
const XChar2b *string = (const XChar2b *)vstring;
|
||||
return XTextWidth16(xfi->xfs, string+start, length);
|
||||
}
|
||||
|
||||
if (fontvariable) {
|
||||
/*
|
||||
* In a variable-pitch font, we draw one character at a
|
||||
* time, and centre it in the character cell.
|
||||
*/
|
||||
step = 1;
|
||||
nsteps = nchars;
|
||||
centre = TRUE;
|
||||
} else {
|
||||
/*
|
||||
* In a fixed-pitch font, we can draw the whole lot in one go.
|
||||
*/
|
||||
step = nchars;
|
||||
nsteps = 1;
|
||||
centre = FALSE;
|
||||
}
|
||||
static int x11font_width_8(unifont_drawctx *ctx, x11font_individual *xfi,
|
||||
const void *vstring, int start, int length)
|
||||
{
|
||||
const char *string = (const char *)vstring;
|
||||
return XTextWidth(xfi->xfs, string+start, length);
|
||||
}
|
||||
|
||||
while (nsteps-- > 0) {
|
||||
int X = x;
|
||||
if (centre)
|
||||
X += (cellwidth - XTextWidth16(xfs, string, step)) / 2;
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
static void x11font_gdk_setup(unifont_drawctx *ctx, x11font_individual *xfi)
|
||||
{
|
||||
XSetFont(GDK_DISPLAY(), GDK_GC_XGC(ctx->u.gdk.gc), xfi->xfs->fid);
|
||||
}
|
||||
|
||||
XDrawString16(disp, GDK_DRAWABLE_XID(target), gc,
|
||||
X, y, string, step);
|
||||
if (shadowoffset)
|
||||
XDrawString16(disp, GDK_DRAWABLE_XID(target), gc,
|
||||
X + shadowoffset, y, string, step);
|
||||
static void x11font_gdk_draw_16(unifont_drawctx *ctx,
|
||||
x11font_individual *xfi, int x, int y,
|
||||
const void *vstring, int start, int length)
|
||||
{
|
||||
const XChar2b *string = (const XChar2b *)vstring;
|
||||
XDrawString16(GDK_DISPLAY(), GDK_DRAWABLE_XID(ctx->u.gdk.target),
|
||||
GDK_GC_XGC(ctx->u.gdk.gc), x, y, string+start, length);
|
||||
}
|
||||
|
||||
x += cellwidth;
|
||||
string += step;
|
||||
static void x11font_gdk_draw_8(unifont_drawctx *ctx,
|
||||
x11font_individual *xfi, int x, int y,
|
||||
const void *vstring, int start, int length)
|
||||
{
|
||||
const char *string = (const char *)vstring;
|
||||
XDrawString(GDK_DISPLAY(), GDK_DRAWABLE_XID(ctx->u.gdk.target),
|
||||
GDK_GC_XGC(ctx->u.gdk.gc), x, y, string+start, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
static void x11font_cairo_setup(unifont_drawctx *ctx, x11font_individual *xfi)
|
||||
{
|
||||
if (xfi->pixmap == None) {
|
||||
XGCValues gcvals;
|
||||
GdkWindow *widgetwin = gtk_widget_get_window(ctx->u.cairo.widget);
|
||||
int widgetscr = GDK_SCREEN_XNUMBER(gdk_window_get_screen(widgetwin));
|
||||
|
||||
xfi->pixwidth =
|
||||
xfi->xfs->max_bounds.rbearing - xfi->xfs->min_bounds.lbearing;
|
||||
xfi->pixheight =
|
||||
xfi->xfs->max_bounds.ascent + xfi->xfs->max_bounds.descent;
|
||||
xfi->pixoriginx = -xfi->xfs->min_bounds.lbearing;
|
||||
xfi->pixoriginy = xfi->xfs->max_bounds.ascent;
|
||||
|
||||
xfi->rowsize = cairo_format_stride_for_width(CAIRO_FORMAT_A1,
|
||||
xfi->pixwidth);
|
||||
xfi->allsize = xfi->rowsize * xfi->pixheight;
|
||||
|
||||
{
|
||||
/*
|
||||
* Test host endianness and use it to set xfi->indexflip,
|
||||
* which is XORed into our left-shift counts in order to
|
||||
* implement the CAIRO_FORMAT_A1 specification, in which
|
||||
* each bitmap byte is oriented LSB-first on little-endian
|
||||
* platforms and MSB-first on big-endian ones.
|
||||
*
|
||||
* This is the same technique Cairo itself uses to test
|
||||
* endianness, so hopefully it'll work in any situation
|
||||
* where Cairo is usable at all.
|
||||
*/
|
||||
static const int endianness_test = 1;
|
||||
xfi->indexflip = (*((char *) &endianness_test) == 1) ? 0 : 7;
|
||||
}
|
||||
|
||||
xfi->pixmap = XCreatePixmap
|
||||
(GDK_DISPLAY(),
|
||||
GDK_DRAWABLE_XID(gtk_widget_get_window(ctx->u.cairo.widget)),
|
||||
xfi->pixwidth, xfi->pixheight, 1);
|
||||
gcvals.foreground = WhitePixel(GDK_DISPLAY(), widgetscr);
|
||||
gcvals.background = BlackPixel(GDK_DISPLAY(), widgetscr);
|
||||
gcvals.font = xfi->xfs->fid;
|
||||
xfi->gc = XCreateGC(GDK_DISPLAY(), xfi->pixmap,
|
||||
GCForeground | GCBackground | GCFont, &gcvals);
|
||||
}
|
||||
}
|
||||
|
||||
static void x11font_really_draw_text(GdkDrawable *target, XFontStruct *xfs,
|
||||
GC gc, int x, int y,
|
||||
const char *string, int nchars,
|
||||
static void x11font_cairo_cache_glyph(x11font_individual *xfi, int glyphindex)
|
||||
{
|
||||
XImage *image;
|
||||
int x, y;
|
||||
unsigned char *bitmap;
|
||||
|
||||
bitmap = snewn(xfi->allsize, unsigned char);
|
||||
memset(bitmap, 0, xfi->allsize);
|
||||
|
||||
image = XGetImage(GDK_DISPLAY(), xfi->pixmap, 0, 0,
|
||||
xfi->pixwidth, xfi->pixheight, AllPlanes, XYPixmap);
|
||||
for (y = 0; y < xfi->pixheight; y++) {
|
||||
for (x = 0; x < xfi->pixwidth; x++) {
|
||||
unsigned long pixel = XGetPixel(image, x, y);
|
||||
if (pixel) {
|
||||
int byteindex = y * xfi->rowsize + x/8;
|
||||
int bitindex = (x & 7) ^ xfi->indexflip;
|
||||
bitmap[byteindex] |= 1U << bitindex;
|
||||
}
|
||||
}
|
||||
}
|
||||
XDestroyImage(image);
|
||||
|
||||
if (xfi->nglyphs <= glyphindex) {
|
||||
/* Round up to the next multiple of 256 on the general
|
||||
* principle that Unicode characters come in contiguous blocks
|
||||
* often used together */
|
||||
int old_nglyphs = xfi->nglyphs;
|
||||
xfi->nglyphs = (glyphindex + 0xFF) & ~0xFF;
|
||||
xfi->glyphcache = sresize(xfi->glyphcache, xfi->nglyphs,
|
||||
struct cairo_cached_glyph);
|
||||
|
||||
while (old_nglyphs < xfi->nglyphs) {
|
||||
xfi->glyphcache[old_nglyphs].surface = NULL;
|
||||
xfi->glyphcache[old_nglyphs].bitmap = NULL;
|
||||
old_nglyphs++;
|
||||
}
|
||||
}
|
||||
xfi->glyphcache[glyphindex].bitmap = bitmap;
|
||||
xfi->glyphcache[glyphindex].surface = cairo_image_surface_create_for_data
|
||||
(bitmap, CAIRO_FORMAT_A1, xfi->pixwidth, xfi->pixheight, xfi->rowsize);
|
||||
}
|
||||
|
||||
static void x11font_cairo_draw_glyph(unifont_drawctx *ctx,
|
||||
x11font_individual *xfi, int x, int y,
|
||||
int glyphindex)
|
||||
{
|
||||
if (xfi->glyphcache[glyphindex].surface) {
|
||||
cairo_mask_surface(ctx->u.cairo.cr,
|
||||
xfi->glyphcache[glyphindex].surface,
|
||||
x - xfi->pixoriginx, y - xfi->pixoriginy);
|
||||
}
|
||||
}
|
||||
|
||||
static void x11font_cairo_draw_16(unifont_drawctx *ctx,
|
||||
x11font_individual *xfi, int x, int y,
|
||||
const void *vstring, int start, int length)
|
||||
{
|
||||
const XChar2b *string = (const XChar2b *)vstring + start;
|
||||
int i;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (x11_font_has_glyph(xfi->xfs, string[i].byte1, string[i].byte2)) {
|
||||
int glyphindex = (256 * (unsigned char)string[i].byte1 +
|
||||
(unsigned char)string[i].byte2);
|
||||
if (glyphindex >= xfi->nglyphs ||
|
||||
!xfi->glyphcache[glyphindex].surface) {
|
||||
XDrawImageString16(GDK_DISPLAY(), xfi->pixmap, xfi->gc,
|
||||
xfi->pixoriginx, xfi->pixoriginy,
|
||||
string+i, 1);
|
||||
x11font_cairo_cache_glyph(xfi, glyphindex);
|
||||
}
|
||||
x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
|
||||
x += XTextWidth16(xfi->xfs, string+i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void x11font_cairo_draw_8(unifont_drawctx *ctx,
|
||||
x11font_individual *xfi, int x, int y,
|
||||
const void *vstring, int start, int length)
|
||||
{
|
||||
const char *string = (const char *)vstring + start;
|
||||
int i;
|
||||
for (i = 0; i < length; i++) {
|
||||
if (x11_font_has_glyph(xfi->xfs, 0, string[i])) {
|
||||
int glyphindex = (unsigned char)string[i];
|
||||
if (glyphindex >= xfi->nglyphs ||
|
||||
!xfi->glyphcache[glyphindex].surface) {
|
||||
XDrawImageString(GDK_DISPLAY(), xfi->pixmap, xfi->gc,
|
||||
xfi->pixoriginx, xfi->pixoriginy,
|
||||
string+i, 1);
|
||||
x11font_cairo_cache_glyph(xfi, glyphindex);
|
||||
}
|
||||
x11font_cairo_draw_glyph(ctx, xfi, x, y, glyphindex);
|
||||
x += XTextWidth(xfi->xfs, string+i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DRAW_TEXT_CAIRO */
|
||||
|
||||
struct x11font_drawfuncs {
|
||||
int (*width)(unifont_drawctx *ctx, x11font_individual *xfi,
|
||||
const void *vstring, int start, int length);
|
||||
void (*setup)(unifont_drawctx *ctx, x11font_individual *xfi);
|
||||
void (*draw)(unifont_drawctx *ctx, x11font_individual *xfi, int x, int y,
|
||||
const void *vstring, int start, int length);
|
||||
};
|
||||
|
||||
/*
|
||||
* This array has two entries per compiled-in drawtype; of each pair,
|
||||
* the first is for an 8-bit font and the second for 16-bit.
|
||||
*/
|
||||
static const struct x11font_drawfuncs x11font_drawfuncs[2*DRAWTYPE_NTYPES] = {
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
/* gdk, 8-bit */
|
||||
{
|
||||
x11font_width_8,
|
||||
x11font_gdk_setup,
|
||||
x11font_gdk_draw_8,
|
||||
},
|
||||
/* gdk, 16-bit */
|
||||
{
|
||||
x11font_width_16,
|
||||
x11font_gdk_setup,
|
||||
x11font_gdk_draw_16,
|
||||
},
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
/* cairo, 8-bit */
|
||||
{
|
||||
x11font_width_8,
|
||||
x11font_cairo_setup,
|
||||
x11font_cairo_draw_8,
|
||||
},
|
||||
/* [3] cairo, 16-bit */
|
||||
{
|
||||
x11font_width_16,
|
||||
x11font_cairo_setup,
|
||||
x11font_cairo_draw_16,
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static void x11font_really_draw_text(const struct x11font_drawfuncs *dfns,
|
||||
unifont_drawctx *ctx,
|
||||
x11font_individual *xfi, int x, int y,
|
||||
const void *string, int nchars,
|
||||
int shadowoffset,
|
||||
int fontvariable, int cellwidth)
|
||||
{
|
||||
Display *disp = GDK_DISPLAY();
|
||||
int step, nsteps, centre;
|
||||
int start = 0, step, nsteps, centre;
|
||||
|
||||
if (fontvariable) {
|
||||
/*
|
||||
@ -520,32 +777,31 @@ static void x11font_really_draw_text(GdkDrawable *target, XFontStruct *xfs,
|
||||
centre = FALSE;
|
||||
}
|
||||
|
||||
dfns->setup(ctx, xfi);
|
||||
|
||||
while (nsteps-- > 0) {
|
||||
int X = x;
|
||||
if (centre)
|
||||
X += (cellwidth - XTextWidth(xfs, string, step)) / 2;
|
||||
X += (cellwidth - dfns->width(ctx, xfi, string, start, step)) / 2;
|
||||
|
||||
XDrawString(disp, GDK_DRAWABLE_XID(target), gc,
|
||||
X, y, string, step);
|
||||
dfns->draw(ctx, xfi, X, y, string, start, step);
|
||||
if (shadowoffset)
|
||||
XDrawString(disp, GDK_DRAWABLE_XID(target), gc,
|
||||
X + shadowoffset, y, string, step);
|
||||
dfns->draw(ctx, xfi, X + shadowoffset, y, string, start, step);
|
||||
|
||||
x += cellwidth;
|
||||
string += step;
|
||||
start += step;
|
||||
}
|
||||
}
|
||||
|
||||
static void x11font_draw_text(GdkDrawable *target, GdkGC *gdkgc, unifont *font,
|
||||
static void x11font_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth)
|
||||
{
|
||||
Display *disp = GDK_DISPLAY();
|
||||
struct x11font *xfont = (struct x11font *)font;
|
||||
GC gc = GDK_GC_XGC(gdkgc);
|
||||
int sfid;
|
||||
int shadowoffset = 0;
|
||||
int mult = (wide ? 2 : 1);
|
||||
int index = 2 * (int)ctx->type;
|
||||
|
||||
wide -= xfont->wide;
|
||||
bold -= xfont->bold;
|
||||
@ -559,21 +815,19 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gdkgc, unifont *font,
|
||||
bold = 0;
|
||||
}
|
||||
sfid = 2 * wide + bold;
|
||||
if (!xfont->allocated[sfid])
|
||||
if (!xfont->fonts[sfid].allocated)
|
||||
x11_alloc_subfont(xfont, sfid);
|
||||
if (bold && !xfont->fonts[sfid]) {
|
||||
if (bold && !xfont->fonts[sfid].xfs) {
|
||||
bold = 0;
|
||||
shadowoffset = xfont->shadowoffset;
|
||||
sfid = 2 * wide + bold;
|
||||
if (!xfont->allocated[sfid])
|
||||
if (!xfont->fonts[sfid].allocated)
|
||||
x11_alloc_subfont(xfont, sfid);
|
||||
}
|
||||
|
||||
if (!xfont->fonts[sfid])
|
||||
if (!xfont->fonts[sfid].xfs)
|
||||
return; /* we've tried our best, but no luck */
|
||||
|
||||
XSetFont(disp, gc, xfont->fonts[sfid]->fid);
|
||||
|
||||
if (xfont->sixteen_bit) {
|
||||
/*
|
||||
* This X font has 16-bit character indices, which means
|
||||
@ -588,9 +842,10 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gdkgc, unifont *font,
|
||||
xcs[i].byte2 = string[i];
|
||||
}
|
||||
|
||||
x11font_really_draw_text_16(target, xfont->fonts[sfid], gc, x, y,
|
||||
xcs, len, shadowoffset,
|
||||
xfont->variable, cellwidth * mult);
|
||||
x11font_really_draw_text(x11font_drawfuncs + index + 1, ctx,
|
||||
&xfont->fonts[sfid], x, y,
|
||||
xcs, len, shadowoffset,
|
||||
xfont->variable, cellwidth * mult);
|
||||
sfree(xcs);
|
||||
} else {
|
||||
/*
|
||||
@ -600,7 +855,8 @@ static void x11font_draw_text(GdkDrawable *target, GdkGC *gdkgc, unifont *font,
|
||||
char *sbstring = snewn(len+1, char);
|
||||
int sblen = wc_to_mb(xfont->real_charset, 0, string, len,
|
||||
sbstring, len+1, ".", NULL, NULL);
|
||||
x11font_really_draw_text(target, xfont->fonts[sfid], gc, x, y,
|
||||
x11font_really_draw_text(x11font_drawfuncs + index + 0, ctx,
|
||||
&xfont->fonts[sfid], x, y,
|
||||
sbstring, sblen, shadowoffset,
|
||||
xfont->variable, cellwidth * mult);
|
||||
sfree(sbstring);
|
||||
@ -847,9 +1103,9 @@ static char *x11font_scale_fontname(GtkWidget *widget, const char *name,
|
||||
#endif
|
||||
|
||||
static int pangofont_has_glyph(unifont *font, wchar_t glyph);
|
||||
static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
static unifont *pangofont_create(GtkWidget *widget, const char *name,
|
||||
int wide, int bold,
|
||||
int shadowoffset, int shadowalways);
|
||||
@ -988,6 +1244,13 @@ static unifont *pangofont_create_internal(GtkWidget *widget,
|
||||
pfont->u.descent = PANGO_PIXELS(pango_font_metrics_get_descent(metrics));
|
||||
pfont->u.height = pfont->u.ascent + pfont->u.descent;
|
||||
pfont->u.want_fallback = FALSE;
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
pfont->u.preferred_drawtype = DRAWTYPE_CAIRO;
|
||||
#elif defined DRAW_TEXT_GDK
|
||||
pfont->u.preferred_drawtype = DRAWTYPE_GDK;
|
||||
#else
|
||||
#error No drawtype available at all
|
||||
#endif
|
||||
/* The Pango API is hardwired to UTF-8 */
|
||||
pfont->u.public_charset = CS_UTF8;
|
||||
pfont->desc = desc;
|
||||
@ -1059,9 +1322,26 @@ static int pangofont_has_glyph(unifont *font, wchar_t glyph)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth)
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
static void pango_gdk_draw_layout(unifont_drawctx *ctx,
|
||||
gint x, gint y, PangoLayout *layout)
|
||||
{
|
||||
gdk_draw_layout(ctx->u.gdk.target, ctx->u.gdk.gc, x, y, layout);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
static void pango_cairo_draw_layout(unifont_drawctx *ctx,
|
||||
gint x, gint y, PangoLayout *layout)
|
||||
{
|
||||
cairo_move_to(ctx->u.cairo.cr, x, y);
|
||||
pango_cairo_show_layout(ctx->u.cairo.cr, layout);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void pangofont_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth)
|
||||
{
|
||||
struct pangofont *pfont = (struct pangofont *)font;
|
||||
PangoLayout *layout;
|
||||
@ -1069,6 +1349,19 @@ static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
char *utfstring, *utfptr;
|
||||
int utflen;
|
||||
int shadowbold = FALSE;
|
||||
void (*draw_layout)(unifont_drawctx *ctx,
|
||||
gint x, gint y, PangoLayout *layout) = NULL;
|
||||
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (ctx->type == DRAWTYPE_GDK) {
|
||||
draw_layout = pango_gdk_draw_layout;
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (ctx->type == DRAWTYPE_CAIRO) {
|
||||
draw_layout = pango_cairo_draw_layout;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wide)
|
||||
cellwidth *= 2;
|
||||
@ -1174,11 +1467,14 @@ static void pangofont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
|
||||
pango_layout_set_text(layout, utfptr, clen);
|
||||
pango_layout_get_pixel_extents(layout, NULL, &rect);
|
||||
gdk_draw_layout(target, gc, x + (n*cellwidth - rect.width)/2,
|
||||
y + (pfont->u.height - rect.height)/2, layout);
|
||||
|
||||
draw_layout(ctx,
|
||||
x + (n*cellwidth - rect.width)/2,
|
||||
y + (pfont->u.height - rect.height)/2, layout);
|
||||
if (shadowbold)
|
||||
gdk_draw_layout(target, gc, x + (n*cellwidth - rect.width)/2 + pfont->shadowoffset,
|
||||
y + (pfont->u.height - rect.height)/2, layout);
|
||||
draw_layout(ctx,
|
||||
x + (n*cellwidth - rect.width)/2 + pfont->shadowoffset,
|
||||
y + (pfont->u.height - rect.height)/2, layout);
|
||||
|
||||
utflen -= clen;
|
||||
utfptr += clen;
|
||||
@ -1529,12 +1825,11 @@ void unifont_destroy(unifont *font)
|
||||
font->vt->destroy(font);
|
||||
}
|
||||
|
||||
void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth)
|
||||
{
|
||||
font->vt->draw_text(target, gc, font, x, y, string, len,
|
||||
wide, bold, cellwidth);
|
||||
font->vt->draw_text(ctx, font, x, y, string, len, wide, bold, cellwidth);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
@ -1550,9 +1845,9 @@ void unifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
* destroy.
|
||||
*/
|
||||
|
||||
static void multifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
static void multifont_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
static void multifont_destroy(unifont *font);
|
||||
|
||||
struct multifont {
|
||||
@ -1611,6 +1906,7 @@ unifont *multifont_create(GtkWidget *widget, const char *name,
|
||||
mfont->u.height = font->height;
|
||||
mfont->u.public_charset = font->public_charset;
|
||||
mfont->u.want_fallback = FALSE; /* shouldn't be needed, but just in case */
|
||||
mfont->u.preferred_drawtype = font->preferred_drawtype;
|
||||
mfont->main = font;
|
||||
mfont->fallback = fallback;
|
||||
|
||||
@ -1626,9 +1922,9 @@ static void multifont_destroy(unifont *font)
|
||||
sfree(font);
|
||||
}
|
||||
|
||||
static void multifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth)
|
||||
static void multifont_draw_text(unifont_drawctx *ctx, unifont *font, int x,
|
||||
int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth)
|
||||
{
|
||||
struct multifont *mfont = (struct multifont *)font;
|
||||
unifont *f;
|
||||
@ -1650,8 +1946,7 @@ static void multifont_draw_text(GdkDrawable *target, GdkGC *gc, unifont *font,
|
||||
*/
|
||||
f = ok ? mfont->main : mfont->fallback;
|
||||
if (f)
|
||||
unifont_draw_text(target, gc, f, x, y, string, i, wide, bold,
|
||||
cellwidth);
|
||||
unifont_draw_text(ctx, f, x, y, string, i, wide, bold, cellwidth);
|
||||
string += i;
|
||||
len -= i;
|
||||
x += i * cellwidth;
|
||||
@ -2006,11 +2301,33 @@ static void unifontsel_draw_preview_text(unifontsel_internal *fs)
|
||||
font = NULL;
|
||||
|
||||
if (fs->preview_pixmap) {
|
||||
GdkGC *gc = gdk_gc_new(fs->preview_pixmap);
|
||||
gdk_gc_set_foreground(gc, &fs->preview_bg);
|
||||
gdk_draw_rectangle(fs->preview_pixmap, gc, 1, 0, 0,
|
||||
fs->preview_width, fs->preview_height);
|
||||
gdk_gc_set_foreground(gc, &fs->preview_fg);
|
||||
unifont_drawctx dctx;
|
||||
dctx.type = DRAWTYPE_DEFAULT;
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx.type == DRAWTYPE_GDK) {
|
||||
dctx.u.gdk.target = fs->preview_pixmap;
|
||||
dctx.u.gdk.gc = gdk_gc_new(fs->preview_pixmap);
|
||||
gdk_gc_set_foreground(dctx.u.gdk.gc, &fs->preview_bg);
|
||||
gdk_draw_rectangle(fs->preview_pixmap, dctx.u.gdk.gc, 1, 0, 0,
|
||||
fs->preview_width, fs->preview_height);
|
||||
gdk_gc_set_foreground(dctx.u.gdk.gc, &fs->preview_fg);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx.type == DRAWTYPE_CAIRO) {
|
||||
dctx.u.cairo.widget = GTK_WIDGET(fs->preview_area);
|
||||
dctx.u.cairo.cr = gdk_cairo_create(fs->preview_pixmap);
|
||||
cairo_set_source_rgb(dctx.u.cairo.cr,
|
||||
fs->preview_bg.red / 65535.0,
|
||||
fs->preview_bg.green / 65535.0,
|
||||
fs->preview_bg.blue / 65535.0);
|
||||
cairo_paint(dctx.u.cairo.cr);
|
||||
cairo_set_source_rgb(dctx.u.cairo.cr,
|
||||
fs->preview_fg.red / 65535.0,
|
||||
fs->preview_fg.green / 65535.0,
|
||||
fs->preview_fg.blue / 65535.0);
|
||||
}
|
||||
#endif
|
||||
if (font) {
|
||||
/*
|
||||
* The pangram used here is rather carefully
|
||||
@ -2033,14 +2350,14 @@ static void unifontsel_draw_preview_text(unifontsel_internal *fs)
|
||||
* that they go to the effort of selecting their font
|
||||
* and _then_ realise it was a mistake.
|
||||
*/
|
||||
info->fontclass->draw_text(fs->preview_pixmap, gc, font,
|
||||
0, font->ascent,
|
||||
L"bankrupt jilted showmen quiz convex fogey",
|
||||
41, FALSE, FALSE, font->width);
|
||||
info->fontclass->draw_text(fs->preview_pixmap, gc, font,
|
||||
0, font->ascent + font->height,
|
||||
L"BANKRUPT JILTED SHOWMEN QUIZ CONVEX FOGEY",
|
||||
41, FALSE, FALSE, font->width);
|
||||
info->fontclass->draw_text(&dctx, font,
|
||||
0, font->ascent,
|
||||
L"bankrupt jilted showmen quiz convex fogey",
|
||||
41, FALSE, FALSE, font->width);
|
||||
info->fontclass->draw_text(&dctx, font,
|
||||
0, font->ascent + font->height,
|
||||
L"BANKRUPT JILTED SHOWMEN QUIZ CONVEX FOGEY",
|
||||
41, FALSE, FALSE, font->width);
|
||||
/*
|
||||
* The ordering of punctuation here is also selected
|
||||
* with some specific aims in mind. I put ` and '
|
||||
@ -2053,12 +2370,23 @@ static void unifontsel_draw_preview_text(unifontsel_internal *fs)
|
||||
* alphabetic character (since that's how it's often
|
||||
* used in practice, at least by programmers).
|
||||
*/
|
||||
info->fontclass->draw_text(fs->preview_pixmap, gc, font,
|
||||
0, font->ascent + font->height * 2,
|
||||
L"0123456789!?,.:;<>()[]{}\\/`'\"+*-=~#_@|%&^$",
|
||||
42, FALSE, FALSE, font->width);
|
||||
info->fontclass->draw_text(&dctx, font,
|
||||
0, font->ascent + font->height * 2,
|
||||
L"0123456789!?,.:;<>()[]{}\\/`'\"+*-=~#_@|%&^$",
|
||||
42, FALSE, FALSE, font->width);
|
||||
}
|
||||
gdk_gc_unref(gc);
|
||||
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx.type == DRAWTYPE_GDK) {
|
||||
gdk_gc_unref(dctx.u.gdk.gc);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_destroy(dctx.u.cairo.cr);
|
||||
}
|
||||
#endif
|
||||
|
||||
gdk_window_invalidate_rect(gtk_widget_get_window(fs->preview_area),
|
||||
NULL, FALSE);
|
||||
}
|
||||
|
@ -7,6 +7,28 @@
|
||||
#ifndef PUTTY_GTKFONT_H
|
||||
#define PUTTY_GTKFONT_H
|
||||
|
||||
/*
|
||||
* We support two entirely different drawing systems: the old
|
||||
* GDK1/GDK2 one which works on server-side X drawables, and the
|
||||
* new-style Cairo one. GTK1 only supports GDK drawing; GTK3 only
|
||||
* supports Cairo; GTK2 supports both, but deprecates GTK, so we only
|
||||
* enable it if we aren't trying on purpose to compile without the
|
||||
* deprecated functions.
|
||||
*
|
||||
* Our different font classes may prefer different drawing systems: X
|
||||
* server-side fonts are a lot faster to draw with GDK, but for
|
||||
* everything else we prefer Cairo, on general grounds of modernness
|
||||
* and also in particular because its matrix-based scaling system
|
||||
* gives much nicer results for double-width and double-height text
|
||||
* when a scalable font is in use.
|
||||
*/
|
||||
#if !GTK_CHECK_VERSION(3,0,0) && !defined GDK_DISABLE_DEPRECATED
|
||||
#define DRAW_TEXT_GDK
|
||||
#endif
|
||||
#if GTK_CHECK_VERSION(2,8,0)
|
||||
#define DRAW_TEXT_CAIRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Exports from gtkfont.c.
|
||||
*/
|
||||
@ -36,15 +58,67 @@ typedef struct unifont {
|
||||
* fallback font to cope with missing glyphs.
|
||||
*/
|
||||
int want_fallback;
|
||||
|
||||
/*
|
||||
* Preferred drawing API to use when this class of font is active.
|
||||
* (See the enum below, in unifont_drawctx.)
|
||||
*/
|
||||
int preferred_drawtype;
|
||||
} unifont;
|
||||
|
||||
/* A default drawtype, for the case where no font exists to make the
|
||||
* decision with. */
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
#define DRAW_DEFAULT_CAIRO
|
||||
#define DRAWTYPE_DEFAULT DRAWTYPE_CAIRO
|
||||
#elif defined DRAW_TEXT_GDK
|
||||
#define DRAW_DEFAULT_GDK
|
||||
#define DRAWTYPE_DEFAULT DRAWTYPE_GDK
|
||||
#else
|
||||
#error No drawtype available at all
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drawing context passed in to unifont_draw_text, which contains
|
||||
* everything required to know where and how to draw the requested
|
||||
* text.
|
||||
*/
|
||||
typedef struct unifont_drawctx {
|
||||
enum {
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
DRAWTYPE_GDK,
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
DRAWTYPE_CAIRO,
|
||||
#endif
|
||||
DRAWTYPE_NTYPES
|
||||
} type;
|
||||
union {
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
struct {
|
||||
GdkDrawable *target;
|
||||
GdkGC *gc;
|
||||
} gdk;
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
struct {
|
||||
/* Need an actual widget, in order to backtrack to its X
|
||||
* screen number when creating server-side pixmaps */
|
||||
GtkWidget *widget;
|
||||
cairo_t *cr;
|
||||
cairo_matrix_t origmatrix;
|
||||
} cairo;
|
||||
#endif
|
||||
} u;
|
||||
} unifont_drawctx;
|
||||
|
||||
unifont *unifont_create(GtkWidget *widget, const 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 wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
void unifont_draw_text(unifont_drawctx *ctx, unifont *font,
|
||||
int x, int y, const wchar_t *string, int len,
|
||||
int wide, int bold, int cellwidth);
|
||||
|
||||
/*
|
||||
* This function behaves exactly like the low-level unifont_create,
|
||||
|
397
unix/gtkwin.c
397
unix/gtkwin.c
@ -126,6 +126,7 @@ struct gui_data {
|
||||
int bold_style;
|
||||
int window_border;
|
||||
int cursor_type;
|
||||
int drawtype;
|
||||
};
|
||||
|
||||
static void cache_conf_values(struct gui_data *inst)
|
||||
@ -136,8 +137,8 @@ static void cache_conf_values(struct gui_data *inst)
|
||||
}
|
||||
|
||||
struct draw_ctx {
|
||||
GdkGC *gc;
|
||||
struct gui_data *inst;
|
||||
unifont_drawctx uctx;
|
||||
};
|
||||
|
||||
static int send_raw_mouse;
|
||||
@ -469,15 +470,7 @@ static void show_mouseptr(struct gui_data *inst, int show)
|
||||
update_mouseptr(inst);
|
||||
}
|
||||
|
||||
void draw_backing_rect(struct gui_data *inst)
|
||||
{
|
||||
GdkGC *gc = gdk_gc_new(gtk_widget_get_window(inst->area));
|
||||
gdk_gc_set_foreground(gc, &inst->cols[258]); /* default background */
|
||||
gdk_draw_rectangle(inst->pixmap, gc, 1, 0, 0,
|
||||
inst->width * inst->font_width + 2*inst->window_border,
|
||||
inst->height * inst->font_height + 2*inst->window_border);
|
||||
gdk_gc_unref(gc);
|
||||
}
|
||||
static void draw_backing_rect(struct gui_data *inst);
|
||||
|
||||
gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
|
||||
{
|
||||
@ -2296,7 +2289,29 @@ Context get_ctx(void *frontend)
|
||||
|
||||
dctx = snew(struct draw_ctx);
|
||||
dctx->inst = inst;
|
||||
dctx->gc = gdk_gc_new(gtk_widget_get_window(inst->area));
|
||||
dctx->uctx.type = inst->drawtype;
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
dctx->uctx.u.gdk.target = inst->pixmap;
|
||||
dctx->uctx.u.gdk.gc = gdk_gc_new(gtk_widget_get_window(inst->area));
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
dctx->uctx.u.cairo.widget = GTK_WIDGET(inst->area);
|
||||
dctx->uctx.u.cairo.cr = gdk_cairo_create(inst->pixmap);
|
||||
cairo_get_matrix(dctx->uctx.u.cairo.cr,
|
||||
&dctx->uctx.u.cairo.origmatrix);
|
||||
cairo_set_line_width(dctx->uctx.u.cairo.cr, 1.0);
|
||||
cairo_set_line_cap(dctx->uctx.u.cairo.cr, CAIRO_LINE_CAP_SQUARE);
|
||||
cairo_set_line_join(dctx->uctx.u.cairo.cr, CAIRO_LINE_JOIN_MITER);
|
||||
/* This antialiasing setting appears to be ignored for Pango
|
||||
* font rendering but honoured for stroking and filling paths;
|
||||
* I don't quite understand the logic of that, but I won't
|
||||
* complain since it's exactly what I happen to want */
|
||||
cairo_set_antialias(dctx->uctx.u.cairo.cr, CAIRO_ANTIALIAS_NONE);
|
||||
}
|
||||
#endif
|
||||
return dctx;
|
||||
}
|
||||
|
||||
@ -2304,11 +2319,237 @@ void free_ctx(Context ctx)
|
||||
{
|
||||
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
|
||||
/* struct gui_data *inst = dctx->inst; */
|
||||
GdkGC *gc = dctx->gc;
|
||||
gdk_gc_unref(gc);
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
gdk_gc_unref(dctx->uctx.u.gdk.gc);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_destroy(dctx->uctx.u.cairo.cr);
|
||||
}
|
||||
#endif
|
||||
sfree(dctx);
|
||||
}
|
||||
|
||||
|
||||
static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h)
|
||||
{
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
gdk_draw_pixmap(gtk_widget_get_window(dctx->inst->area),
|
||||
dctx->uctx.u.gdk.gc, dctx->inst->pixmap,
|
||||
x, y, x, y, w, h);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO /* FIXME: and not GTK3 where a cairo_t is all we have */
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
GdkGC *gc = gdk_gc_new(gtk_widget_get_window(dctx->inst->area));
|
||||
gdk_draw_pixmap(gtk_widget_get_window(dctx->inst->area),
|
||||
gc, dctx->inst->pixmap, x, y, x, y, w, h);
|
||||
gdk_gc_unref(gc);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_set_colour(struct draw_ctx *dctx, int col)
|
||||
{
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
gdk_gc_set_foreground(dctx->uctx.u.gdk.gc, &dctx->inst->cols[col]);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_set_source_rgb(dctx->uctx.u.cairo.cr,
|
||||
dctx->inst->cols[col].red / 65535.0,
|
||||
dctx->inst->cols[col].green / 65535.0,
|
||||
dctx->inst->cols[col].blue / 65535.0);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_rectangle(struct draw_ctx *dctx, int filled,
|
||||
int x, int y, int w, int h)
|
||||
{
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
gdk_draw_rectangle(dctx->uctx.u.gdk.target, dctx->uctx.u.gdk.gc,
|
||||
filled, x, y, w, h);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_new_path(dctx->uctx.u.cairo.cr);
|
||||
if (filled) {
|
||||
cairo_rectangle(dctx->uctx.u.cairo.cr, x, y, w, h);
|
||||
cairo_fill(dctx->uctx.u.cairo.cr);
|
||||
} else {
|
||||
cairo_rectangle(dctx->uctx.u.cairo.cr,
|
||||
x + 0.5, y + 0.5, w, h);
|
||||
cairo_close_path(dctx->uctx.u.cairo.cr);
|
||||
cairo_stroke(dctx->uctx.u.cairo.cr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_clip(struct draw_ctx *dctx, int x, int y, int w, int h)
|
||||
{
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
GdkRectangle r;
|
||||
|
||||
r.x = x;
|
||||
r.y = y;
|
||||
r.width = w;
|
||||
r.height = h;
|
||||
|
||||
gdk_gc_set_clip_rectangle(dctx->uctx.u.gdk.gc, &r);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_reset_clip(dctx->uctx.u.cairo.cr);
|
||||
cairo_new_path(dctx->uctx.u.cairo.cr);
|
||||
cairo_rectangle(dctx->uctx.u.cairo.cr, x, y, w, h);
|
||||
cairo_clip(dctx->uctx.u.cairo.cr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_point(struct draw_ctx *dctx, int x, int y)
|
||||
{
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
gdk_draw_point(dctx->uctx.u.gdk.target, dctx->uctx.u.gdk.gc, x, y);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_new_path(dctx->uctx.u.cairo.cr);
|
||||
cairo_rectangle(dctx->uctx.u.cairo.cr, x, y, 1, 1);
|
||||
cairo_fill(dctx->uctx.u.cairo.cr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_line(struct draw_ctx *dctx, int x0, int y0, int x1, int y1)
|
||||
{
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
gdk_draw_line(dctx->uctx.u.gdk.target, dctx->uctx.u.gdk.gc,
|
||||
x0, y0, x1, y1);
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_new_path(dctx->uctx.u.cairo.cr);
|
||||
cairo_move_to(dctx->uctx.u.cairo.cr, x0 + 0.5, y0 + 0.5);
|
||||
cairo_line_to(dctx->uctx.u.cairo.cr, x1 + 0.5, y1 + 0.5);
|
||||
cairo_stroke(dctx->uctx.u.cairo.cr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_stretch_before(struct draw_ctx *dctx, int x, int y,
|
||||
int w, int wdouble,
|
||||
int h, int hdouble, int hbothalf)
|
||||
{
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_matrix_t matrix;
|
||||
|
||||
matrix.xy = 0;
|
||||
matrix.yx = 0;
|
||||
|
||||
if (wdouble) {
|
||||
matrix.xx = 2;
|
||||
matrix.x0 = -x;
|
||||
} else {
|
||||
matrix.xx = 1;
|
||||
matrix.x0 = 0;
|
||||
}
|
||||
|
||||
if (hdouble) {
|
||||
matrix.yy = 2;
|
||||
if (hbothalf) {
|
||||
matrix.y0 = -(y+h);
|
||||
} else {
|
||||
matrix.y0 = -y;
|
||||
}
|
||||
} else {
|
||||
matrix.yy = 1;
|
||||
matrix.y0 = 0;
|
||||
}
|
||||
cairo_transform(dctx->uctx.u.cairo.cr, &matrix);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_stretch_after(struct draw_ctx *dctx, int x, int y,
|
||||
int w, int wdouble,
|
||||
int h, int hdouble, int hbothalf)
|
||||
{
|
||||
#ifdef DRAW_TEXT_GDK
|
||||
if (dctx->uctx.type == DRAWTYPE_GDK) {
|
||||
/*
|
||||
* I can't find any plausible StretchBlt equivalent in the X
|
||||
* server, so I'm going to do this the slow and painful way.
|
||||
* This will involve repeated calls to gdk_draw_pixmap() to
|
||||
* stretch the text horizontally. It's O(N^2) in time and O(N)
|
||||
* in network bandwidth, but you try thinking of a better way.
|
||||
* :-(
|
||||
*/
|
||||
int i;
|
||||
if (wdouble) {
|
||||
for (i = 0; i < w; i++) {
|
||||
gdk_draw_pixmap(dctx->uctx.u.gdk.target,
|
||||
dctx->uctx.u.gdk.gc,
|
||||
dctx->uctx.u.gdk.target,
|
||||
x + 2*i, y,
|
||||
x + 2*i+1, y,
|
||||
w - i, h);
|
||||
}
|
||||
w *= 2;
|
||||
}
|
||||
|
||||
if (hdouble) {
|
||||
int dt, db;
|
||||
/* Now stretch vertically, in the same way. */
|
||||
if (hbothalf)
|
||||
dt = 0, db = 1;
|
||||
else
|
||||
dt = 1, db = 0;
|
||||
for (i = 0; i < h; i += 2) {
|
||||
gdk_draw_pixmap(dctx->uctx.u.gdk.target,
|
||||
dctx->uctx.u.gdk.gc,
|
||||
dctx->uctx.u.gdk.target,
|
||||
x, y + dt*i + db,
|
||||
x, y + dt*(i+1),
|
||||
w, h-i-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef DRAW_TEXT_CAIRO
|
||||
if (dctx->uctx.type == DRAWTYPE_CAIRO) {
|
||||
cairo_set_matrix(dctx->uctx.u.cairo.cr,
|
||||
&dctx->uctx.u.cairo.origmatrix);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void draw_backing_rect(struct gui_data *inst)
|
||||
{
|
||||
struct draw_ctx *dctx = get_ctx(inst);
|
||||
draw_set_colour(dctx, 258);
|
||||
draw_rectangle(dctx, 1, 0, 0,
|
||||
inst->width * inst->font_width + 2*inst->window_border,
|
||||
inst->height * inst->font_height + 2*inst->window_border);
|
||||
free_ctx(dctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Draw a line of text in the window, at given character
|
||||
* coordinates, in given attributes.
|
||||
@ -2320,7 +2561,6 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
{
|
||||
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
|
||||
struct gui_data *inst = dctx->inst;
|
||||
GdkGC *gc = dctx->gc;
|
||||
int ncombining, combining;
|
||||
int nfg, nbg, t, fontid, shadow, rlen, widefactor, bold;
|
||||
int monochrome =
|
||||
@ -2395,25 +2635,31 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
} else
|
||||
rlen = len;
|
||||
|
||||
{
|
||||
GdkRectangle r;
|
||||
|
||||
r.x = x*inst->font_width+inst->window_border;
|
||||
r.y = y*inst->font_height+inst->window_border;
|
||||
r.width = rlen*widefactor*inst->font_width;
|
||||
r.height = inst->font_height;
|
||||
gdk_gc_set_clip_rectangle(gc, &r);
|
||||
if ((lattr & LATTR_MODE) != LATTR_NORM) {
|
||||
draw_stretch_before(dctx,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
rlen*widefactor*inst->font_width, TRUE,
|
||||
inst->font_height,
|
||||
((lattr & LATTR_MODE) != LATTR_WIDE),
|
||||
((lattr & LATTR_MODE) == LATTR_BOT));
|
||||
}
|
||||
|
||||
gdk_gc_set_foreground(gc, &inst->cols[nbg]);
|
||||
gdk_draw_rectangle(inst->pixmap, gc, 1,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
rlen*widefactor*inst->font_width, inst->font_height);
|
||||
draw_clip(dctx,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
rlen*widefactor*inst->font_width,
|
||||
inst->font_height);
|
||||
|
||||
gdk_gc_set_foreground(gc, &inst->cols[nfg]);
|
||||
draw_set_colour(dctx, nbg);
|
||||
draw_rectangle(dctx, TRUE,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
rlen*widefactor*inst->font_width, inst->font_height);
|
||||
|
||||
draw_set_colour(dctx, nfg);
|
||||
for (combining = 0; combining < ncombining; combining++) {
|
||||
unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid],
|
||||
unifont_draw_text(&dctx->uctx, inst->fonts[fontid],
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border+inst->fonts[0]->ascent,
|
||||
text + combining, len, widefactor > 1,
|
||||
@ -2424,47 +2670,20 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
int uheight = inst->fonts[0]->ascent + 1;
|
||||
if (uheight >= inst->font_height)
|
||||
uheight = inst->font_height - 1;
|
||||
gdk_draw_line(inst->pixmap, gc, x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height + uheight + inst->window_border,
|
||||
(x+len)*widefactor*inst->font_width-1+inst->window_border,
|
||||
y*inst->font_height + uheight + inst->window_border);
|
||||
draw_line(dctx, x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height + uheight + inst->window_border,
|
||||
(x+len)*widefactor*inst->font_width-1+inst->window_border,
|
||||
y*inst->font_height + uheight + inst->window_border);
|
||||
}
|
||||
|
||||
if ((lattr & LATTR_MODE) != LATTR_NORM) {
|
||||
/*
|
||||
* I can't find any plausible StretchBlt equivalent in the
|
||||
* X server, so I'm going to do this the slow and painful
|
||||
* way. This will involve repeated calls to
|
||||
* gdk_draw_pixmap() to stretch the text horizontally. It's
|
||||
* O(N^2) in time and O(N) in network bandwidth, but you
|
||||
* try thinking of a better way. :-(
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < len * widefactor * inst->font_width; i++) {
|
||||
gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap,
|
||||
x*inst->font_width+inst->window_border + 2*i,
|
||||
y*inst->font_height+inst->window_border,
|
||||
x*inst->font_width+inst->window_border + 2*i+1,
|
||||
y*inst->font_height+inst->window_border,
|
||||
len * widefactor * inst->font_width - i, inst->font_height);
|
||||
}
|
||||
len *= 2;
|
||||
if ((lattr & LATTR_MODE) != LATTR_WIDE) {
|
||||
int dt, db;
|
||||
/* Now stretch vertically, in the same way. */
|
||||
if ((lattr & LATTR_MODE) == LATTR_BOT)
|
||||
dt = 0, db = 1;
|
||||
else
|
||||
dt = 1, db = 0;
|
||||
for (i = 0; i < inst->font_height; i+=2) {
|
||||
gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border+dt*i+db,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border+dt*(i+1),
|
||||
len * widefactor * inst->font_width, inst->font_height-i-1);
|
||||
}
|
||||
}
|
||||
draw_stretch_after(dctx,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
rlen*widefactor*inst->font_width, TRUE,
|
||||
inst->font_height,
|
||||
((lattr & LATTR_MODE) != LATTR_WIDE),
|
||||
((lattr & LATTR_MODE) == LATTR_BOT));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2473,7 +2692,6 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
{
|
||||
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
|
||||
struct gui_data *inst = dctx->inst;
|
||||
GdkGC *gc = dctx->gc;
|
||||
int widefactor;
|
||||
|
||||
do_text_internal(ctx, x, y, text, len, attr, lattr);
|
||||
@ -2493,12 +2711,10 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
len *= 2;
|
||||
}
|
||||
|
||||
gdk_draw_pixmap(gtk_widget_get_window(inst->area), gc, inst->pixmap,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
len*widefactor*inst->font_width, inst->font_height);
|
||||
draw_update(dctx,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
len*widefactor*inst->font_width, inst->font_height);
|
||||
}
|
||||
|
||||
void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
@ -2506,7 +2722,6 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
{
|
||||
struct draw_ctx *dctx = (struct draw_ctx *)ctx;
|
||||
struct gui_data *inst = dctx->inst;
|
||||
GdkGC *gc = dctx->gc;
|
||||
|
||||
int active, passive, widefactor;
|
||||
|
||||
@ -2547,11 +2762,12 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
* if it's passive.
|
||||
*/
|
||||
if (passive) {
|
||||
gdk_gc_set_foreground(gc, &inst->cols[261]);
|
||||
gdk_draw_rectangle(inst->pixmap, gc, 0,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
len*widefactor*inst->font_width-1, inst->font_height-1);
|
||||
draw_set_colour(dctx, 261);
|
||||
draw_rectangle(dctx, FALSE,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
len*widefactor*inst->font_width-1,
|
||||
inst->font_height-1);
|
||||
}
|
||||
} else {
|
||||
int uheight;
|
||||
@ -2585,27 +2801,25 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len,
|
||||
length = inst->font_height;
|
||||
}
|
||||
|
||||
gdk_gc_set_foreground(gc, &inst->cols[261]);
|
||||
draw_set_colour(dctx, 261);
|
||||
if (passive) {
|
||||
for (i = 0; i < length; i++) {
|
||||
if (i % 2 == 0) {
|
||||
gdk_draw_point(inst->pixmap, gc, startx, starty);
|
||||
draw_point(dctx, startx, starty);
|
||||
}
|
||||
startx += dx;
|
||||
starty += dy;
|
||||
}
|
||||
} else if (active) {
|
||||
gdk_draw_line(inst->pixmap, gc, startx, starty,
|
||||
startx + (length-1) * dx, starty + (length-1) * dy);
|
||||
draw_line(dctx, startx, starty,
|
||||
startx + (length-1) * dx, starty + (length-1) * dy);
|
||||
} /* else no cursor (e.g., blinked off) */
|
||||
}
|
||||
|
||||
gdk_draw_pixmap(gtk_widget_get_window(inst->area), gc, inst->pixmap,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
len*widefactor*inst->font_width, inst->font_height);
|
||||
draw_update(dctx,
|
||||
x*inst->font_width+inst->window_border,
|
||||
y*inst->font_height+inst->window_border,
|
||||
len*widefactor*inst->font_width, inst->font_height);
|
||||
|
||||
#if GTK_CHECK_VERSION(2,0,0)
|
||||
{
|
||||
@ -3110,6 +3324,8 @@ char *setup_fonts_ucs(struct gui_data *inst)
|
||||
inst->fonts[0]->public_charset,
|
||||
conf_get_int(inst->conf, CONF_vtmode));
|
||||
|
||||
inst->drawtype = inst->fonts[0]->preferred_drawtype;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3775,6 +3991,7 @@ int pt_main(int argc, char **argv)
|
||||
inst->wintitle = inst->icontitle = NULL;
|
||||
inst->quit_fn_scheduled = FALSE;
|
||||
inst->idle_fn_scheduled = FALSE;
|
||||
inst->drawtype = DRAWTYPE_DEFAULT;
|
||||
|
||||
/* defer any child exit handling until we're ready to deal with
|
||||
* it */
|
||||
|
Loading…
Reference in New Issue
Block a user