[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
RFC: flicker-free double-buffered Emacs under X11
From: |
Daniel Colascione |
Subject: |
RFC: flicker-free double-buffered Emacs under X11 |
Date: |
Thu, 20 Oct 2016 18:32:01 -0700 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.3.0 |
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 <address@hidden>
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 <X11/Xlib.h>
+ ])
+ 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.
address@hidden@
@@ -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
<http://www.gnu.org/licenses/>. */
#include "emacsgtkfixed.h"
#endif
+#ifdef HAVE_XDBE
+#include <X11/extensions/Xdbe.h>
+#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
<http://www.gnu.org/licenses/>. */
#include "gtkutil.h"
#endif
+#ifdef HAVE_XDBE
+#include <X11/extensions/Xdbe.h>
+#endif
+
#ifdef USE_X_TOOLKIT
#include <X11/Shell.h>
@@ -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
<http://www.gnu.org/licenses/>. */
#include <X11/extensions/Xrender.h>
#endif
+#ifdef HAVE_XDBE
+#include <X11/extensions/Xdbe.h>
+#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 *);
- RFC: flicker-free double-buffered Emacs under X11,
Daniel Colascione <=
Re: RFC: flicker-free double-buffered Emacs under X11, Clément Pit--Claudel, 2016/10/20
Re: RFC: flicker-free double-buffered Emacs under X11, Eli Zaretskii, 2016/10/21