Hi Daniel, This is brillant! I applied the patch and everything seems to work great: all of the cases in which I usually see flickering (I tried resizing windows, running a process in the background, and isearch) seemed fixed :) Congrats on this very nice patch :) Clément. On 2016-10-20 21:32, Daniel Colascione wrote: > This patch teaches Emacs how to use the X11 DOUBLE-BUFFER extension to avoid showing the user incomplete drawing results. Without this patch, I can make Emacs flicker like crazy by running isearch for a piece of text unique in a buffer and holding down C-s. With this patch, Emacs does not flicker no matter what I do to it. > > The patch also stops flickering that occurs when using the "solid resizing" feature of some window managers --- i.e., when the WM redraws windows as the user drags their edges, as opposed to displaying some kind of bounding-box in lieu of the actual window contents. > > I've tried to avoid changing the logic in the single-buffered case (which we still support), and I've also tried to avoid touching Cairo rendering. This patch should work with any toolkit --- I've tested GTK+3 and no toolkit at all. > > A few notes: > > * We do a buffer flip at the end of redisplay instead of in x_update_end() so the user never sees the completely-cleared state that we enter immediately after clear_garbaged_frames(). x_update_end() does do a buffer flip if it's called outside redisplay. I've added a new terminal hook to support this hack. > > * The DBE documentation claims that XClearWindow and XClearArea clear both the front and back buffers. It's a lie. In my experiments, these functions clear only the front buffer. > > * XFT stops drawing after we give XftCreateDraw a DBE back-buffer and the size of that back buffer changes. To work around this problem, we discard any caches XftDraw object we might have to a frame after that frame changes size. I haven't noticed any performance problems. > > commit 15fdd8f63533201f05627ede634a8f5ae4757d7e > Author: Daniel Colascione > Date: Thu Oct 20 16:50:54 2016 -0700 > > Add double-buffered output support to Emacs > > diff --git a/configure.ac b/configure.ac > index cd11b10..4716b43 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -3712,6 +3712,24 @@ AC_DEFUN > AC_SUBST(XFIXES_CFLAGS) > AC_SUBST(XFIXES_LIBS) > > +### Use Xdbe (-lXdbe) if available > +HAVE_XDBE=no > +if test "${HAVE_X11}" = "yes"; then > + AC_CHECK_HEADER(X11/extensions/Xdbe.h, > + [AC_CHECK_LIB(Xext, XdbeAllocateBackBufferName, HAVE_XDBE=yes)], > + [], > + [#include > + ]) > + if test $HAVE_XDBE = yes; then > + XDBE_LIBS=-lXext > + fi > + if test $HAVE_XDBE = yes; then > + AC_DEFINE(HAVE_XDBE, 1, [Define to 1 if you have the Xdbe extension.]) > + fi > +fi > +AC_SUBST(XDBE_CFLAGS) > +AC_SUBST(XDBE_LIBS) > + > ### Use libxml (-lxml2) if available > ### mingw32 doesn't use -lxml2, since it loads the library dynamically. > HAVE_LIBXML2=no > diff --git a/src/Makefile.in b/src/Makefile.in > index 89f7a92..dc0bfff 100644 > --- a/src/Makefile.in > +++ b/src/Makefile.in > @@ -254,6 +254,9 @@ XINERAMA_CFLAGS = > XFIXES_LIBS = @XFIXES_LIBS@ > XFIXES_CFLAGS = @XFIXES_CFLAGS@ > > +XDBE_LIBS = @XDBE_LIBS@ > +XDBE_CFLAGS = @XDBE_CFLAGS@ > + > ## widget.o if USE_X_TOOLKIT, otherwise empty. > WIDGET_OBJ=@WIDGET_OBJ@ > > @@ -372,7 +375,7 @@ ALL_CFLAGS= > $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \ > $(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ > $(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \ > - $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) \ > + $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \ > $(WEBKIT_CFLAGS) \ > $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ > $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ > @@ -489,6 +492,7 @@ LIBES = > $(WEBKIT_LIBS) \ > $(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ > $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \ > + $(XDBE_LIBS) \ > $(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \ > $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ > $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ > diff --git a/src/dispnew.c b/src/dispnew.c > index 70d4de0..8f81cee 100644 > --- a/src/dispnew.c > +++ b/src/dispnew.c > @@ -2999,6 +2999,7 @@ redraw_frame (struct frame *f) > { > /* Error if F has no glyphs. */ > eassert (f->glyphs_initialized_p); > + font_flush_frame_caches (f); > update_begin (f); > if (FRAME_MSDOS_P (f)) > FRAME_TERMINAL (f)->set_terminal_modes_hook (FRAME_TERMINAL (f)); > diff --git a/src/font.c b/src/font.c > index f8e6794..033995e 100644 > --- a/src/font.c > +++ b/src/font.c > @@ -5275,6 +5275,16 @@ font_deferred_log (const char *action, Lisp_Object arg, Lisp_Object result) > } > > void > +font_flush_frame_caches (struct frame *f) > +{ > + struct font_driver_list *list; > + > + for (list = f->font_driver_list; list; list = list->next) > + if (list->on && list->driver->flush_frame_caches) > + list->driver->flush_frame_caches (f); > +} > + > +void > syms_of_font (void) > { > sort_shift_bits[FONT_TYPE_INDEX] = 0; > diff --git a/src/font.h b/src/font.h > index cf47729..961e9c4 100644 > --- a/src/font.h > +++ b/src/font.h > @@ -763,6 +763,12 @@ struct font_driver > Return non-nil if the driver support rendering of combining > characters for FONT according to Unicode combining class. */ > Lisp_Object (*combining_capability) (struct font *font); > + > + /* Optional > + > + Called when frame F is redrawn from scratch. Font engines may > + invalidate certain caches in this case. */ > + void (*flush_frame_caches) (struct frame *f); > }; > > > @@ -862,7 +868,9 @@ extern void *font_get_frame_data (struct frame *f, Lisp_Object); > extern void font_filter_properties (Lisp_Object font, > Lisp_Object alist, > const char *const boolean_properties[], > - const char *const non_boolean_properties[]); > + const char *const non_boolean_properties[]); > + > +extern void font_flush_frame_caches (struct frame *f); > > #ifdef HAVE_FREETYPE > extern struct font_driver ftfont_driver; > diff --git a/src/ftxfont.c b/src/ftxfont.c > index f49d44f..bfdeb40 100644 > --- a/src/ftxfont.c > +++ b/src/ftxfont.c > @@ -95,7 +95,7 @@ ftxfont_get_gcs (struct frame *f, unsigned long foreground, unsigned long backgr > if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &color)) > break; > xgcv.foreground = color.pixel; > - new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > GCForeground, &xgcv); > } > unblock_input (); > @@ -139,14 +139,14 @@ ftxfont_draw_bitmap (struct frame *f, GC gc_fore, GC *gcs, struct font *font, > p[n[0]].y = y - bitmap.top + i; > if (++n[0] == size) > { > - XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > gc_fore, p, size, CoordModeOrigin); > n[0] = 0; > } > } > } > if (flush && n[0] > 0) > - XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > gc_fore, p, n[0], CoordModeOrigin); > } > else > @@ -168,7 +168,7 @@ ftxfont_draw_bitmap (struct frame *f, GC gc_fore, GC *gcs, struct font *font, > pp[n[idx]].y = y - bitmap.top + i; > if (++(n[idx]) == size) > { > - XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > idx == 6 ? gc_fore : gcs[idx], pp, size, > CoordModeOrigin); > n[idx] = 0; > @@ -180,10 +180,10 @@ ftxfont_draw_bitmap (struct frame *f, GC gc_fore, GC *gcs, struct font *font, > { > for (i = 0; i < 6; i++) > if (n[i] > 0) > - XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > gcs[i], p + 0x100 * i, n[i], CoordModeOrigin); > if (n[6] > 0) > - XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > gc_fore, p + 0x600, n[6], CoordModeOrigin); > } > } > @@ -203,7 +203,7 @@ ftxfont_draw_background (struct frame *f, struct font *font, GC gc, int x, int y > XGetGCValues (FRAME_X_DISPLAY (f), gc, > GCForeground | GCBackground, &xgcv); > XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background); > - XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc, > + XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), gc, > x, y - FONT_BASE (font), width, FONT_HEIGHT (font)); > XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground); > } > diff --git a/src/gtkutil.c b/src/gtkutil.c > index 88e6d30..f81940b 100644 > --- a/src/gtkutil.c > +++ b/src/gtkutil.c > @@ -48,6 +48,10 @@ along with GNU Emacs. If not, see . */ > #include "emacsgtkfixed.h" > #endif > > +#ifdef HAVE_XDBE > +#include > +#endif > + > #ifndef HAVE_GTK_WIDGET_SET_HAS_WINDOW > #define gtk_widget_set_has_window(w, b) \ > (gtk_fixed_set_has_window (GTK_FIXED (w), b)) > @@ -1233,6 +1237,7 @@ xg_create_frame_widgets (struct frame *f) > by callers of this function. */ > gtk_widget_realize (wfixed); > FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed); > + set_up_x_back_buffer (f); > > /* Since GTK clears its window by filling with the background color, > we must keep X and GTK background in sync. */ > @@ -1296,6 +1301,15 @@ xg_free_frame_widgets (struct frame *f) > if (tbinfo) > xfree (tbinfo); > > +#ifdef HAVE_XDBE > + if (FRAME_X_WINDOW (f) != FRAME_X_DRAWABLE (f)) > + { > + XdbeDeallocateBackBufferName (FRAME_X_DISPLAY (f), > + FRAME_X_DRAWABLE (f)); > + FRAME_X_DRAWABLE (f) = 0; > + } > +#endif > + > gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f)); > FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */ > FRAME_GTK_OUTER_WIDGET (f) = 0; > diff --git a/src/image.c b/src/image.c > index 9bd2455..1303a93 100644 > --- a/src/image.c > +++ b/src/image.c > @@ -220,7 +220,7 @@ x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsi > > #ifdef HAVE_X_WINDOWS > Pixmap bitmap; > - bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > bits, width, height); > if (! bitmap) > return -1; > @@ -327,7 +327,7 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file) > > filename = SSDATA (found); > > - result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > filename, &width, &height, &bitmap, &xhot, &yhot); > if (result != BitmapSuccess) > return -1; > @@ -1952,7 +1952,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, > { > #ifdef HAVE_X_WINDOWS > Display *display = FRAME_X_DISPLAY (f); > - Window window = FRAME_X_WINDOW (f); > + Drawable drawable = FRAME_X_DRAWABLE (f); > Screen *screen = FRAME_X_SCREEN (f); > > eassert (input_blocked_p ()); > @@ -1981,7 +1981,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth, > (*ximg)->data = xmalloc ((*ximg)->bytes_per_line * height); > > /* Allocate a pixmap of the same size. */ > - *pixmap = XCreatePixmap (display, window, width, height, depth); > + *pixmap = XCreatePixmap (display, drawable, width, height, depth); > if (*pixmap == NO_PIXMAP) > { > x_destroy_x_image (*ximg); > @@ -2742,7 +2742,7 @@ Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data, > img->pixmap = > (x_check_image_size (0, img->width, img->height) > ? XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f), > - FRAME_X_WINDOW (f), > + FRAME_X_DRAWABLE (f), > data, > img->width, img->height, > fg, bg, > @@ -3520,7 +3520,7 @@ x_create_bitmap_from_xpm_data (struct frame *f, const char **bits) > xpm_init_color_cache (f, &attrs); > #endif > > - rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > (char **) bits, &bitmap, &mask, &attrs); > if (rc != XpmSuccess) > { > @@ -3758,7 +3758,7 @@ xpm_load (struct frame *f, struct image *img) > #ifdef HAVE_X_WINDOWS > if (rc == XpmSuccess) > { > - img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > img->ximg->width, img->ximg->height, > img->ximg->depth); > if (img->pixmap == NO_PIXMAP) > @@ -3768,7 +3768,7 @@ xpm_load (struct frame *f, struct image *img) > } > else if (img->mask_img) > { > - img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > img->mask_img->width, > img->mask_img->height, > img->mask_img->depth); > @@ -9541,7 +9541,7 @@ gs_load (struct frame *f, struct image *img) > { > /* Only W32 version did BLOCK_INPUT here. ++kfs */ > block_input (); > - img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > img->width, img->height, > DefaultDepthOfScreen (FRAME_X_SCREEN (f))); > unblock_input (); > @@ -9557,7 +9557,7 @@ gs_load (struct frame *f, struct image *img) > if successful. We do not record_unwind_protect here because > other places in redisplay like calling window scroll functions > don't either. Let the Lisp loader use `unwind-protect' instead. */ > - printnum1 = FRAME_X_WINDOW (f); > + printnum1 = FRAME_X_DRAWABLE (f); > printnum2 = img->pixmap; > window_and_pixmap_id > = make_formatted_string (buffer, "%"pMu" %"pMu, printnum1, printnum2); > diff --git a/src/termhooks.h b/src/termhooks.h > index ff74d99..c8d7fae 100644 > --- a/src/termhooks.h > +++ b/src/termhooks.h > @@ -477,6 +477,7 @@ struct terminal > > void (*update_begin_hook) (struct frame *); > void (*update_end_hook) (struct frame *); > + void (*redisplay_end_hook) (struct frame *); > void (*set_terminal_window_hook) (struct frame *, int); > > /* Multi-frame and mouse support hooks. */ > diff --git a/src/xdisp.c b/src/xdisp.c > index 3af5ea4..04f0ca1 100644 > --- a/src/xdisp.c > +++ b/src/xdisp.c > @@ -2501,7 +2501,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect) > > /* Visible feedback for debugging. */ > #if false && defined HAVE_X_WINDOWS > - XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > f->output_data.x->normal_gc, > gx, gy, width, height); > #endif > @@ -14211,6 +14211,13 @@ redisplay_internal (void) > windows_or_buffers_changed = 0; > } > > + FOR_EACH_FRAME (tail, frame) > + { > + struct frame *f = XFRAME (frame); > + if (FRAME_TERMINAL (f)->redisplay_end_hook) > + (*FRAME_TERMINAL (f)->redisplay_end_hook) (f); > + } > + > /* Start SIGIO interrupts coming again. Having them off during the > code above makes it less likely one will discard output, but not > impossible, since there might be stuff in the system buffer here. > @@ -24608,7 +24615,7 @@ init_glyph_string (struct glyph_string *s, > s->hdc = hdc; > #endif > s->display = FRAME_X_DISPLAY (s->f); > - s->window = FRAME_X_WINDOW (s->f); > + s->window = FRAME_X_DRAWABLE (s->f); > s->char2b = char2b; > s->hl = hl; > s->row = row; > diff --git a/src/xfaces.c b/src/xfaces.c > index 5837f35..accb98b 100644 > --- a/src/xfaces.c > +++ b/src/xfaces.c > @@ -495,7 +495,7 @@ x_create_gc (struct frame *f, unsigned long mask, XGCValues *xgcv) > { > GC gc; > block_input (); > - gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), mask, xgcv); > + gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), mask, xgcv); > unblock_input (); > IF_DEBUG (++ngcs); > return gc; > diff --git a/src/xfns.c b/src/xfns.c > index 8571d0e..2098036 100644 > --- a/src/xfns.c > +++ b/src/xfns.c > @@ -53,6 +53,10 @@ along with GNU Emacs. If not, see . */ > #include "gtkutil.h" > #endif > > +#ifdef HAVE_XDBE > +#include > +#endif > + > #ifdef USE_X_TOOLKIT > #include > > @@ -2483,6 +2487,29 @@ xic_set_xfontset (struct frame *f, const char *base_fontname) > > > > + > +void > +set_up_x_back_buffer (struct frame* f) > +{ > + FRAME_X_DRAWABLE (f) = FRAME_X_WINDOW (f); > +#ifdef HAVE_XDBE > + if (FRAME_DISPLAY_INFO (f)->supports_xdbe) > + { > + /* If allocating a back buffer fails, just use single-buffered > + rendering. */ > + x_sync (f); > + x_catch_errors (FRAME_X_DISPLAY (f)); > + FRAME_X_DRAWABLE (f) = XdbeAllocateBackBufferName ( > + FRAME_X_DISPLAY (f), > + FRAME_X_WINDOW (f), > + XdbeCopied); > + if (x_had_errors_p (FRAME_X_DISPLAY (f))) > + FRAME_X_DRAWABLE (f) = FRAME_X_WINDOW (f); > + x_uncatch_errors_after_check (); > + } > +#endif > +} > + > #ifdef USE_X_TOOLKIT > > /* Create and set up the X widget for frame F. */ > @@ -2638,7 +2665,7 @@ x_window (struct frame *f, long window_prompting) > f->output_data.x->parent_desc, 0, 0); > > FRAME_X_WINDOW (f) = XtWindow (frame_widget); > - > + set_up_x_back_buffer (f); > validate_x_resource_name (); > > class_hints.res_name = SSDATA (Vx_resource_name); > @@ -2784,7 +2811,8 @@ x_window (struct frame *f) > CopyFromParent, /* depth */ > InputOutput, /* class */ > FRAME_X_VISUAL (f), > - attribute_mask, &attributes); > + attribute_mask, &attributes); > + set_up_x_back_buffer (f); > > #ifdef HAVE_X_I18N > if (use_xim) > @@ -2938,7 +2966,7 @@ x_make_gc (struct frame *f) > gc_values.line_width = 0; /* Means 1 using fast algorithm. */ > f->output_data.x->normal_gc > = XCreateGC (FRAME_X_DISPLAY (f), > - FRAME_X_WINDOW (f), > + FRAME_X_DRAWABLE (f), > GCLineWidth | GCForeground | GCBackground, > &gc_values); > > @@ -2947,7 +2975,7 @@ x_make_gc (struct frame *f) > gc_values.background = FRAME_FOREGROUND_PIXEL (f); > f->output_data.x->reverse_gc > = XCreateGC (FRAME_X_DISPLAY (f), > - FRAME_X_WINDOW (f), > + FRAME_X_DRAWABLE (f), > GCForeground | GCBackground | GCLineWidth, > &gc_values); > > @@ -2956,7 +2984,7 @@ x_make_gc (struct frame *f) > gc_values.background = f->output_data.x->cursor_pixel; > gc_values.fill_style = FillOpaqueStippled; > f->output_data.x->cursor_gc > - = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > (GCForeground | GCBackground > | GCFillStyle | GCLineWidth), > &gc_values); > @@ -5636,7 +5664,8 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) > /* Border. */ > f->border_width, > CopyFromParent, InputOutput, CopyFromParent, > - mask, &attrs); > + mask, &attrs); > + set_up_x_back_buffer (f); > XChangeProperty (FRAME_X_DISPLAY (f), tip_window, > FRAME_DISPLAY_INFO (f)->Xatom_net_window_type, > XA_ATOM, 32, PropModeReplace, > diff --git a/src/xfont.c b/src/xfont.c > index 45b0e0a..c2b7317 100644 > --- a/src/xfont.c > +++ b/src/xfont.c > @@ -1057,20 +1057,20 @@ xfont_draw (struct glyph_string *s, int from, int to, int x, int y, > { > if (s->padding_p) > for (i = 0; i < len; i++) > - XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x + i, y, str + i, 1); > else > - XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawImageString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x, y, str, len); > } > else > { > if (s->padding_p) > for (i = 0; i < len; i++) > - XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x + i, y, str + i, 1); > else > - XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawString (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x, y, str, len); > } > unblock_input (); > @@ -1083,20 +1083,20 @@ xfont_draw (struct glyph_string *s, int from, int to, int x, int y, > { > if (s->padding_p) > for (i = 0; i < len; i++) > - XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x + i, y, s->char2b + from + i, 1); > else > - XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawImageString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x, y, s->char2b + from, len); > } > else > { > if (s->padding_p) > for (i = 0; i < len; i++) > - XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x + i, y, s->char2b + from + i, 1); > else > - XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_WINDOW (s->f), > + XDrawString16 (FRAME_X_DISPLAY (s->f), FRAME_X_DRAWABLE (s->f), > gc, x, y, s->char2b + from, len); > } > unblock_input (); > diff --git a/src/xftfont.c b/src/xftfont.c > index 34c6f7d..447adf6 100644 > --- a/src/xftfont.c > +++ b/src/xftfont.c > @@ -586,7 +586,7 @@ xftfont_get_xft_draw (struct frame *f) > { > block_input (); > xft_draw= XftDrawCreate (FRAME_X_DISPLAY (f), > - FRAME_X_WINDOW (f), > + FRAME_X_DRAWABLE (f), > FRAME_X_VISUAL (f), > FRAME_X_COLORMAP (f)); > unblock_input (); > @@ -695,6 +695,13 @@ xftfont_end_for_frame (struct frame *f) > return 0; > } > > +static void > +xftfont_flush_frame_caches (struct frame *f) > +{ > + if (FRAME_X_WINDOW (f) != FRAME_X_DRAWABLE (f)) > + xftfont_end_for_frame (f); > +} > + > static bool > xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object, > Lisp_Object entity) > @@ -777,6 +784,9 @@ This is needed with some fonts to correct vertical overlap of glyphs. */); > #if defined (HAVE_M17N_FLT) && defined (HAVE_LIBOTF) > xftfont_driver.shape = xftfont_shape; > #endif > + // When using X double buffering, the XftDraw structure we > + // build seems to be useless once a frame is resized, so > + xftfont_driver.flush_frame_caches = xftfont_flush_frame_caches; > > register_font_driver (&xftfont_driver, NULL); > } > diff --git a/src/xterm.c b/src/xterm.c > index 7476694..7116784 100644 > --- a/src/xterm.c > +++ b/src/xterm.c > @@ -45,6 +45,10 @@ along with GNU Emacs. If not, see . */ > #include > #endif > > +#ifdef HAVE_XDBE > +#include > +#endif > + > /* Load sys/types.h if not already loaded. > In some systems loading it twice is suicidal. */ > #ifndef makedev > @@ -360,7 +364,7 @@ x_begin_cr_clip (struct frame *f, GC gc) > { > cairo_surface_t *surface; > surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f), > - FRAME_X_WINDOW (f), > + FRAME_X_DRAWABLE (f), > FRAME_DISPLAY_INFO (f)->visual, > FRAME_PIXEL_WIDTH (f), > FRAME_PIXEL_HEIGHT (f)); > @@ -722,7 +726,7 @@ x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height) > cairo_fill (cr); > x_end_cr_clip (f); > #else > - XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > gc, x, y, width, height); > #endif > } > @@ -740,7 +744,7 @@ x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height) > cairo_stroke (cr); > x_end_cr_clip (f); > #else > - XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > gc, x, y, width, height); > #endif > } > @@ -756,7 +760,10 @@ x_clear_window (struct frame *f) > cairo_paint (cr); > x_end_cr_clip (f); > #else > - XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); > + if (FRAME_X_WINDOW (f) != FRAME_X_DRAWABLE (f)) > + x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); > + else > + XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); > #endif > } > > @@ -1067,7 +1074,7 @@ x_draw_vertical_window_border (struct window *w, int x, int y0, int y1) > #ifdef USE_CAIRO > x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0); > #else > - XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), > f->output_data.x->normal_gc, x, y0, x, y1); > #endif > } > @@ -1179,6 +1186,21 @@ x_update_window_end (struct window *w, bool cursor_on_p, > /* End update of frame F. This function is installed as a hook in > update_end. */ > > +#if defined (HAVE_XDBE) > +static void > +show_back_buffer (struct frame *f) > +{ > + if (FRAME_X_WINDOW (f) != FRAME_X_DRAWABLE (f)) > + { > + XdbeSwapInfo swap_info; > + memset (&swap_info, 0, sizeof (swap_info)); > + swap_info.swap_window = FRAME_X_WINDOW (f); > + swap_info.swap_action = XdbeCopied; > + XdbeSwapBuffers (FRAME_X_DISPLAY (f), &swap_info, 1); > + } > +} > +#endif > + > static void > x_update_end (struct frame *f) > { > @@ -1207,7 +1229,7 @@ x_update_end (struct frame *f) > if (! FRAME_EXTERNAL_MENU_BAR (f)) > height += FRAME_MENU_BAR_HEIGHT (f); > surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f), > - FRAME_X_WINDOW (f), > + FRAME_X_DRAWABLE (f), > FRAME_DISPLAY_INFO (f)->visual, > width, > height); > @@ -1220,7 +1242,14 @@ x_update_end (struct frame *f) > cairo_destroy (cr); > unblock_input (); > } > -#endif /* USE_CAIRO */ > +#endif > + > +#ifdef HAVE_XDBE > + if (redisplaying_p) > + FRAME_X_NEED_BUFFER_FLIP (f) = true; > + else > + show_back_buffer (f); > +#endif > > #ifndef XFlush > block_input (); > @@ -1229,6 +1258,17 @@ x_update_end (struct frame *f) > #endif > } > > +static void > +x_redisplay_end (struct frame *f) > +{ > +#ifdef HAVE_XDBE > + if (FRAME_X_NEED_BUFFER_FLIP (f)) > + { > + show_back_buffer (f); > + FRAME_X_NEED_BUFFER_FLIP (f) = false; > + } > +#endif > +} > > /* This function is called from various places in xdisp.c > whenever a complete update has been performed. */ > @@ -1354,7 +1394,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring > #else /* not USE_CAIRO */ > if (p->which) > { > - Window window = FRAME_X_WINDOW (f); > + Drawable drawable = FRAME_X_DRAWABLE (f); > char *bits; > Pixmap pixmap, clipmask = (Pixmap) 0; > int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); > @@ -1367,7 +1407,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring > > /* Draw the bitmap. I believe these small pixmaps can be cached > by the server. */ > - pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h, > + pixmap = XCreatePixmapFromBitmapData (display, drawable, bits, p->wd, p->h, > (p->cursor_p > ? (p->overlay_p ? face->background > : f->output_data.x->cursor_pixel) > @@ -1386,7 +1426,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring > XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv); > } > > - XCopyArea (display, pixmap, window, gc, 0, 0, > + XCopyArea (display, pixmap, drawable, gc, 0, 0, > p->wd, p->h, p->x, p->y); > XFreePixmap (display, pixmap); > > @@ -2565,7 +2605,7 @@ x_setup_relief_color (struct frame *f, struct relief *relief, double factor, > { > xgcv.stipple = dpyinfo->gray; > mask |= GCStipple; > - relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv); > + relief->gc = XCreateGC (dpy, FRAME_X_DRAWABLE (f), mask, &xgcv); > } > else > XChangeGC (dpy, relief->gc, mask, &xgcv); > @@ -2696,7 +2736,7 @@ x_draw_relief_rect (struct frame *f, > x_reset_clip_rectangles (f, bottom_right_gc); > #else > Display *dpy = FRAME_X_DISPLAY (f); > - Window window = FRAME_X_WINDOW (f); > + Drawable drawable = FRAME_X_DRAWABLE (f); > int i; > GC gc; > > @@ -2715,12 +2755,12 @@ x_draw_relief_rect (struct frame *f, > if (top_p) > { > if (width == 1) > - XDrawLine (dpy, window, gc, > + XDrawLine (dpy, drawable, gc, > left_x + left_p, top_y, > right_x + !right_p, top_y); > > for (i = 1; i < width; ++i) > - XDrawLine (dpy, window, gc, > + XDrawLine (dpy, drawable, gc, > left_x + i * left_p, top_y + i, > right_x + 1 - i * right_p, top_y + i); > } > @@ -2729,13 +2769,13 @@ x_draw_relief_rect (struct frame *f, > if (left_p) > { > if (width == 1) > - XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y); > + XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y); > > - XClearArea (dpy, window, left_x, top_y, 1, 1, False); > - XClearArea (dpy, window, left_x, bottom_y, 1, 1, False); > + x_clear_area(f, left_x, top_y, 1, 1); > + x_clear_area(f, left_x, bottom_y, 1, 1); > > for (i = (width > 1 ? 1 : 0); i < width; ++i) > - XDrawLine (dpy, window, gc, > + XDrawLine (dpy, drawable, gc, > left_x + i, top_y + (i + 1) * top_p, > left_x + i, bottom_y + 1 - (i + 1) * bot_p); > } > @@ -2751,23 +2791,23 @@ x_draw_relief_rect (struct frame *f, > { > /* Outermost top line. */ > if (top_p) > - XDrawLine (dpy, window, gc, > + XDrawLine (dpy, drawable, gc, > left_x + left_p, top_y, > right_x + !right_p, top_y); > > /* Outermost left line. */ > if (left_p) > - XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y); > + XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y); > } > > /* Bottom. */ > if (bot_p) > { > - XDrawLine (dpy, window, gc, > + XDrawLine (dpy, drawable, gc, > left_x + left_p, bottom_y, > right_x + !right_p, bottom_y); > for (i = 1; i < width; ++i) > - XDrawLine (dpy, window, gc, > + XDrawLine (dpy, drawable, gc, > left_x + i * left_p, bottom_y - i, > right_x + 1 - i * right_p, bottom_y - i); > } > @@ -2775,10 +2815,10 @@ x_draw_relief_rect (struct frame *f, > /* Right. */ > if (right_p) > { > - XClearArea (dpy, window, right_x, top_y, 1, 1, False); > - XClearArea (dpy, window, right_x, bottom_y, 1, 1, False); > + x_clear_area(f, right_x, top_y, 1, 1); > + x_clear_area(f, right_x, bottom_y, 1, 1); > for (i = 0; i < width; ++i) > - XDrawLine (dpy, window, gc, > + XDrawLine (dpy, drawable, gc, > right_x - i, top_y + (i + 1) * top_p, > right_x - i, bottom_y + 1 - (i + 1) * bot_p); > } > @@ -3741,7 +3781,7 @@ x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, > /* Never called on a GUI frame, see > http://lists.gnu.org/archive/html/emacs-devel/2015-05/msg00456.html > */ > - XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f), > + XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), > f->output_data.x->normal_gc, > x, y, width, height, > x + shift_by, y); > @@ -3782,8 +3822,14 @@ x_clear_area (struct frame *f, int x, int y, int width, int height) > cairo_fill (cr); > x_end_cr_clip (f); > #else > - x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > - x, y, width, height, False); > + if (FRAME_X_WINDOW (f) != FRAME_X_DRAWABLE (f)) > + XFillRectangle (FRAME_X_DISPLAY (f), > + FRAME_X_DRAWABLE (f), > + f->output_data.x->reverse_gc, > + x, y, width, height); > + else > + x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), > + x, y, width, height, False); > #endif > } > > @@ -4109,7 +4155,7 @@ x_scroll_run (struct window *w, struct run *run) > SET_FRAME_GARBAGED (f); > #else > XCopyArea (FRAME_X_DISPLAY (f), > - FRAME_X_WINDOW (f), FRAME_X_WINDOW (f), > + FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), > f->output_data.x->normal_gc, > x, from_y, > width, height, > @@ -7769,6 +7815,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, > SET_FRAME_VISIBLE (f, 1); > SET_FRAME_ICONIFIED (f, false); > f->output_data.x->has_been_visible = true; > + font_flush_frame_caches (f); > SET_FRAME_GARBAGED (f); > } > else > @@ -8437,7 +8484,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, > { > if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height > || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) > - SET_FRAME_GARBAGED (f); > + { > + font_flush_frame_caches (f); > + SET_FRAME_GARBAGED (f); > + } > FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height; > FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width; > } > @@ -8463,7 +8513,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, > || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f)) > { > change_frame_size (f, width, height, false, true, false, true); > - x_clear_under_internal_border (f); > + x_clear_under_internal_border (f); > + font_flush_frame_caches (f); > SET_FRAME_GARBAGED (f); > cancel_mouse_face (f); > } > @@ -8880,7 +8931,7 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row *row) > if (dpyinfo->scratch_cursor_gc) > XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv); > else > - dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f), > + dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_DRAWABLE (f), > GCForeground, &xgcv); > gc = dpyinfo->scratch_cursor_gc; > > @@ -8937,7 +8988,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text > else > { > Display *dpy = FRAME_X_DISPLAY (f); > - Window window = FRAME_X_WINDOW (f); > + Drawable drawable = FRAME_X_DRAWABLE (f); > GC gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc; > unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures; > struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); > @@ -8958,7 +9009,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text > XChangeGC (dpy, gc, mask, &xgcv); > else > { > - gc = XCreateGC (dpy, window, mask, &xgcv); > + gc = XCreateGC (dpy, drawable, mask, &xgcv); > FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc; > } > > @@ -11271,7 +11322,14 @@ x_free_frame_resources (struct frame *f) > #endif /* USE_GTK */ > > if (FRAME_X_WINDOW (f)) > - XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); > + { > +#ifdef HAVE_XDBE > + if (FRAME_X_WINDOW (f) != FRAME_X_DRAWABLE (f)) > + XdbeDeallocateBackBufferName (FRAME_X_DISPLAY (f), > + FRAME_X_DRAWABLE (f)); > +#endif > + XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); > + } > #endif /* !USE_X_TOOLKIT */ > > unload_color (f, FRAME_FOREGROUND_PIXEL (f)); > @@ -12111,7 +12169,17 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) > } > else > dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window, > - dpyinfo->visual, AllocNone); > + dpyinfo->visual, AllocNone); > + > +#ifdef HAVE_XDBE > + dpyinfo->supports_xdbe = false; > + { > + int xdbe_major; > + int xdbe_minor; > + if (XdbeQueryExtension (dpyinfo->display, &xdbe_major, &xdbe_minor)) > + dpyinfo->supports_xdbe = true; > + } > +#endif > > #ifdef HAVE_XFT > { > @@ -12590,6 +12658,7 @@ x_create_terminal (struct x_display_info *dpyinfo) > terminal->toggle_invisible_pointer_hook = XTtoggle_invisible_pointer; > terminal->update_begin_hook = x_update_begin; > terminal->update_end_hook = x_update_end; > + terminal->redisplay_end_hook = x_redisplay_end; > terminal->read_socket_hook = XTread_socket; > terminal->frame_up_to_date_hook = XTframe_up_to_date; > terminal->mouse_position_hook = XTmouse_position; > diff --git a/src/xterm.h b/src/xterm.h > index 675a484..cb1aa1d 100644 > --- a/src/xterm.h > +++ b/src/xterm.h > @@ -475,6 +475,10 @@ struct x_display_info > #ifdef USE_XCB > xcb_connection_t *xcb_connection; > #endif > + > +#ifdef HAVE_XDBE > + bool supports_xdbe; > +#endif > }; > > #ifdef HAVE_X_I18N > @@ -527,6 +531,17 @@ struct x_output > and the X window has not yet been created. */ > Window window_desc; > > +#ifdef HAVE_XDBE > + /* The drawable to which we're rendering. In the single-buffered > + base, the window itself. In the double-buffered case, the > + window's back buffer. */ > + Drawable draw_desc; > + > + /* Set to true when we need a buffer flip. We do a buffer flip only > + at the end of redisplay in order to minimize flicker. */ > + bool need_buffer_flip; > +#endif > + > /* The X window used for the bitmap icon; > or 0 if we don't have a bitmap icon. */ > Window icon_desc; > @@ -737,6 +752,18 @@ enum > /* Return the X window used for displaying data in frame F. */ > #define FRAME_X_WINDOW(f) ((f)->output_data.x->window_desc) > > +/* Return the drawable used for rendering to frame F. */ > +#ifdef HAVE_XDBE > +#define FRAME_X_DRAWABLE(f) ((f)->output_data.x->draw_desc) > +#else > +#define FRAME_X_DRAWABLE(f) (0,(FRAME_X_WINDOW (f))) > +#endif > + > +/* Return the need-buffer-flip flag for frame F. */ > +#ifdef HAVE_XDBE > +#define FRAME_X_NEED_BUFFER_FLIP(f) ((f)->output_data.x->need_buffer_flip) > +#endif > + > /* Return the outermost X window associated with the frame F. */ > #ifdef USE_X_TOOLKIT > #define FRAME_OUTER_WINDOW(f) ((f)->output_data.x->widget ? \ > @@ -1140,6 +1167,8 @@ extern bool x_wm_supports (struct frame *, Atom); > extern void x_wait_for_event (struct frame *, int); > extern void x_clear_under_internal_border (struct frame *f); > > +extern void set_up_x_back_buffer (struct frame* f); > + > /* Defined in xselect.c. */ > > extern void x_handle_property_notify (const XPropertyEvent *); > > >