1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-31 12:51:54 -08:00

Clean up X11 double buffering code

This fixes several latent bugs where code went down the path
with double buffering enabled when it wasn't, and vice versa.

* src/xfns.c (x_set_inhibit_double_buffering): Improve
commentary and only define when HAVE_XDBE.
(x_mark_frame_dirty): Only set buffer flip flag when HAVE_XDBE.
(initial_set_up_x_back_buffer): Clean up coding style and remove
unnecessary block_input pair.
(Fx_double_buffered_p): Always return nil if !HAVE_XDBE.
(x_frame_parm_handlers): Don't set double buffering handler if
!HAVE_XDBE.

* src/xftfont.c (xftfont_drop_xrender_surfaces, xftfont_driver):
Only define when XDBE is available.

* src/xterm.c (x_drop_xrender_surfaces): Likewise.
(x_clear_window): Don't test double buffering flags when
!HAVE_XDBE.
(show_back_buffer): Only define when HAVE_XDBE.
(x_flip_and_flush): Don't try to flip when !HAVE_XDBE.
(XTframe_up_to_date): Likewise.
(XTbuffer_flipping_unblocked_hook): Only define when Xdbe is
available.
(x_clear_area): Don't test double buffering flags when Xdbe is
not available.
(flush_dirty_back_buffer_on): Don't define if there's no DBE.
(handle_one_xevent, x_create_terminal): Likewise.

* src/xterm.h (FRAME_X_DRAWABLE): Fix coding style.
This commit is contained in:
Po Lu 2022-05-03 09:22:06 +08:00
parent 64bcfcbd32
commit 952cc28e58
4 changed files with 109 additions and 51 deletions

View file

