]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Make the use of server-side backing pixmaps in GTK optional.
authorSimon Tatham <anakin@pobox.com>
Sun, 16 Aug 2015 08:02:31 +0000 (09:02 +0100)
committerSimon Tatham <anakin@pobox.com>
Sun, 16 Aug 2015 12:11:06 +0000 (13:11 +0100)
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.

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

index 55878307447a63edf9c0f3f49e7b96a4680165f6..cd0097b184ec9192ca820347043939da7c9d87ae 100644 (file)
@@ -1970,7 +1970,9 @@ typedef struct unifontsel_internal {
     GtkWidget *filter_buttons[4];
     int n_filter_buttons;
     GtkWidget *preview_area;
+#ifndef NO_BACKING_PIXMAPS
     GdkPixmap *preview_pixmap;
+#endif
     int preview_width, preview_height;
     GdkColor preview_fg, preview_bg;
     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)
 {
     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;
 
     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);
+        dctx.u.gdk.target = target;
+        dctx.u.gdk.gc = gdk_gc_new(target);
     }
 #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);
+        dctx.u.cairo.cr = gdk_cairo_create(target);
     }
 #endif
 
@@ -2839,6 +2847,7 @@ static gint unifontsel_expose_area(GtkWidget *widget, GdkEventExpose *event,
 {
     unifontsel_internal *fs = (unifontsel_internal *)data;
 
+#ifndef NO_BACKING_PIXMAPS
     if (fs->preview_pixmap) {
         gdk_draw_pixmap(gtk_widget_get_window(widget),
                        (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.width, event->area.height);
     }
+#else
+    unifontsel_draw_preview_text(fs);
+#endif
+
     return TRUE;
 }
 
 static gint unifontsel_configure_area(GtkWidget *widget,
                                      GdkEventConfigure *event, gpointer data)
 {
+#ifndef NO_BACKING_PIXMAPS
     unifontsel_internal *fs = (unifontsel_internal *)data;
     int ox, oy, nx, ny, x, y;
 
@@ -2877,6 +2891,7 @@ static gint unifontsel_configure_area(GtkWidget *widget,
 
        unifontsel_draw_preview_text(fs);
     }
+#endif
 
     gdk_window_invalidate_rect(gtk_widget_get_window(widget), NULL, FALSE);
 
@@ -3071,7 +3086,9 @@ unifontsel *unifontsel_new(const char *wintitle)
      * Preview widget.
      */
     fs->preview_area = gtk_drawing_area_new();
+#ifndef NO_BACKING_PIXMAPS
     fs->preview_pixmap = NULL;
+#endif
     fs->preview_width = 0;
     fs->preview_height = 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;
     fontinfo *info;
 
+#ifndef NO_BACKING_PIXMAPS
     if (fs->preview_pixmap)
        gdk_pixmap_unref(fs->preview_pixmap);
+#endif
 
     freetree234(fs->fonts_by_selorder);
     while ((info = delpos234(fs->fonts_by_realname, 0)) != NULL)
index b56640c5b7bdefc976729a9e9f9751fc3ca3c2c5..f99097f2ffd485d99674b3700deb65d247cbfdd2 100644 (file)
 #define DRAW_TEXT_CAIRO
 #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.
  */
index c62bddb4f00a2c14915229c43291072b7913ae11..4062816c7f82f01feac24a6fa0f92c4c35568be7 100644 (file)
@@ -79,7 +79,9 @@ struct gui_data {
     GtkWidget *menu, *specialsmenu, *specialsitem1, *specialsitem2,
        *restartitem;
     GtkWidget *sessionsmenu;
+#ifndef NO_BACKING_PIXMAPS
     GdkPixmap *pixmap;
+#endif
 #if GTK_CHECK_VERSION(2,0,0)
     GtkIMContext *imc;
 #endif
@@ -491,6 +493,7 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
        need_size = 1;
     }
 
+#ifndef NO_BACKING_PIXMAPS
     if (inst->pixmap) {
        gdk_pixmap_unref(inst->pixmap);
        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),
                                  (w * inst->font_width + 2*inst->window_border),
                                  (h * inst->font_height + 2*inst->window_border), -1);
+#endif
 
     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;
 
+#ifndef NO_BACKING_PIXMAPS
     /*
      * Pass the exposed rectangle to terminal.c, which will call us
      * 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.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;
 }
 
@@ -2283,23 +2317,30 @@ Context get_ctx(void *frontend)
 {
     struct gui_data *inst = (struct gui_data *)frontend;
     struct draw_ctx *dctx;
+    GdkWindow *target;
 
     if (!gtk_widget_get_window(inst->area))
        return NULL;
 
+#ifndef NO_BACKING_PIXMAPS
+    target = inst->pixmap;
+#else
+    target = gtk_widget_get_window(inst->area);
+#endif
+
     dctx = snew(struct draw_ctx);
     dctx->inst = inst;
     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.target = target;
         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);
+        dctx->uctx.u.cairo.cr = gdk_cairo_create(target);
         cairo_get_matrix(dctx->uctx.u.cairo.cr,
                          &dctx->uctx.u.cairo.origmatrix);
         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)
 {
+#ifndef NO_BACKING_PIXMAPS
 #ifdef DRAW_TEXT_GDK
     if (dctx->uctx.type == DRAWTYPE_GDK) {
         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);
     }
 #endif
+#endif
 }
 
 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)
 {
 #ifdef DRAW_TEXT_GDK
+#ifndef NO_BACKING_PIXMAPS
     if (dctx->uctx.type == DRAWTYPE_GDK) {
        /*
         * 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 /* DRAW_TEXT_GDK */
 #ifdef DRAW_TEXT_CAIRO
     if (dctx->uctx.type == DRAWTYPE_CAIRO) {
         cairo_set_matrix(dctx->uctx.u.cairo.cr,