diff options
author | Daniel Colascione <dancol@dancol.org> | 2016-10-20 20:34:36 -0700 |
---|---|---|
committer | Daniel Colascione <dancol@dancol.org> | 2016-10-28 19:21:39 -0700 |
commit | c29071587c64efb30792bd72248d3c791abd9337 (patch) | |
tree | a38c726630104997b7d63cbba56056ed1f8d19fa /src/xfns.c | |
parent | f5543ffcf5b2974fa8fc6cf007e9109fa8e9051e (diff) | |
download | emacs-c29071587c64efb30792bd72248d3c791abd9337.tar.gz |
Add double-buffering support to reduce flicker
* src/dispextern.h (struct glyph_string): Remove window member
(block_buffer_flips, unblock_buffer_flips)
(buffer_flipping_blocked_p): Declare.
* src/xterm.h (struct x_display_info): New member supports_xdbe.
(struct x_output): New members draw_desc and need_buffer_flip.
(FRAME_X_DRAWABLE, FRAME_X_RAW_DRAWABLE)
(FRAME_X_DOUBLE_BUFFERED_P)
(FRAME_X_NEED_BUFFER_FLIP): New macros.
(set_up_x_back_buffer, tear_down_x_back_buffer)
(initial_set_up_x_back_buffer): Declare.
* src/xterm.c: Include Xdbe.h.
(x_begin_cr_clip, x_fill_rectangle, x_draw_rectangle)
(x_draw_vertical_window_border, x_update_end)
(x_setup_relief_color, x_draw_relief_rect)
(x_draw_fringe_bitmap, x_shift_glyphs_for_insert)
(x_scroll_run, x_draw_hollow_cursor, x_draw_bar_cursor): Use
FRAME_X_DRAWABLE instead of FRAME_X_WINDOW; rename local
variables appropriately; substitute calls to XClearArea with
x_clear_area, which DTRT for double buffering.
(x_clear_window, x_clear_area): In double-buffering mode, use
rect-drawing X functions instead of XClearWindow and
XClearArea, which always operate on the front buffer.
(show_back_buffer): New function.
(XTframe_up_to_date): Call show_back_buffer when done.
(x_clear_frame, x_clear_frame_area): Remove obsolete calls to
gtk_widget_queue_draw to refresh scroll bars; scroll bars are
now independent X windows.
(handle_one_xevent): Call font_drop_xrender_surfaces when
XftDraw might need regenerating; perform buffer flip when
responding to Expose events; issue front-buffer clearing
commands as stopgap while we wait for redisplay.
Call flush_dirty_back_buffers.
(x_make_frame_visible): Un-bitrot comment; move XSETFRAME
earlier in function.
(x_free_frame_resources): Call tear_down_x_back_buffer when
destroying frame.
(x_term_init): Attempt to initialize double buffer extension.
(x_flip_and_flush): New function.
(x_redisplay_interface): Point to x_flip_and_flush instead of
x_flip directly.
(flush_dirty_back_buffers): New function.
(x_create_terminal): Register buffer_flipping_unblocked_hook.
* src/xftfont.c (xftfont_drop_xrender_surfaces): Use
FRAME_X_DRAWABLE instead of FRAME_X_WINDOW.
(xftfont_draw): Call x_mark_frame_dirty.
(xftfont_drop_xrender_surfaces): New function.
(syms_of_xftfont): Register it.
* src/xfont.c (xfont_draw): Use FRAME_X_DRAWABLE instead of
FRAME_X_WINDOW.
* src/xfns.c: Include Xdbe.h.
(x_set_inhibit_double_buffering, set_up_x_back_buffer)
(Fx_double_buffered_p): New functions.
(x_window): Call initial_set_up_x_back_buffer.
(x_make_gc): Use FRAME_X_DRAWABLE instead of FRAME_X_WINDOW.
(Fx_create_frame): Configure `inhibit-double-buffering'
frame parameter.
(x_create_tip_frame): Call initial_set_up_x_back_buffer.
(x_frame_parm_handlers): Register
x_set_inhibit_double_buffering.
(syms_of_xfns): Register Sx_double_buffered_p.
(x_mark_frame_dirty): Define.
* src/xfaces.c (x_create_gc): Use FRAME_X_DRAWABLE instead of
FRAME_X_WINDOW.
* src/xdisp.c (remember_mouse_glyph, init_glyph_string): Use
FRAME_X_DRAWABLE instead of FRAME_X_WINDOW.
(redisplay_internal): Restart redisplay if a frame is garbaged
during updating; explain why. Block buffer flips
during redisplay.
(redisplay_preserve_echo_area): Block buffer flip during call
to redisplay_internal.
(buffer_flip_blocked_depth): New variable.
(block_buffer_flips, unblock_buffer_flips)
(buffer_flipping_blocked_p): New functions.
(init_glyph_string): Stop setting window member of struct
glyph_string.
* src/w32fns.c (w32_frame_parm_handlers): Add placeholder for
x_set_inhibit_double_buffering.
* src/termhooks.h (struct terminal): Add
buffer_flipping_unblocked_hook.
* src/nsfns.m (ns_frame_parm_handlers): Add placeholder for
x_set_inhibit_double_buffering.
* src/image.c (x_create_bitmap_from_data)
(x_create_bitmap_from_file, x_create_x_image_and_pixmap)
(Create_Pixmap_From_Bitmap_Data)
(x_create_bitmap_from_xpm_data, xpm_load, gs_load): Use
FRAME_X_DRAWABLE instead of FRAME_X_WINDOW; rename local
variables appropriately.
* src/gtkutil.c: Include Xdbe.h.
(xg_get_widget_from_map): Forward declare.
(xg_clear_under_internal_border): Remove obsolete calls to
refresh scroll bars.
(xg_create_frame_widgets): Call initial_set_up_x_back_buffer.
(xg_free_frame_widgets): Call tear_down_x_back_buffer; reset
FRAME_X_DRAWABLE as well as FRAME_X_WINDOW and for the
same reason.
(xg_set_background_color): Set scroll bar background colors.
(xg_finish_scroll_bar_creation): New function with common
logic of xg_create_scroll_bar, xg_create_horizontal_scroll_bar. Force
scroll bars to be real X11 windows.
(xg_create_scroll_bar, xg_create_horizontal_scroll_bar): Call
xg_finish_scroll_bar_creation.
(xg_update_scrollbar_pos, xg_update_horizontal_scrollbar_pos):
Remove obsolete calls to refresh scroll bars; fix comments.
* src/ftxfont.c (ftxfont_get_gcs, ftxfont_draw_bitmap,
(ftxfont_draw_background): Use FRAME_X_DRAWABLE instead of
FRAME_X_WINDOW.
* src/frame.c (frame_parms): Add table entry for new
`inhibit-double-buffering' frame parameter
(syms_of_frame): Register Qinhibit_double_buffering.
* src/font.h (struct font_driver): Add new `flush_frame_caches' hook.
(font_drop_xrender_surfaces): Declare.
* src/font.c (font_drop_xrender_surfaces): New function.
* src/Makefile.in (XDBE_LIBS, XDBE_CFLAGS): Substitute.
* etc/NEWS: Mention use of double buffering
* doc/lispref/frames.texi (Management Parameters): Document
`inhibit-double-buffering' frame parameters.
(Visibility of Frames): Document `x-double-buffered-p'.
* configure.ac: Check for the X double buffer extension
Diffstat (limited to 'src/xfns.c')
-rw-r--r-- | src/xfns.c | 128 |
1 files changed, 122 insertions, 6 deletions
diff --git a/src/xfns.c b/src/xfns.c index 8571d0e20ab..3438c8ef5b4 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> @@ -114,6 +118,7 @@ static int dpyinfo_refcount; #endif static struct x_display_info *x_display_info_for_name (Lisp_Object); +static void set_up_x_back_buffer (struct frame *f); /* Let the user specify an X display with a Lisp object. OBJECT may be nil, a frame or a terminal object. @@ -701,6 +706,35 @@ x_set_tool_bar_position (struct frame *f, wrong_choice (choice, new_value); } +static void +x_set_inhibit_double_buffering (struct frame *f, + Lisp_Object new_value, + Lisp_Object old_value) +{ + block_input (); + 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. */ + if (want_double_buffering != was_double_buffered) + font_drop_xrender_surfaces (f); + if (FRAME_X_DOUBLE_BUFFERED_P (f) && !want_double_buffering) + tear_down_x_back_buffer (f); + else if (!FRAME_X_DOUBLE_BUFFERED_P (f) && want_double_buffering) + set_up_x_back_buffer (f); + if (FRAME_X_DOUBLE_BUFFERED_P (f) != was_double_buffered) + { + SET_FRAME_GARBAGED (f); + font_drop_xrender_surfaces (f); + } + } + unblock_input (); +} + #ifdef USE_GTK /* Set icon from FILE for frame F. By using GTK functions the icon @@ -2483,6 +2517,72 @@ 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)) + FRAME_X_NEED_BUFFER_FLIP (f) = true; +} + +static void +set_up_x_back_buffer (struct frame *f) +{ +#ifdef HAVE_XDBE + block_input (); + if (FRAME_X_WINDOW (f) && !FRAME_X_DOUBLE_BUFFERED_P (f)) + { + FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f); + if (FRAME_DISPLAY_INFO (f)->supports_xdbe) + { + /* If allocating a back buffer fails, either because the + server ran out of memory or we don't have the right kind + of visual, just use single-buffered rendering. */ + x_catch_errors (FRAME_X_DISPLAY (f)); + FRAME_X_RAW_DRAWABLE (f) = XdbeAllocateBackBufferName ( + FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + XdbeCopied); + if (x_had_errors_p (FRAME_X_DISPLAY (f))) + FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f); + x_uncatch_errors_after_check (); + } + } + unblock_input (); +#endif +} + +void +tear_down_x_back_buffer (struct frame *f) +{ +#ifdef HAVE_XDBE + block_input (); + if (FRAME_X_WINDOW (f) && FRAME_X_DOUBLE_BUFFERED_P (f)) + { + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + { + XdbeDeallocateBackBufferName (FRAME_X_DISPLAY (f), + FRAME_X_DRAWABLE (f)); + FRAME_X_RAW_DRAWABLE (f) = FRAME_X_WINDOW (f); + } + } + unblock_input (); +#endif +} + +/* Set up double buffering if the frame parameters don't prohibit + it. */ +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)))) + set_up_x_back_buffer (f); + unblock_input (); +} + #ifdef USE_X_TOOLKIT /* Create and set up the X widget for frame F. */ @@ -2638,7 +2738,7 @@ x_window (struct frame *f, long window_prompting) f->output_data.x->parent_desc, 0, 0); FRAME_X_WINDOW (f) = XtWindow (frame_widget); - + initial_set_up_x_back_buffer (f); validate_x_resource_name (); class_hints.res_name = SSDATA (Vx_resource_name); @@ -2784,7 +2884,8 @@ x_window (struct frame *f) CopyFromParent, /* depth */ InputOutput, /* class */ FRAME_X_VISUAL (f), - attribute_mask, &attributes); + attribute_mask, &attributes); + initial_set_up_x_back_buffer (f); #ifdef HAVE_X_I18N if (use_xim) @@ -2938,7 +3039,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 +3048,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 +3057,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); @@ -3463,6 +3564,9 @@ This function is an internal primitive--use `make-frame' instead. */) "waitForWM", "WaitForWM", RES_TYPE_BOOLEAN); x_default_parameter (f, parms, Qtool_bar_position, FRAME_TOOL_BAR_POSITION (f), 0, 0, RES_TYPE_SYMBOL); + x_default_parameter (f, parms, Qinhibit_double_buffering, Qnil, + "inhibitDoubleBuffering", "InhibitDoubleBuffering", + RES_TYPE_BOOLEAN); /* Compute the size of the X window. */ window_prompting = x_figure_window_size (f, parms, true, &x_width, &x_height); @@ -5636,7 +5740,8 @@ x_create_tip_frame (struct x_display_info *dpyinfo, Lisp_Object parms) /* Border. */ f->border_width, CopyFromParent, InputOutput, CopyFromParent, - mask, &attrs); + mask, &attrs); + initial_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, @@ -6213,6 +6318,15 @@ Value is t if tooltip was open, nil otherwise. */) return x_hide_tip (!tooltip_reuse_hidden_frame); } +DEFUN ("x-double-buffered-p", Fx_double_buffered_p, Sx_double_buffered_p, + 0, 1, 0, + doc: /* Return t if FRAME is being double buffered. */) + (Lisp_Object frame) +{ + struct frame *f = decode_live_frame (frame); + return FRAME_X_DOUBLE_BUFFERED_P (f) ? Qt : Qnil; +} + /*********************************************************************** File selection dialog @@ -6864,6 +6978,7 @@ frame_parm_handler x_frame_parm_handlers[] = x_set_alpha, x_set_sticky, x_set_tool_bar_position, + x_set_inhibit_double_buffering, }; void @@ -7080,6 +7195,7 @@ When using Gtk+ tooltips, the tooltip face is not used. */); defsubr (&Sx_show_tip); defsubr (&Sx_hide_tip); + defsubr (&Sx_double_buffered_p); tip_timer = Qnil; staticpro (&tip_timer); tip_frame = Qnil; |