@ -823,22 +823,24 @@ x_set_tool_bar_position (struct frame *f,
wrong_choice (choice, new_value);
}
#ifdef HAVE_XDBE
static void
x_set_inhibit_double_buffering (struct frame *f,
Lisp_Object new_value,
Lisp_Object old_value)
{
block_input ();
bool want_double_buffering, was_double_buffered;
if (FRAME_X_WINDOW (f) && !EQ (new_value, old_value))
{
bool want_double_buffering = NILP (new_value);
bool was_double_buffered = FRAME_X_DOUBLE_BUFFERED_P (f);
/* font_drop_xrender_surfaces in xftfont does something only if
we're double-buffered, so call font_drop_xrender_surfaces before
and after any potential change. One of the calls will end up
being a no-op. */
want_double_buffering = NILP (new_value);
was_double_buffered = FRAME_X_DOUBLE_BUFFERED_P (f);
block_input ();
if (want_double_buffering != was_double_buffered)
{
/* Force XftDraw etc to be recreated with the new double
buffered drawable. */
font_drop_xrender_surfaces (f);
/* Scroll bars decide whether or not to use a back buffer
@ -860,9 +862,10 @@ x_set_inhibit_double_buffering (struct frame *f,
SET_FRAME_GARBAGED (f);
font_drop_xrender_surfaces (f);
}
unblock_input ();
}
unblock_input ();
}
#endif
/**
* x_set_undecorated:
@ -3548,8 +3551,11 @@ xic_set_xfontset (struct frame *f, const char *base_fontname)
void
x_mark_frame_dirty (struct frame *f)
{
if (FRAME_X_DOUBLE_BUFFERED_P (f) && !FRAME_X_NEED_BUFFER_FLIP (f))
#ifdef HAVE_XDBE
if (FRAME_X_DOUBLE_BUFFERED_P (f)
&& !FRAME_X_NEED_BUFFER_FLIP (f))
FRAME_X_NEED_BUFFER_FLIP (f) = true;
#endif
}
static void
@ -3630,12 +3636,12 @@ tear_down_x_back_buffer (struct frame *f)
void
initial_set_up_x_back_buffer (struct frame *f)
{
block_input ();
eassert (FRAME_X_WINDOW (f));
FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f);
if (NILP (CDR (Fassq (Qinhibit_double_buffering, f->param_alist))))
if (NILP (CDR (Fassq (Qinhibit_double_buffering,
f->param_alist))))
set_up_x_back_buffer (f);
unblock_input ();
}
#if defined HAVE_XINPUT2
@ -8614,7 +8620,12 @@ DEFUN ("x-double-buffered-p", Fx_double_buffered_p, Sx_double_buffered_p,
(Lisp_Object frame)
{
struct frame *f = decode_live_frame (frame);
#ifdef HAVE_XDBE
return FRAME_X_DOUBLE_BUFFERED_P (f) ? Qt : Qnil;
#else
return Qnil;
#endif
}
@ -9360,7 +9371,11 @@ frame_parm_handler x_frame_parm_handlers[] =
gui_set_alpha,
x_set_sticky,
x_set_tool_bar_position,
#ifdef HAVE_XDBE
x_set_inhibit_double_buffering,
#else
NULL,
#endif
x_set_undecorated,
x_set_parent_frame,
x_set_skip_taskbar,

View file

@ -643,18 +643,23 @@ xftfont_end_for_frame (struct frame *f)
return 0;
}
/* When using X double buffering, the XftDraw structure we build
seems to be useless once a frame is resized, so recreate it on
/* When using X double buffering, the XRender surfaces we create seem
to become useless once the window acting as the front buffer is
resized for an unknown reason (X server bug?), so recreate it on
ConfigureNotify and in some other cases. */
#ifdef HAVE_XDBE
static void
xftfont_drop_xrender_surfaces (struct frame *f)
{
block_input ();
if (FRAME_X_DOUBLE_BUFFERED_P (f))
xftfont_end_for_frame (f);
unblock_input ();
{
block_input ();
xftfont_end_for_frame (f);
unblock_input ();
}
}
#endif
static bool
xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object,
@ -741,35 +746,37 @@ static void syms_of_xftfont_for_pdumper (void);
struct font_driver const xftfont_driver =
{
/* We can't draw a text without device dependent functions. */
.type = LISPSYM_INITIALLY (Qxft),
.get_cache = xfont_get_cache,
.list = xftfont_list,
.match = xftfont_match,
.list_family = ftfont_list_family,
.open_font = xftfont_open,
.close_font = xftfont_close,
.prepare_face = xftfont_prepare_face,
.done_face = xftfont_done_face,
.has_char = xftfont_has_char,
.encode_char = xftfont_encode_char,
.text_extents = xftfont_text_extents,
.draw = xftfont_draw,
.get_bitmap = ftfont_get_bitmap,
.anchor_point = ftfont_anchor_point,
.type = LISPSYM_INITIALLY (Qxft),
.get_cache = xfont_get_cache,
.list = xftfont_list,
.match = xftfont_match,
.list_family = ftfont_list_family,
.open_font = xftfont_open,
.close_font = xftfont_close,
.prepare_face = xftfont_prepare_face,
.done_face = xftfont_done_face,
.has_char = xftfont_has_char,
.encode_char = xftfont_encode_char,
.text_extents = xftfont_text_extents,
.draw = xftfont_draw,
.get_bitmap = ftfont_get_bitmap,
.anchor_point = ftfont_anchor_point,
#ifdef HAVE_LIBOTF
.otf_capability = ftfont_otf_capability,
.otf_capability = ftfont_otf_capability,
#endif
.end_for_frame = xftfont_end_for_frame,
.end_for_frame = xftfont_end_for_frame,
#if defined HAVE_M17N_FLT && defined HAVE_LIBOTF
.shape = xftfont_shape,
.shape = xftfont_shape,
#endif
#if defined HAVE_OTF_GET_VARIATION_GLYPHS || defined HAVE_FT_FACE_GETCHARVARIANTINDEX
.get_variation_glyphs = ftfont_variation_glyphs,
.get_variation_glyphs = ftfont_variation_glyphs,
#endif
.filter_properties = ftfont_filter_properties,
.cached_font_ok = xftfont_cached_font_ok,
.combining_capability = ftfont_combining_capability,
#ifdef HAVE_XDBE
.drop_xrender_surfaces = xftfont_drop_xrender_surfaces,
#endif
.filter_properties = ftfont_filter_properties,
.cached_font_ok = xftfont_cached_font_ok,
.combining_capability = ftfont_combining_capability,
.drop_xrender_surfaces = xftfont_drop_xrender_surfaces,
};
#ifdef HAVE_HARFBUZZ
struct font_driver xfthbfont_driver;

View file

@ -3780,6 +3780,7 @@ x_flush (struct frame *f)
unblock_input ();
}
#ifdef HAVE_XDBE
static void
x_drop_xrender_surfaces (struct frame *f)
{
@ -3795,6 +3796,7 @@ x_drop_xrender_surfaces (struct frame *f)
}
#endif
}
#endif
#ifdef HAVE_XRENDER
void
@ -5127,9 +5129,14 @@ x_clear_window (struct frame *f)
x_end_cr_clip (f);
#else
#ifndef USE_GTK
if (FRAME_X_DOUBLE_BUFFERED_P (f) || (f->alpha_background != 1.0))
if (f->alpha_background != 1.0
#ifdef HAVE_XDBE
|| FRAME_X_DOUBLE_BUFFERED_P (f)
#endif
x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
)
#endif
x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f),
FRAME_PIXEL_HEIGHT (f));
#ifndef USE_GTK
else
XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
@ -5456,13 +5463,15 @@ x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
/* Show the frame back buffer. If frame is double-buffered,
atomically publish to the user's screen graphics updates made since
the last call to show_back_buffer. */
#ifdef HAVE_XDBE
static void
show_back_buffer (struct frame *f)
{
block_input ();
if (FRAME_X_DOUBLE_BUFFERED_P (f))
{
#ifdef HAVE_XDBE
#ifdef USE_CAIRO
cairo_t *cr = FRAME_CR_CONTEXT (f);
if (cr)
@ -5473,13 +5482,12 @@ show_back_buffer (struct frame *f)
swap_info.swap_window = FRAME_X_WINDOW (f);
swap_info.swap_action = XdbeCopied;
XdbeSwapBuffers (FRAME_X_DISPLAY (f), &swap_info, 1);
#else
eassert (!"should have back-buffer only with XDBE");
#endif
}
FRAME_X_NEED_BUFFER_FLIP (f) = false;
unblock_input ();
}
#endif
/* Updates back buffer and flushes changes to display. Called from
minibuf read code. Note that we display the back buffer even if
@ -5488,8 +5496,10 @@ static void
x_flip_and_flush (struct frame *f)
{
block_input ();
#ifdef HAVE_XDBE
if (FRAME_X_NEED_BUFFER_FLIP (f))
show_back_buffer (f);
#endif
x_flush (f);
unblock_input ();
}
@ -5538,8 +5548,12 @@ XTframe_up_to_date (struct frame *f)
eassert (FRAME_X_P (f));
block_input ();
FRAME_MOUSE_UPDATE (f);
if (!buffer_flipping_blocked_p () && FRAME_X_NEED_BUFFER_FLIP (f))
#ifdef HAVE_XDBE
if (!buffer_flipping_blocked_p ()
&& FRAME_X_NEED_BUFFER_FLIP (f))
show_back_buffer (f);
#endif
#ifdef HAVE_XSYNC
#ifndef HAVE_GTK3
@ -5592,12 +5606,14 @@ XTframe_up_to_date (struct frame *f)
unblock_input ();
}
#ifdef HAVE_XDBE
static void
XTbuffer_flipping_unblocked_hook (struct frame *f)
{
if (FRAME_X_NEED_BUFFER_FLIP (f))
show_back_buffer (f);
}
#endif
/**
* x_clear_under_internal_border:
@ -8716,8 +8732,11 @@ x_clear_area (struct frame *f, int x, int y, int width, int height)
x_end_cr_clip (f);
#else
#ifndef USE_GTK
if (FRAME_X_DOUBLE_BUFFERED_P (f)
|| f->alpha_background != 1.0)
if (f->alpha_background != 1.0
#ifdef HAVE_XDBE
|| FRAME_X_DOUBLE_BUFFERED_P (f)
#endif
)
#endif
{
#if defined HAVE_XRENDER && \
@ -13738,7 +13757,9 @@ x_net_wm_state (struct frame *f, Window window)
store_frame_param (f, Qshaded, shaded ? Qt : Qnil);
}
/* Flip back buffers on FRAME if it has undrawn content. */
/* Flip back buffers on F if it has undrawn content. */
#ifdef HAVE_XDBE
static void
flush_dirty_back_buffer_on (struct frame *f)
{
@ -13749,6 +13770,7 @@ flush_dirty_back_buffer_on (struct frame *f)
show_back_buffer (f);
unblock_input ();
}
#endif
#ifdef HAVE_GTK3
void
@ -14707,8 +14729,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
SET_FRAME_ICONIFIED (f, false);
}
#ifdef HAVE_XDBE
if (FRAME_X_DOUBLE_BUFFERED_P (f))
x_drop_xrender_surfaces (f);
#endif
f->output_data.x->has_been_visible = true;
SET_FRAME_GARBAGED (f);
unblock_input ();
@ -14753,8 +14777,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#endif
}
#ifdef HAVE_XDBE
if (!FRAME_GARBAGED_P (f))
show_back_buffer (f);
#endif
}
else
{
@ -14802,7 +14828,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#ifdef USE_GTK
x_clear_under_internal_border (f);
#endif
#ifdef HAVE_XDBE
show_back_buffer (f);
#endif
}
#ifdef USE_X_TOOLKIT
else
@ -16016,8 +16044,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
for size changes: that's not sufficient. We miss some
surface invalidations and flicker. */
block_input ();
#ifdef HAVE_XDBE
if (f && FRAME_X_DOUBLE_BUFFERED_P (f))
x_drop_xrender_surfaces (f);
#endif
unblock_input ();
#if defined USE_CAIRO && !defined USE_GTK
if (f)
@ -19447,11 +19477,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
redisplay. To ensure that these changes become visible, draw
them here. */
#ifdef HAVE_XDBE
if (f)
flush_dirty_back_buffer_on (f);
if (any && any != f)
flush_dirty_back_buffer_on (any);
#endif
return count;
}
@ -24309,7 +24341,9 @@ x_create_terminal (struct x_display_info *dpyinfo)
terminal->update_end_hook = x_update_end;
terminal->read_socket_hook = XTread_socket;
terminal->frame_up_to_date_hook = XTframe_up_to_date;
#ifdef HAVE_XDBE
terminal->buffer_flipping_unblocked_hook = XTbuffer_flipping_unblocked_hook;
#endif
terminal->defined_color_hook = x_defined_color;
terminal->query_frame_background_color = x_query_frame_background_color;
terminal->query_colors = x_query_colors;

View file

@ -1025,13 +1025,15 @@ extern void x_mark_frame_dirty (struct frame *f);
code after any drawing command, but we can run code whenever
someone asks for the handle necessary to draw. */
#define FRAME_X_DRAWABLE(f) \
(x_mark_frame_dirty((f)), FRAME_X_RAW_DRAWABLE ((f)))
(x_mark_frame_dirty ((f)), FRAME_X_RAW_DRAWABLE ((f)))
#ifdef HAVE_XDBE
#define FRAME_X_DOUBLE_BUFFERED_P(f) \
(FRAME_X_WINDOW (f) != FRAME_X_RAW_DRAWABLE (f))
/* Return the need-buffer-flip flag for frame F. */
#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