Commit c2907158 authored by Daniel Colascione's avatar Daniel Colascione

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
parent f5543ffc
......@@ -3712,6 +3712,24 @@ fi
AC_SUBST(XFIXES_CFLAGS)
AC_SUBST(XFIXES_LIBS)
### Use Xdbe (-lXdbe) if available
HAVE_XDBE=no
if test "${HAVE_X11}" = "yes"; then
AC_CHECK_HEADER(X11/extensions/Xdbe.h,
[AC_CHECK_LIB(Xext, XdbeAllocateBackBufferName, HAVE_XDBE=yes)],
[],
[#include <X11/Xlib.h>
])
if test $HAVE_XDBE = yes; then
XDBE_LIBS=-lXext
fi
if test $HAVE_XDBE = yes; then
AC_DEFINE(HAVE_XDBE, 1, [Define to 1 if you have the Xdbe extension.])
fi
fi
AC_SUBST(XDBE_CFLAGS)
AC_SUBST(XDBE_LIBS)
### Use libxml (-lxml2) if available
### mingw32 doesn't use -lxml2, since it loads the library dynamically.
HAVE_LIBXML2=no
......
......@@ -1539,6 +1539,13 @@ prevent hanging with those window managers.
If non-@code{nil}, the frame is visible on all virtual desktops on systems
with virtual desktops.
@vindex inhibit-double-buffering, a frame parameter
@item inhibit-double-buffering
If non-@code{nil}, the frame is drawn to the screen without double buffering.
Emacs normally attempts to use double buffering, where available, to
reduce flicker. Set this property if you experience display bugs or
pine for that retro, flicker-y feeling.
@ignore
@vindex parent-id, a frame parameter
@item parent-id
......@@ -2210,6 +2217,12 @@ window manager. This happens below the level at which Emacs can exert
any control, but Emacs does provide events that you can use to keep
track of such changes. @xref{Misc Events}.
@defun x-double-buffered-p &optional frame
This function returns non-@code{nil} if @var{frame} is currently
being rendered with double buffering. @var{frame} defaults to the
selected frame.
@end defun
@node Raising and Lowering
@section Raising and Lowering Frames
......
......@@ -66,6 +66,12 @@ affected by this, as SGI stopped supporting IRIX in December 2013.
of curved quotes for 'electric-quote-mode', allowing user to choose
the types of quotes to be used.
+++
** Emacs now uses double buffering to reduce flicker when editing and
resizing graphical Emacs frames on the X Window System. This support
requires the DOUBLE-BUFFER extension, which major X servers have
supported for many years.
---
The group 'wp', whose label was "text", is now deprecated.
Use the new group 'text', which inherits from 'wp', instead.
......
......@@ -12,6 +12,7 @@
*
*/
#include <string.h>
#include "XMenuInt.h"
int
......
......@@ -13,6 +13,7 @@
*
*/
#include <string.h>
#include "XMenuInt.h"
int
......
......@@ -3,6 +3,7 @@
#include <config.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <errno.h>
#include "X10.h"
......
......@@ -254,6 +254,9 @@ XINERAMA_CFLAGS = @XINERAMA_CFLAGS@
XFIXES_LIBS = @XFIXES_LIBS@
XFIXES_CFLAGS = @XFIXES_CFLAGS@
XDBE_LIBS = @XDBE_LIBS@
XDBE_CFLAGS = @XDBE_CFLAGS@
## widget.o if USE_X_TOOLKIT, otherwise empty.
WIDGET_OBJ=@WIDGET_OBJ@
......@@ -372,7 +375,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
$(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
$(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
$(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \
$(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) \
$(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) $(XDBE_CFLAGS) \
$(WEBKIT_CFLAGS) \
$(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
......@@ -489,6 +492,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
$(WEBKIT_LIBS) \
$(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
$(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \
$(XDBE_LIBS) \
$(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
$(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
$(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
......
......@@ -1276,7 +1276,6 @@ struct glyph_string
/* X display and window for convenience. */
Display *display;
Window window;
/* The glyph row for which this string was built. It determines the
y-origin and height of the string. */
......@@ -3357,6 +3356,10 @@ void x_cr_init_fringe (struct redisplay_interface *);
extern unsigned row_hash (struct glyph_row *);
extern void block_buffer_flips(void);
extern void unblock_buffer_flips(void);
extern bool buffer_flipping_blocked_p(void);
/* Defined in image.c */
#ifdef HAVE_WINDOW_SYSTEM
......
......@@ -5274,6 +5274,16 @@ font_deferred_log (const char *action, Lisp_Object arg, Lisp_Object result)
ASET (Vfont_log_deferred, 2, result);
}
void
font_drop_xrender_surfaces (struct frame *f)
{
struct font_driver_list *list;
for (list = f->font_driver_list; list; list = list->next)
if (list->on && list->driver->drop_xrender_surfaces)
list->driver->drop_xrender_surfaces (f);
}
void
syms_of_font (void)
{
......
......@@ -763,6 +763,13 @@ struct font_driver
Return non-nil if the driver support rendering of combining
characters for FONT according to Unicode combining class. */
Lisp_Object (*combining_capability) (struct font *font);
/* Optional
Called when frame F is double-buffered and its size changes; Xft
relies on this hook to throw away its old XftDraw (which won't
work after the size change) and get a new one. */
void (*drop_xrender_surfaces) (struct frame *f);
};
......@@ -862,7 +869,9 @@ extern void *font_get_frame_data (struct frame *f, Lisp_Object);
extern void font_filter_properties (Lisp_Object font,
Lisp_Object alist,
const char *const boolean_properties[],
const char *const non_boolean_properties[]);
const char *const non_boolean_properties[]);
extern void font_drop_xrender_surfaces (struct frame *f);
#ifdef HAVE_FREETYPE
extern struct font_driver ftfont_driver;
......
......@@ -3128,6 +3128,7 @@ static const struct frame_parm_table frame_parms[] =
{"alpha", SYMBOL_INDEX (Qalpha)},
{"sticky", SYMBOL_INDEX (Qsticky)},
{"tool-bar-position", SYMBOL_INDEX (Qtool_bar_position)},
{"inhibit-double-buffering", SYMBOL_INDEX (Qinhibit_double_buffering)},
};
#ifdef HAVE_WINDOW_SYSTEM
......@@ -5044,6 +5045,7 @@ syms_of_frame (void)
DEFSYM (Qvertical_scroll_bars, "vertical-scroll-bars");
DEFSYM (Qvisibility, "visibility");
DEFSYM (Qwait_for_wm, "wait-for-wm");
DEFSYM (Qinhibit_double_buffering, "inhibit-double-buffering");
{
int i;
......
......@@ -95,7 +95,7 @@ ftxfont_get_gcs (struct frame *f, unsigned long foreground, unsigned long backgr
if (! x_alloc_nearest_color (f, FRAME_X_COLORMAP (f), &color))
break;
xgcv.foreground = color.pixel;
new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
new->gcs[i - 1] = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
GCForeground, &xgcv);
}
unblock_input ();
......@@ -139,14 +139,14 @@ ftxfont_draw_bitmap (struct frame *f, GC gc_fore, GC *gcs, struct font *font,
p[n[0]].y = y - bitmap.top + i;
if (++n[0] == size)
{
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
gc_fore, p, size, CoordModeOrigin);
n[0] = 0;
}
}
}
if (flush && n[0] > 0)
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
gc_fore, p, n[0], CoordModeOrigin);
}
else
......@@ -168,7 +168,7 @@ ftxfont_draw_bitmap (struct frame *f, GC gc_fore, GC *gcs, struct font *font,
pp[n[idx]].y = y - bitmap.top + i;
if (++(n[idx]) == size)
{
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
idx == 6 ? gc_fore : gcs[idx], pp, size,
CoordModeOrigin);
n[idx] = 0;
......@@ -180,10 +180,10 @@ ftxfont_draw_bitmap (struct frame *f, GC gc_fore, GC *gcs, struct font *font,
{
for (i = 0; i < 6; i++)
if (n[i] > 0)
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
gcs[i], p + 0x100 * i, n[i], CoordModeOrigin);
if (n[6] > 0)
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
XDrawPoints (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
gc_fore, p + 0x600, n[6], CoordModeOrigin);
}
}
......@@ -203,7 +203,7 @@ ftxfont_draw_background (struct frame *f, struct font *font, GC gc, int x, int y
XGetGCValues (FRAME_X_DISPLAY (f), gc,
GCForeground | GCBackground, &xgcv);
XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.background);
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), gc,
XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), gc,
x, y - FONT_BASE (font), width, FONT_HEIGHT (font));
XSetForeground (FRAME_X_DISPLAY (f), gc, xgcv.foreground);
}
......
......@@ -48,6 +48,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "emacsgtkfixed.h"
#endif
#ifdef HAVE_XDBE
#include <X11/extensions/Xdbe.h>
#endif
#ifndef HAVE_GTK_WIDGET_SET_HAS_WINDOW
#define gtk_widget_set_has_window(w, b) \
(gtk_fixed_set_has_window (GTK_FIXED (w), b))
......@@ -143,6 +147,8 @@ struct xg_frame_tb_info
GtkTextDirection dir;
};
static GtkWidget * xg_get_widget_from_map (ptrdiff_t idx);
/***********************************************************************
Display handling functions
......@@ -815,12 +821,6 @@ xg_clear_under_internal_border (struct frame *f)
{
if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0)
{
#ifndef USE_CAIRO
GtkWidget *wfixed = f->output_data.x->edit_widget;
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
#endif
x_clear_area (f, 0, 0,
FRAME_PIXEL_WIDTH (f), FRAME_INTERNAL_BORDER_WIDTH (f));
......@@ -1233,6 +1233,7 @@ xg_create_frame_widgets (struct frame *f)
by callers of this function. */
gtk_widget_realize (wfixed);
FRAME_X_WINDOW (f) = GTK_WIDGET_TO_X_WIN (wfixed);
initial_set_up_x_back_buffer (f);
/* Since GTK clears its window by filling with the background color,
we must keep X and GTK background in sync. */
......@@ -1296,8 +1297,11 @@ xg_free_frame_widgets (struct frame *f)
if (tbinfo)
xfree (tbinfo);
/* x_free_frame_resources should have taken care of it */
eassert (!FRAME_X_DOUBLE_BUFFERED_P (f));
gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
FRAME_X_WINDOW (f) = 0; /* Set to avoid XDestroyWindow in xterm.c */
FRAME_X_RAW_DRAWABLE (f) = 0;
FRAME_GTK_OUTER_WIDGET (f) = 0;
#ifdef USE_GTK_TOOLTIP
if (x->ttip_lbl)
......@@ -1440,6 +1444,18 @@ xg_set_background_color (struct frame *f, unsigned long bg)
{
block_input ();
xg_set_widget_bg (f, FRAME_GTK_WIDGET (f), FRAME_BACKGROUND_PIXEL (f));
Lisp_Object bar;
for (bar = FRAME_SCROLL_BARS (f);
!NILP (bar);
bar = XSCROLL_BAR (bar)->next)
{
GtkWidget *scrollbar =
xg_get_widget_from_map (XSCROLL_BAR (bar)->x_window);
GtkWidget *webox = gtk_widget_get_parent (scrollbar);
xg_set_widget_bg (f, webox, FRAME_BACKGROUND_PIXEL (f));
}
unblock_input ();
}
}
......@@ -2265,7 +2281,6 @@ xg_mark_data (void)
}
}
/* Callback called when a menu item is destroyed. Used to free data.
W is the widget that is being destroyed (not used).
CLIENT_DATA points to the xg_menu_item_cb_data associated with the W. */
......@@ -3569,44 +3584,23 @@ xg_gtk_scroll_destroy (GtkWidget *widget, gpointer data)
xg_remove_widget_from_map (id);
}
/* Create a scroll bar widget for frame F. Store the scroll bar
in BAR.
SCROLL_CALLBACK is the callback to invoke when the value of the
bar changes.
END_CALLBACK is the callback to invoke when scrolling ends.
SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
to set resources for the widget. */
void
xg_create_scroll_bar (struct frame *f,
struct scroll_bar *bar,
GCallback scroll_callback,
GCallback end_callback,
const char *scroll_bar_name)
static void
xg_finish_scroll_bar_creation (struct frame *f,
GtkWidget *wscroll,
struct scroll_bar *bar,
GCallback scroll_callback,
GCallback end_callback,
const char *scroll_bar_name)
{
GtkWidget *wscroll;
GtkWidget *webox;
intptr_t scroll_id;
#ifdef HAVE_GTK3
GtkAdjustment *vadj;
#else
GtkObject *vadj;
#endif
GtkWidget *webox = gtk_event_box_new ();
/* Page, step increment values are not so important here, they
will be corrected in x_set_toolkit_scroll_bar_thumb. */
vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
0.1, 0.1, 0.1);
wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj));
webox = gtk_event_box_new ();
gtk_widget_set_name (wscroll, scroll_bar_name);
#ifndef HAVE_GTK3
gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
#endif
g_object_set_data (G_OBJECT (wscroll), XG_FRAME_DATA, (gpointer)f);
scroll_id = xg_store_widget_in_map (wscroll);
ptrdiff_t scroll_id = xg_store_widget_in_map (wscroll);
g_signal_connect (G_OBJECT (wscroll),
"destroy",
......@@ -3630,11 +3624,52 @@ xg_create_scroll_bar (struct frame *f,
gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
gtk_container_add (GTK_CONTAINER (webox), wscroll);
xg_set_widget_bg (f, webox, FRAME_BACKGROUND_PIXEL (f));
/* N.B. The event box doesn't become a real X11 window until we ask
for its XID via GTK_WIDGET_TO_X_WIN. If the event box is not a
real X window, it and its scroll-bar child try to draw on the
Emacs main window, which we draw over using Xlib. */
gtk_widget_realize (webox);
GTK_WIDGET_TO_X_WIN (webox);
/* Set the cursor to an arrow. */
xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor);
bar->x_window = scroll_id;
}
/* Create a scroll bar widget for frame F. Store the scroll bar
in BAR.
SCROLL_CALLBACK is the callback to invoke when the value of the
bar changes.
END_CALLBACK is the callback to invoke when scrolling ends.
SCROLL_BAR_NAME is the name we use for the scroll bar. Can be used
to set resources for the widget. */
void
xg_create_scroll_bar (struct frame *f,
struct scroll_bar *bar,
GCallback scroll_callback,
GCallback end_callback,
const char *scroll_bar_name)
{
GtkWidget *wscroll;
#ifdef HAVE_GTK3
GtkAdjustment *vadj;
#else
GtkObject *vadj;
#endif
/* Page, step increment values are not so important here, they
will be corrected in x_set_toolkit_scroll_bar_thumb. */
vadj = gtk_adjustment_new (XG_SB_MIN, XG_SB_MIN, XG_SB_MAX,
0.1, 0.1, 0.1);
wscroll = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT (vadj));
xg_finish_scroll_bar_creation (f, wscroll, bar, scroll_callback,
end_callback, scroll_bar_name);
bar->horizontal = 0;
}
......@@ -3652,8 +3687,6 @@ xg_create_horizontal_scroll_bar (struct frame *f,
const char *scroll_bar_name)
{
GtkWidget *wscroll;
GtkWidget *webox;
intptr_t scroll_id;
#ifdef HAVE_GTK3
GtkAdjustment *hadj;
#else
......@@ -3666,42 +3699,9 @@ xg_create_horizontal_scroll_bar (struct frame *f,
0.1, 0.1, 0.1);
wscroll = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (hadj));
webox = gtk_event_box_new ();
gtk_widget_set_name (wscroll, scroll_bar_name);
#ifndef HAVE_GTK3
gtk_range_set_update_policy (GTK_RANGE (wscroll), GTK_UPDATE_CONTINUOUS);
#endif
g_object_set_data (G_OBJECT (wscroll), XG_FRAME_DATA, (gpointer)f);
scroll_id = xg_store_widget_in_map (wscroll);
g_signal_connect (G_OBJECT (wscroll),
"destroy",
G_CALLBACK (xg_gtk_scroll_destroy),
(gpointer) scroll_id);
g_signal_connect (G_OBJECT (wscroll),
"change-value",
scroll_callback,
(gpointer) bar);
g_signal_connect (G_OBJECT (wscroll),
"button-release-event",
end_callback,
(gpointer) bar);
/* The scroll bar widget does not draw on a window of its own. Instead
it draws on the parent window, in this case the edit widget. So
whenever the edit widget is cleared, the scroll bar needs to redraw
also, which causes flicker. Put an event box between the edit widget
and the scroll bar, so the scroll bar instead draws itself on the
event box window. */
gtk_fixed_put (GTK_FIXED (f->output_data.x->edit_widget), webox, -1, -1);
gtk_container_add (GTK_CONTAINER (webox), wscroll);
/* Set the cursor to an arrow. */
xg_set_cursor (webox, FRAME_DISPLAY_INFO (f)->xg_cursor);
bar->x_window = scroll_id;
xg_finish_scroll_bar_creation (f, wscroll, bar, scroll_callback,
end_callback, scroll_bar_name);
bar->horizontal = 1;
}
......@@ -3770,16 +3770,10 @@ xg_update_scrollbar_pos (struct frame *f,
gtk_widget_show_all (wparent);
gtk_widget_set_size_request (wscroll, width, height);
}
#ifndef USE_CAIRO
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
#endif
if (oldx != -1 && oldw > 0 && oldh > 0)
{
/* Clear under old scroll bar position. This must be done after
the gtk_widget_queue_draw and gdk_window_process_all_updates
above. */
oldw += (scale - 1) * oldw;
/* Clear under old scroll bar position. */
oldw += (scale - 1) * oldw;
oldx -= (scale - 1) * oldw;
x_clear_area (f, oldx, oldy, oldw, oldh);
}
......@@ -3841,14 +3835,9 @@ xg_update_horizontal_scrollbar_pos (struct frame *f,
gtk_widget_show_all (wparent);
gtk_widget_set_size_request (wscroll, width, height);
}
gtk_widget_queue_draw (wfixed);
gdk_window_process_all_updates ();
if (oldx != -1 && oldw > 0 && oldh > 0)
/* Clear under old scroll bar position. This must be done after
the gtk_widget_queue_draw and gdk_window_process_all_updates
above. */
x_clear_area (f,
oldx, oldy, oldw, oldh);
/* Clear under old scroll bar position. */
x_clear_area (f, oldx, oldy, oldw, oldh);
/* GTK does not redraw until the main loop is entered again, but
if there are no X events pending we will not enter it. So we sync
......
......@@ -220,7 +220,7 @@ x_create_bitmap_from_data (struct frame *f, char *bits, unsigned int width, unsi
#ifdef HAVE_X_WINDOWS
Pixmap bitmap;
bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
bitmap = XCreateBitmapFromData (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
bits, width, height);
if (! bitmap)
return -1;
......@@ -327,7 +327,7 @@ x_create_bitmap_from_file (struct frame *f, Lisp_Object file)
filename = SSDATA (found);
result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
result = XReadBitmapFile (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
filename, &width, &height, &bitmap, &xhot, &yhot);
if (result != BitmapSuccess)
return -1;
......@@ -1952,7 +1952,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
{
#ifdef HAVE_X_WINDOWS
Display *display = FRAME_X_DISPLAY (f);
Window window = FRAME_X_WINDOW (f);
Drawable drawable = FRAME_X_DRAWABLE (f);
Screen *screen = FRAME_X_SCREEN (f);
eassert (input_blocked_p ());
......@@ -1981,7 +1981,7 @@ x_create_x_image_and_pixmap (struct frame *f, int width, int height, int depth,
(*ximg)->data = xmalloc ((*ximg)->bytes_per_line * height);
/* Allocate a pixmap of the same size. */
*pixmap = XCreatePixmap (display, window, width, height, depth);
*pixmap = XCreatePixmap (display, drawable, width, height, depth);
if (*pixmap == NO_PIXMAP)
{
x_destroy_x_image (*ximg);
......@@ -2742,7 +2742,7 @@ Create_Pixmap_From_Bitmap_Data (struct frame *f, struct image *img, char *data,
img->pixmap =
(x_check_image_size (0, img->width, img->height)
? XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
FRAME_X_WINDOW (f),
FRAME_X_DRAWABLE (f),
data,
img->width, img->height,
fg, bg,
......@@ -3520,7 +3520,7 @@ x_create_bitmap_from_xpm_data (struct frame *f, const char **bits)
xpm_init_color_cache (f, &attrs);
#endif
rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
rc = XpmCreatePixmapFromData (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
(char **) bits, &bitmap, &mask, &attrs);
if (rc != XpmSuccess)
{
......@@ -3758,7 +3758,7 @@ xpm_load (struct frame *f, struct image *img)
#ifdef HAVE_X_WINDOWS
if (rc == XpmSuccess)
{
img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
img->ximg->width, img->ximg->height,
img->ximg->depth);
if (img->pixmap == NO_PIXMAP)
......@@ -3768,7 +3768,7 @@ xpm_load (struct frame *f, struct image *img)
}
else if (img->mask_img)
{
img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
img->mask = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
img->mask_img->width,
img->mask_img->height,
img->mask_img->depth);
......@@ -9541,7 +9541,7 @@ gs_load (struct frame *f, struct image *img)
{
/* Only W32 version did BLOCK_INPUT here. ++kfs */
block_input ();
img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
img->pixmap = XCreatePixmap (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
img->width, img->height,
DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
unblock_input ();
......@@ -9557,7 +9557,7 @@ gs_load (struct frame *f, struct image *img)
if successful. We do not record_unwind_protect here because
other places in redisplay like calling window scroll functions
don't either. Let the Lisp loader use `unwind-protect' instead. */
printnum1 = FRAME_X_WINDOW (f);
printnum1 = FRAME_X_DRAWABLE (f);
printnum2 = img->pixmap;
window_and_pixmap_id
= make_formatted_string (buffer, "%"pMu" %"pMu, printnum1, printnum2);
......
......@@ -971,6 +971,7 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side
x_set_alpha,
0, /* x_set_sticky */
0, /* x_set_tool_bar_position */
0, /* x_set_inhibit_double_buffering */
};
......
......@@ -631,6 +631,11 @@ struct terminal
/* Called when a frame's display becomes entirely up to date. */
void (*frame_up_to_date_hook) (struct frame *);
/* Called when buffer flipping becomes unblocked after having
previously been blocked. Redisplay always blocks buffer flips
while it runs. */
void (*buffer_flipping_unblocked_hook) (struct frame *);
/* Called to delete the device-specific portions of a frame that is
on this terminal device. */
......
......@@ -9757,6 +9757,7 @@ frame_parm_handler w32_frame_parm_handlers[] =
x_set_alpha,
0, /* x_set_sticky */
0, /* x_set_tool_bar_position */
0, /* x_set_inhibit_double_buffering */
};
void
......
......@@ -2501,7 +2501,7 @@ remember_mouse_glyph (struct frame *f, int gx, int gy, NativeRectangle *rect)
/* Visible feedback for debugging. */
#if false && defined HAVE_X_WINDOWS
XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f),
f->output_data.x->normal_gc,
gx, gy, width, height);
#endif
......@@ -11349,7 +11349,7 @@ clear_garbaged_frames (void)
fset_redisplay (f);
f->garbaged = false;
f->resized_p = false;
}
}
}
frame_garbaged = false;
......@@ -13573,6 +13573,7 @@ redisplay_internal (void)
count = SPECPDL_INDEX ();
record_unwind_protect_void (unwind_redisplay);
redisplaying_p = true;
block_buffer_flips ();
specbind (Qinhibit_free_realized_faces, Qnil);