summaryrefslogtreecommitdiff
path: root/src/xterm.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/xterm.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/xterm.c')
-rw-r--r--src/xterm.c288
1 files changed, 208 insertions, 80 deletions
diff --git a/src/xterm.c b/src/xterm.c
index 747669446f5..f0dd0ca1dc1 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_DOUBLE_BUFFERED_P (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
}
@@ -1175,6 +1182,41 @@ x_update_window_end (struct window *w, bool cursor_on_p,
}
}
+/* 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. */
+static void
+show_back_buffer (struct frame *f)
+{
+ block_input ();
+ if (FRAME_X_DOUBLE_BUFFERED_P (f))
+ {
+#ifdef HAVE_XDBE
+ 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);
+#else
+ eassert (!"should have back-buffer only with XDBE");
+#endif
+ }
+ FRAME_X_NEED_BUFFER_FLIP (f) = false;
+ unblock_input ();
+}
+
+/* Updates back buffer and flushes changes to display. Called from
+ minibuf read code. Note that we display the back buffer even if
+ buffer flipping is blocked. */
+static void
+x_flip_and_flush (struct frame *f)
+{
+ block_input ();
+ if (FRAME_X_NEED_BUFFER_FLIP (f))
+ show_back_buffer (f);
+ x_flush (f);
+ unblock_input ();
+}
/* End update of frame F. This function is installed as a hook in
update_end. */
@@ -1207,7 +1249,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 +1262,7 @@ x_update_end (struct frame *f)
cairo_destroy (cr);
unblock_input ();
}
-#endif /* USE_CAIRO */
+#endif
#ifndef XFlush
block_input ();
@@ -1229,17 +1271,26 @@ x_update_end (struct frame *f)
#endif
}
-
/* This function is called from various places in xdisp.c
whenever a complete update has been performed. */
static void
XTframe_up_to_date (struct frame *f)
{
- if (FRAME_X_P (f))
- FRAME_MOUSE_UPDATE (f);
+ eassert (FRAME_X_P (f));
+ block_input ();
+ FRAME_MOUSE_UPDATE (f);
+ if (!buffer_flipping_blocked_p () && FRAME_X_NEED_BUFFER_FLIP (f))
+ show_back_buffer (f);
+ unblock_input ();
}
+static void
+XTbuffer_flipping_unblocked_hook (struct frame *f)
+{
+ if (FRAME_X_NEED_BUFFER_FLIP (f))
+ show_back_buffer (f);
+}
/* Clear under internal border if any (GTK has its own version). */
#ifndef USE_GTK
@@ -1354,7 +1405,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 +1418,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 +1437,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);
@@ -1487,7 +1538,7 @@ x_set_cursor_gc (struct glyph_string *s)
mask, &xgcv);
else
FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
- = XCreateGC (s->display, s->window, mask, &xgcv);
+ = XCreateGC (s->display, FRAME_X_DRAWABLE (s->f), mask, &xgcv);
s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
}
@@ -1534,7 +1585,7 @@ x_set_mouse_face_gc (struct glyph_string *s)
mask, &xgcv);
else
FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc
- = XCreateGC (s->display, s->window, mask, &xgcv);
+ = XCreateGC (s->display, FRAME_X_DRAWABLE (s->f), mask, &xgcv);
s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc;
@@ -2565,7 +2616,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 +2747,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 +2766,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 +2780,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 +2802,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 +2826,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);
}
@@ -2930,7 +2981,8 @@ x_draw_image_foreground (struct glyph_string *s)
image_rect.width = s->slice.width;
image_rect.height = s->slice.height;
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
- XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+ XCopyArea (s->display, s->img->pixmap,
+ FRAME_X_DRAWABLE (s->f), s->gc,
s->slice.x + r.x - x, s->slice.y + r.y - y,
r.width, r.height, r.x, r.y);
}
@@ -2944,7 +2996,8 @@ x_draw_image_foreground (struct glyph_string *s)
image_rect.width = s->slice.width;
image_rect.height = s->slice.height;
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
- XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
+ XCopyArea (s->display, s->img->pixmap,
+ FRAME_X_DRAWABLE (s->f), s->gc,
s->slice.x + r.x - x, s->slice.y + r.y - y,
r.width, r.height, r.x, r.y);
@@ -3184,7 +3237,7 @@ x_draw_image_glyph_string (struct glyph_string *s)
int depth = DefaultDepthOfScreen (screen);
/* Create a pixmap as large as the glyph string. */
- pixmap = XCreatePixmap (s->display, s->window,
+ pixmap = XCreatePixmap (s->display, FRAME_X_DRAWABLE (s->f),
s->background_width,
s->height, depth);
@@ -3259,7 +3312,7 @@ x_draw_image_glyph_string (struct glyph_string *s)
{
x_draw_image_foreground_1 (s, pixmap);
x_set_glyph_string_clipping (s);
- XCopyArea (s->display, pixmap, s->window, s->gc,
+ XCopyArea (s->display, pixmap, FRAME_X_DRAWABLE (s->f), s->gc,
0, 0, s->background_width, s->height, s->x, s->y);
XFreePixmap (s->display, pixmap);
}
@@ -3438,7 +3491,7 @@ x_draw_underwave (struct glyph_string *s)
while (x1 <= xmax)
{
- XDrawLine (s->display, s->window, s->gc, x1, y1, x2, y2);
+ XDrawLine (s->display, FRAME_X_DRAWABLE (s->f), s->gc, x1, y1, x2, y2);
x1 = x2, y1 = y2;
x2 += dx, y2 = y0 + odd*dy;
odd = !odd;
@@ -3741,7 +3794,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 +3835,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_DOUBLE_BUFFERED_P (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
}
@@ -3799,19 +3858,13 @@ x_clear_frame (struct frame *f)
block_input ();
+ font_drop_xrender_surfaces (f);
x_clear_window (f);
/* We have to clear the scroll bars. If we have changed colors or
something like that, then they should be notified. */
x_scroll_bar_clear (f);
-#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS)
- /* Make sure scroll bars are redrawn. As they aren't redrawn by
- redisplay, do it here. */
- if (FRAME_GTK_WIDGET (f))
- gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
-#endif
-
XFlush (FRAME_X_DISPLAY (f));
unblock_input ();
@@ -4109,7 +4162,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,
@@ -7448,6 +7501,26 @@ x_net_wm_state (struct frame *f, Window window)
/** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/
}
+/* Flip back buffers on any frames with undrawn content. */
+static void
+flush_dirty_back_buffers (void)
+{
+ block_input ();
+ Lisp_Object tail, frame;
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+ if (FRAME_LIVE_P (f) &&
+ FRAME_X_P (f) &&
+ FRAME_X_WINDOW (f) &&
+ !FRAME_GARBAGED_P (f) &&
+ !buffer_flipping_blocked_p () &&
+ FRAME_X_NEED_BUFFER_FLIP (f))
+ show_back_buffer (f);
+ }
+ unblock_input ();
+}
+
/* Handles the XEvent EVENT on display DPYINFO.
*FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
@@ -7766,23 +7839,49 @@ handle_one_xevent (struct x_display_info *dpyinfo,
{
if (!FRAME_VISIBLE_P (f))
{
+ block_input ();
SET_FRAME_VISIBLE (f, 1);
SET_FRAME_ICONIFIED (f, false);
+ if (FRAME_X_DOUBLE_BUFFERED_P (f))
+ font_drop_xrender_surfaces (f);
f->output_data.x->has_been_visible = true;
SET_FRAME_GARBAGED (f);
+ unblock_input ();
}
- else
- {
+ else if (FRAME_GARBAGED_P (f))
+ {
#ifdef USE_GTK
- /* This seems to be needed for GTK 2.6 and later, see
- http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */
- x_clear_area (f,
- event->xexpose.x, event->xexpose.y,
- event->xexpose.width, event->xexpose.height);
+ /* Go around the back buffer and manually clear the
+ window the first time we show it. This way, we avoid
+ showing users the sanity-defying horror of whatever
+ GtkWindow is rendering beneath us. We've garbaged
+ the frame, so we'll redraw the whole thing on next
+ redisplay anyway. Yuck. */
+ x_clear_area1 (
+ FRAME_X_DISPLAY (f),
+ FRAME_X_WINDOW (f),
+ event->xexpose.x, event->xexpose.y,
+ event->xexpose.width, event->xexpose.height,
+ 0);
#endif
- expose_frame (f, event->xexpose.x, event->xexpose.y,
+ }
+
+
+ if (!FRAME_GARBAGED_P (f))
+ {
+#ifdef USE_GTK
+ /* This seems to be needed for GTK 2.6 and later, see
+ http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */
+ x_clear_area (f,
+ event->xexpose.x, event->xexpose.y,
+ event->xexpose.width, event->xexpose.height);
+#endif
+ expose_frame (f, event->xexpose.x, event->xexpose.y,
event->xexpose.width, event->xexpose.height);
- }
+ }
+
+ if (!FRAME_GARBAGED_P (f))
+ show_back_buffer (f);
}
else
{
@@ -7822,10 +7921,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
available. */
f = x_window_to_frame (dpyinfo, event->xgraphicsexpose.drawable);
if (f)
- expose_frame (f, event->xgraphicsexpose.x,
- event->xgraphicsexpose.y,
- event->xgraphicsexpose.width,
- event->xgraphicsexpose.height);
+ {
+ expose_frame (f, event->xgraphicsexpose.x,
+ event->xgraphicsexpose.y,
+ event->xgraphicsexpose.width,
+ event->xgraphicsexpose.height);
+ show_back_buffer (f);
+ }
#ifdef USE_X_TOOLKIT
else
goto OTHER;
@@ -8410,7 +8512,17 @@ handle_one_xevent (struct x_display_info *dpyinfo,
else
configureEvent = next_event;
}
+
f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window);
+ /* Unfortunately, we need to call font_drop_xrender_surfaces for
+ _all_ ConfigureNotify events, otherwise we miss some and
+ flicker. Don't try to optimize these calls by looking only
+ for size changes: that's not sufficient. We miss some
+ surface invalidations and flicker. */
+ block_input ();
+ if (f && FRAME_X_DOUBLE_BUFFERED_P (f))
+ font_drop_xrender_surfaces (f);
+ unblock_input ();
#ifdef USE_CAIRO
if (f) x_cr_destroy_surface (f);
#endif
@@ -8419,6 +8531,10 @@ handle_one_xevent (struct x_display_info *dpyinfo,
&& (f = any)
&& configureEvent.xconfigure.window == FRAME_X_WINDOW (f))
{
+ block_input ();
+ if (FRAME_X_DOUBLE_BUFFERED_P (f))
+ font_drop_xrender_surfaces (f);
+ unblock_input ();
xg_frame_resized (f, configureEvent.xconfigure.width,
configureEvent.xconfigure.height);
#ifdef USE_CAIRO
@@ -8429,7 +8545,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
#endif
if (f)
{
- x_net_wm_state (f, configureEvent.xconfigure.window);
+
+ x_net_wm_state (f, configureEvent.xconfigure.window);
#ifdef USE_X_TOOLKIT
/* Tip frames are pure X window, set size for them. */
@@ -8437,7 +8554,9 @@ 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);
+ {
+ SET_FRAME_GARBAGED (f);
+ }
FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height;
FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width;
}
@@ -8463,8 +8582,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);
- SET_FRAME_GARBAGED (f);
+ x_clear_under_internal_border (f);
+ SET_FRAME_GARBAGED (f);
cancel_mouse_face (f);
}
#endif /* not USE_GTK */
@@ -8688,6 +8807,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
count++;
}
+ /* Sometimes event processing draws to the frame outside redisplay.
+ To ensure that these changes become visible, draw them here. */
+ flush_dirty_back_buffers ();
SAFE_FREE ();
return count;
}
@@ -8880,7 +9002,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 +9059,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 +9080,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;
}
@@ -9028,11 +9150,6 @@ static void
x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
{
x_clear_area (f, x, y, width, height);
-#ifdef USE_GTK
- /* Must queue a redraw, because scroll bars might have been cleared. */
- if (FRAME_GTK_WIDGET (f))
- gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
-#endif
}
@@ -10889,9 +11006,9 @@ x_make_frame_visible (struct frame *f)
if (! FRAME_VISIBLE_P (f))
{
- /* We test FRAME_GARBAGED_P here to make sure we don't
- call x_set_offset a second time
- if we get to x_make_frame_visible a second time
+ /* We test asked_for_visible here to make sure we don't
+ call x_set_offset a second time
+ if we get to x_make_frame_visible a second time
before the window gets really visible. */
if (! FRAME_ICONIFIED_P (f)
&& ! FRAME_X_EMBEDDED_P (f)
@@ -10935,6 +11052,8 @@ x_make_frame_visible (struct frame *f)
will set it when they are handled. */
bool previously_visible = f->output_data.x->has_been_visible;
+ XSETFRAME (frame, f);
+
original_left = f->left_pos;
original_top = f->top_pos;
@@ -10981,8 +11100,6 @@ x_make_frame_visible (struct frame *f)
unblock_input ();
}
- XSETFRAME (frame, f);
-
/* Process X events until a MapNotify event has been seen. */
while (!FRAME_VISIBLE_P (f))
{
@@ -11227,6 +11344,7 @@ x_free_frame_resources (struct frame *f)
font-driver (e.g. xft) access a window while finishing a
face. */
free_frame_faces (f);
+ tear_down_x_back_buffer (f);
if (f->output_data.x->icon_desc)
XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc);
@@ -11258,7 +11376,7 @@ x_free_frame_resources (struct frame *f)
/* Tooltips don't have widgets, only a simple X window, even if
we are using a toolkit. */
else if (FRAME_X_WINDOW (f))
- XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
free_frame_menubar (f);
@@ -11270,8 +11388,9 @@ x_free_frame_resources (struct frame *f)
xg_free_frame_widgets (f);
#endif /* USE_GTK */
+ tear_down_x_back_buffer (f);
if (FRAME_X_WINDOW (f))
- XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
+ XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
#endif /* !USE_X_TOOLKIT */
unload_color (f, FRAME_FOREGROUND_PIXEL (f));
@@ -12111,7 +12230,15 @@ 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
{
@@ -12462,7 +12589,7 @@ static struct redisplay_interface x_redisplay_interface =
x_after_update_window_line,
x_update_window_begin,
x_update_window_end,
- x_flush,
+ x_flip_and_flush,
x_clear_window_mouse_face,
x_get_glyph_overhangs,
x_fix_overlapping_area,
@@ -12592,6 +12719,7 @@ 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;
+ terminal->buffer_flipping_unblocked_hook = XTbuffer_flipping_unblocked_hook;
terminal->mouse_position_hook = XTmouse_position;
terminal->frame_rehighlight_hook = XTframe_rehighlight;
terminal->frame_raise_lower_hook = XTframe_raise_lower;