From c29071587c64efb30792bd72248d3c791abd9337 Mon Sep 17 00:00:00 2001 From: Daniel Colascione Date: Thu, 20 Oct 2016 20:34:36 -0700 Subject: 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 --- src/xftfont.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'src/xftfont.c') diff --git a/src/xftfont.c b/src/xftfont.c index 34c6f7d3e42..861ad80da5c 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 (); @@ -600,6 +600,8 @@ static int xftfont_draw (struct glyph_string *s, int from, int to, int x, int y, bool with_background) { + block_input (); + struct frame *f = s->f; struct face *face = s->face; struct xftfont_info *xftfont_info = (struct xftfont_info *) s->font; @@ -614,7 +616,6 @@ xftfont_draw (struct glyph_string *s, int from, int to, int x, int y, xftface_info = (struct xftface_info *) face->extra; xftfont_get_colors (f, face, s->gc, xftface_info, &fg, with_background ? &bg : NULL); - block_input (); if (s->num_clips > 0) XftDrawSetClipRectangles (xft_draw, 0, 0, s->clip, s->num_clips); else @@ -652,9 +653,12 @@ xftfont_draw (struct glyph_string *s, int from, int to, int x, int y, x + i, y, code + i, 1); else XftDrawGlyphs (xft_draw, &fg, xftfont_info->xftfont, - x, y, code, len); + x, y, code, len); + /* Need to explicitly mark the frame dirty because we didn't call + FRAME_X_DRAWABLE in order to draw: we cached the drawable in the + XftDraw structure. */ + x_mark_frame_dirty (f); unblock_input (); - return len; } @@ -678,13 +682,10 @@ xftfont_shape (Lisp_Object lgstring) static int xftfont_end_for_frame (struct frame *f) { + block_input (); XftDraw *xft_draw; - /* Don't do anything if display is dead */ - if (FRAME_X_DISPLAY (f) == NULL) return 0; - xft_draw = font_get_frame_data (f, Qxft); - if (xft_draw) { block_input (); @@ -692,9 +693,19 @@ xftfont_end_for_frame (struct frame *f) unblock_input (); font_put_frame_data (f, Qxft, NULL); } + unblock_input (); return 0; } +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 (); +} + static bool xftfont_cached_font_ok (struct frame *f, Lisp_Object font_object, Lisp_Object entity) @@ -777,6 +788,10 @@ 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 recreate it on + ConfigureNotify and in some other cases. */ + xftfont_driver.drop_xrender_surfaces = xftfont_drop_xrender_surfaces; register_font_driver (&xftfont_driver, NULL); } -- cgit v1.2.1