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/xterm.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/xterm.c')
-rw-r--r-- | src/xterm.c | 288 |
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; |