1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-10 01:48:00 +00:00

Make the use of server-side backing pixmaps in GTK optional.

We won't be able to use them in GTK3, or when compiling with GTK2 and
-DGDK_DISABLE_DEPRECATED.

This applies to the one we use for the main terminal window, and also
the small one we use for the preview pane in the unified font selector.
This commit is contained in:
Simon Tatham 2015-08-16 09:02:31 +01:00
parent 066bce3d19
commit 5319c659ad
3 changed files with 89 additions and 6 deletions

View File

@ -1970,7 +1970,9 @@ typedef struct unifontsel_internal {
GtkWidget *filter_buttons[4]; GtkWidget *filter_buttons[4];
int n_filter_buttons; int n_filter_buttons;
GtkWidget *preview_area; GtkWidget *preview_area;
#ifndef NO_BACKING_PIXMAPS
GdkPixmap *preview_pixmap; GdkPixmap *preview_pixmap;
#endif
int preview_width, preview_height; int preview_width, preview_height;
GdkColor preview_fg, preview_bg; GdkColor preview_fg, preview_bg;
int filter_flags; int filter_flags;
@ -2379,21 +2381,27 @@ static void unifontsel_draw_preview_text_inner(unifont_drawctx *dctx,
static void unifontsel_draw_preview_text(unifontsel_internal *fs) static void unifontsel_draw_preview_text(unifontsel_internal *fs)
{ {
unifont_drawctx dctx; unifont_drawctx dctx;
GdkWindow *target;
if (!fs->preview_pixmap) #ifndef NO_BACKING_PIXMAPS
target = fs->preview_pixmap;
#else
target = gtk_widget_get_window(fs->preview_area);
#endif
if (!target) /* we may be called when we haven't created everything yet */
return; return;
dctx.type = DRAWTYPE_DEFAULT; dctx.type = DRAWTYPE_DEFAULT;
#ifdef DRAW_TEXT_GDK #ifdef DRAW_TEXT_GDK
if (dctx.type == DRAWTYPE_GDK) { if (dctx.type == DRAWTYPE_GDK) {
dctx.u.gdk.target = fs->preview_pixmap; dctx.u.gdk.target = target;
dctx.u.gdk.gc = gdk_gc_new(fs->preview_pixmap); dctx.u.gdk.gc = gdk_gc_new(target);
} }
#endif #endif
#ifdef DRAW_TEXT_CAIRO #ifdef DRAW_TEXT_CAIRO
if (dctx.type == DRAWTYPE_CAIRO) { if (dctx.type == DRAWTYPE_CAIRO) {
dctx.u.cairo.widget = GTK_WIDGET(fs->preview_area); dctx.u.cairo.widget = GTK_WIDGET(fs->preview_area);
dctx.u.cairo.cr = gdk_cairo_create(fs->preview_pixmap); dctx.u.cairo.cr = gdk_cairo_create(target);
} }
#endif #endif
@ -2839,6 +2847,7 @@ static gint unifontsel_expose_area(GtkWidget *widget, GdkEventExpose *event,
{ {
unifontsel_internal *fs = (unifontsel_internal *)data; unifontsel_internal *fs = (unifontsel_internal *)data;
#ifndef NO_BACKING_PIXMAPS
if (fs->preview_pixmap) { if (fs->preview_pixmap) {
gdk_draw_pixmap(gtk_widget_get_window(widget), gdk_draw_pixmap(gtk_widget_get_window(widget),
(gtk_widget_get_style(widget)->fg_gc (gtk_widget_get_style(widget)->fg_gc
@ -2848,12 +2857,17 @@ static gint unifontsel_expose_area(GtkWidget *widget, GdkEventExpose *event,
event->area.x, event->area.y, event->area.x, event->area.y,
event->area.width, event->area.height); event->area.width, event->area.height);
} }
#else
unifontsel_draw_preview_text(fs);
#endif
return TRUE; return TRUE;
} }
static gint unifontsel_configure_area(GtkWidget *widget, static gint unifontsel_configure_area(GtkWidget *widget,
GdkEventConfigure *event, gpointer data) GdkEventConfigure *event, gpointer data)
{ {
#ifndef NO_BACKING_PIXMAPS
unifontsel_internal *fs = (unifontsel_internal *)data; unifontsel_internal *fs = (unifontsel_internal *)data;
int ox, oy, nx, ny, x, y; int ox, oy, nx, ny, x, y;
@ -2877,6 +2891,7 @@ static gint unifontsel_configure_area(GtkWidget *widget,
unifontsel_draw_preview_text(fs); unifontsel_draw_preview_text(fs);
} }
#endif
gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, FALSE); gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, FALSE);
@ -3071,7 +3086,9 @@ unifontsel *unifontsel_new(const char *wintitle)
* Preview widget. * Preview widget.
*/ */
fs->preview_area = gtk_drawing_area_new(); fs->preview_area = gtk_drawing_area_new();
#ifndef NO_BACKING_PIXMAPS
fs->preview_pixmap = NULL; fs->preview_pixmap = NULL;
#endif
fs->preview_width = 0; fs->preview_width = 0;
fs->preview_height = 0; fs->preview_height = 0;
fs->preview_fg.pixel = fs->preview_bg.pixel = 0; fs->preview_fg.pixel = fs->preview_bg.pixel = 0;
@ -3179,8 +3196,10 @@ void unifontsel_destroy(unifontsel *fontsel)
unifontsel_internal *fs = (unifontsel_internal *)fontsel; unifontsel_internal *fs = (unifontsel_internal *)fontsel;
fontinfo *info; fontinfo *info;
#ifndef NO_BACKING_PIXMAPS
if (fs->preview_pixmap) if (fs->preview_pixmap)
gdk_pixmap_unref(fs->preview_pixmap); gdk_pixmap_unref(fs->preview_pixmap);
#endif
freetree234(fs->fonts_by_selorder); freetree234(fs->fonts_by_selorder);
while ((info = delpos234(fs->fonts_by_realname, 0)) != NULL) while ((info = delpos234(fs->fonts_by_realname, 0)) != NULL)

View File

@ -29,6 +29,23 @@
#define DRAW_TEXT_CAIRO #define DRAW_TEXT_CAIRO
#endif #endif
#if GTK_CHECK_VERSION(3,0,0) || defined GDK_DISABLE_DEPRECATED
/*
* Where the facility is available, we prefer to render text on to a
* persistent server-side pixmap, and redraw windows by simply
* blitting rectangles of that pixmap into them as needed. This is
* better for performance since we avoid expensive font rendering
* calls where possible, and it's particularly good over a non-local X
* connection because the response to an expose event can now be a
* very simple rectangle-copy operation rather than a lot of fiddly
* drawing or bitmap transfer.
*
* However, GTK is deprecating the use of server-side pixmaps, so we
* have to disable this mode under some circumstances.
*/
#define NO_BACKING_PIXMAPS
#endif
/* /*
* Exports from gtkfont.c. * Exports from gtkfont.c.
*/ */

View File

@ -79,7 +79,9 @@ struct gui_data {
GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2, GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2,
*restartitem; *restartitem;
GtkWidget *sessionsmenu; GtkWidget *sessionsmenu;
#ifndef NO_BACKING_PIXMAPS
GdkPixmap *pixmap; GdkPixmap *pixmap;
#endif
#if GTK_CHECK_VERSION(2,0,0) #if GTK_CHECK_VERSION(2,0,0)
GtkIMContext *imc; GtkIMContext *imc;
#endif #endif
@ -491,6 +493,7 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
need_size = 1; need_size = 1;
} }
#ifndef NO_BACKING_PIXMAPS
if (inst->pixmap) { if (inst->pixmap) {
gdk_pixmap_unref(inst->pixmap); gdk_pixmap_unref(inst->pixmap);
inst->pixmap = NULL; inst->pixmap = NULL;
@ -499,6 +502,7 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
inst->pixmap = gdk_pixmap_new(gtk_widget_get_window(widget), inst->pixmap = gdk_pixmap_new(gtk_widget_get_window(widget),
(w * inst->font_width + 2*inst->window_border), (w * inst->font_width + 2*inst->window_border),
(h * inst->font_height + 2*inst->window_border), -1); (h * inst->font_height + 2*inst->window_border), -1);
#endif
draw_backing_rect(inst); draw_backing_rect(inst);
@ -520,6 +524,7 @@ gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{ {
struct gui_data *inst = (struct gui_data *)data; struct gui_data *inst = (struct gui_data *)data;
#ifndef NO_BACKING_PIXMAPS
/* /*
* Pass the exposed rectangle to terminal.c, which will call us * Pass the exposed rectangle to terminal.c, which will call us
* back to do the actual painting. * back to do the actual painting.
@ -533,6 +538,35 @@ gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data)
event->area.x, event->area.y, event->area.x, event->area.y,
event->area.width, event->area.height); event->area.width, event->area.height);
} }
#else
if (inst->term) {
Context ctx = get_ctx(inst);
/*
* As in window.c, we clear the 'immediately' flag in the
* term_paint() call if the terminal has an update pending, in
* case we're constrained within this event to only draw on
* the exposed rectangle of the window. (Because if the whole
* of a character cell needs a redraw due to a terminal
* contents change, the last thing we want is to give it a
* _partial_ redraw here due to system-imposed clipping, and
* then have the next main terminal update believe it's been
* redrawn in full.)
*
* I don't actually know if GTK expose events will constrain
* us in this way, but it's best to be careful...
*/
term_paint(inst->term, ctx,
(event->area.x - inst->window_border) / inst->font_width,
(event->area.y - inst->window_border) / inst->font_height,
(event->area.x + event->area.width -
inst->window_border) / inst->font_width,
(event->area.y + event->area.height -
inst->window_border) / inst->font_height,
!inst->term->window_update_pending);
free_ctx(ctx);
}
#endif
return TRUE; return TRUE;
} }
@ -2283,23 +2317,30 @@ Context get_ctx(void *frontend)
{ {
struct gui_data *inst = (struct gui_data *)frontend; struct gui_data *inst = (struct gui_data *)frontend;
struct draw_ctx *dctx; struct draw_ctx *dctx;
GdkWindow *target;
if (!gtk_widget_get_window(inst->area)) if (!gtk_widget_get_window(inst->area))
return NULL; return NULL;
#ifndef NO_BACKING_PIXMAPS
target = inst->pixmap;
#else
target = gtk_widget_get_window(inst->area);
#endif
dctx = snew(struct draw_ctx); dctx = snew(struct draw_ctx);
dctx->inst = inst; dctx->inst = inst;
dctx->uctx.type = inst->drawtype; dctx->uctx.type = inst->drawtype;
#ifdef DRAW_TEXT_GDK #ifdef DRAW_TEXT_GDK
if (dctx->uctx.type == DRAWTYPE_GDK) { if (dctx->uctx.type == DRAWTYPE_GDK) {
dctx->uctx.u.gdk.target = inst->pixmap; dctx->uctx.u.gdk.target = target;
dctx->uctx.u.gdk.gc = gdk_gc_new(gtk_widget_get_window(inst->area)); dctx->uctx.u.gdk.gc = gdk_gc_new(gtk_widget_get_window(inst->area));
} }
#endif #endif
#ifdef DRAW_TEXT_CAIRO #ifdef DRAW_TEXT_CAIRO
if (dctx->uctx.type == DRAWTYPE_CAIRO) { if (dctx->uctx.type == DRAWTYPE_CAIRO) {
dctx->uctx.u.cairo.widget = GTK_WIDGET(inst->area); dctx->uctx.u.cairo.widget = GTK_WIDGET(inst->area);
dctx->uctx.u.cairo.cr = gdk_cairo_create(inst->pixmap); dctx->uctx.u.cairo.cr = gdk_cairo_create(target);
cairo_get_matrix(dctx->uctx.u.cairo.cr, cairo_get_matrix(dctx->uctx.u.cairo.cr,
&dctx->uctx.u.cairo.origmatrix); &dctx->uctx.u.cairo.origmatrix);
cairo_set_line_width(dctx->uctx.u.cairo.cr, 1.0); cairo_set_line_width(dctx->uctx.u.cairo.cr, 1.0);
@ -2335,6 +2376,7 @@ void free_ctx(Context ctx)
static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h) static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h)
{ {
#ifndef NO_BACKING_PIXMAPS
#ifdef DRAW_TEXT_GDK #ifdef DRAW_TEXT_GDK
if (dctx->uctx.type == DRAWTYPE_GDK) { if (dctx->uctx.type == DRAWTYPE_GDK) {
gdk_draw_pixmap(gtk_widget_get_window(dctx->inst->area), gdk_draw_pixmap(gtk_widget_get_window(dctx->inst->area),
@ -2350,6 +2392,7 @@ static void draw_update(struct draw_ctx *dctx, int x, int y, int w, int h)
gdk_gc_unref(gc); gdk_gc_unref(gc);
} }
#endif #endif
#endif
} }
static void draw_set_colour(struct draw_ctx *dctx, int col) static void draw_set_colour(struct draw_ctx *dctx, int col)
@ -2492,6 +2535,7 @@ static void draw_stretch_after(struct draw_ctx *dctx, int x, int y,
int h, int hdouble, int hbothalf) int h, int hdouble, int hbothalf)
{ {
#ifdef DRAW_TEXT_GDK #ifdef DRAW_TEXT_GDK
#ifndef NO_BACKING_PIXMAPS
if (dctx->uctx.type == DRAWTYPE_GDK) { if (dctx->uctx.type == DRAWTYPE_GDK) {
/* /*
* I can't find any plausible StretchBlt equivalent in the X * I can't find any plausible StretchBlt equivalent in the X
@ -2531,7 +2575,10 @@ static void draw_stretch_after(struct draw_ctx *dctx, int x, int y,
} }
} }
} }
#else
#error No way to implement stretching in GDK without a reliable backing pixmap
#endif #endif
#endif /* DRAW_TEXT_GDK */
#ifdef DRAW_TEXT_CAIRO #ifdef DRAW_TEXT_CAIRO
if (dctx->uctx.type == DRAWTYPE_CAIRO) { if (dctx->uctx.type == DRAWTYPE_CAIRO) {
cairo_set_matrix(dctx->uctx.u.cairo.cr, cairo_set_matrix(dctx->uctx.u.cairo.cr,