summaryrefslogtreecommitdiff
path: root/src/xfns.c
diff options
context:
space:
mode:
authorDaniel Colascione <dancol@dancol.org>2016-10-20 20:34:36 -0700
committerDaniel Colascione <dancol@dancol.org>2016-10-28 19:21:39 -0700
commitc29071587c64efb30792bd72248d3c791abd9337 (patch)
treea38c726630104997b7d63cbba56056ed1f8d19fa /src/xfns.c
parentf5543ffcf5b2974fa8fc6cf007e9109fa8e9051e (diff)
downloademacs-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.c128
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;