diff --git a/configure.ac b/configure.ac index 2ad5f2312c1..6f469cf0f04 100644 --- a/configure.ac +++ b/configure.ac @@ -4490,6 +4490,22 @@ fi AC_SUBST(XINPUT_CFLAGS) AC_SUBST(XINPUT_LIBS) +XSYNC_LIBS= +XSYNC_CFLAGS= +HAVE_XSYNC=no +if test "${HAVE_X11}" = "yes"; then + AC_CHECK_HEADER(X11/extensions/sync.h, + AC_CHECK_LIB(Xext, XSyncQueryExtension, HAVE_XSYNC=yes), + [], [#include ]) + + if test "${HAVE_XSYNC}" = "yes"; then + AC_DEFINE(HAVE_XSYNC, 1, [Define to 1 if the X Synchronization Extension is available.]) + XSYNC_LIBS="-lXext" + fi +fi +AC_SUBST(XSYNC_LIBS) +AC_SUBST(XSYNC_CFLAGS) + ### Use Xdbe (-lXdbe) if available HAVE_XDBE=no if test "${HAVE_X11}" = "yes"; then diff --git a/src/Makefile.in b/src/Makefile.in index 706beb453b6..186e06735cc 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -264,6 +264,9 @@ XFIXES_CFLAGS = @XFIXES_CFLAGS@ XINPUT_LIBS = @XINPUT_LIBS@ XINPUT_CFLAGS = @XINPUT_CFLAGS@ +XSYNC_LIBS = @XSYNC_LIBS@ +XSYNC_CFLAGS = @XSYNC_CFLAGS@ + XDBE_LIBS = @XDBE_LIBS@ XDBE_CFLAGS = @XDBE_CFLAGS@ @@ -396,7 +399,7 @@ EMACS_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \ $(XINPUT_CFLAGS) $(WEBP_CFLAGS) $(WEBKIT_CFLAGS) $(LCMS2_CFLAGS) \ $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ $(HARFBUZZ_CFLAGS) $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \ - $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) \ + $(LIBSYSTEMD_CFLAGS) $(JSON_CFLAGS) $(XSYNC_CFLAGS) \ $(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \ $(WERROR_CFLAGS) $(HAIKU_CFLAGS) ALL_CFLAGS = $(EMACS_CFLAGS) $(WARN_CFLAGS) $(CFLAGS) @@ -548,7 +551,7 @@ LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(PGTK_LIBS) $(LIBX_BASE) $(LIBIMAGE $(WEBKIT_LIBS) \ $(LIB_EACCESS) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \ - $(XDBE_LIBS) \ + $(XDBE_LIBS) $(XSYNC_LIBS) \ $(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \ $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(HARFBUZZ_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ diff --git a/src/xfns.c b/src/xfns.c index 4719c5dac7d..bfb61c1205e 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -2367,6 +2367,9 @@ append_wm_protocols (struct x_display_info *dpyinfo, Atom protos[10]; int num_protos = 0; bool found_wm_ping = false; +#if !defined HAVE_GTK3 && defined HAVE_XSYNC + bool found_wm_sync_request = false; +#endif unsigned long bytes_after; block_input (); @@ -2385,6 +2388,11 @@ append_wm_protocols (struct x_display_info *dpyinfo, if (existing_protocols[nitems] == dpyinfo->Xatom_net_wm_ping) found_wm_ping = true; +#if !defined HAVE_GTK3 && defined HAVE_XSYNC + else if (existing_protocols[nitems] + == dpyinfo->Xatom_net_wm_sync_request) + found_wm_sync_request = true; +#endif } } @@ -2393,6 +2401,10 @@ append_wm_protocols (struct x_display_info *dpyinfo, if (!found_wm_ping) protos[num_protos++] = dpyinfo->Xatom_net_wm_ping; +#if !defined HAVE_GTK3 && defined HAVE_XSYNC + if (!found_wm_sync_request) + protos[num_protos++] = dpyinfo->Xatom_net_wm_sync_request; +#endif if (num_protos) XChangeProperty (dpyinfo->display, @@ -3842,7 +3854,6 @@ x_window (struct frame *f) FRAME_X_VISUAL (f), attribute_mask, &attributes); initial_set_up_x_back_buffer (f); - append_wm_protocols (FRAME_DISPLAY_INFO (f), f); #ifdef HAVE_X_I18N if (use_xim) @@ -3891,6 +3902,8 @@ x_window (struct frame *f) XSetWMProtocols (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), protocols, 2); } + append_wm_protocols (FRAME_DISPLAY_INFO (f), f); + /* x_set_name normally ignores requests to set the name if the requested name is the same as the current name. This is the one place where that assumption isn't correct; f->name is set, but @@ -4795,6 +4808,24 @@ This function is an internal primitive--use `make-frame' instead. */) (unsigned char *) &dpyinfo->client_leader_window, 1); } +#ifdef HAVE_XSYNC + if (dpyinfo->xsync_supported_p) + { +#ifndef HAVE_GTK3 + XSyncValue initial_value; + + XSyncIntToValue (&initial_value, 0); + FRAME_X_BASIC_COUNTER (f) = XSyncCreateCounter (FRAME_X_DISPLAY (f), + initial_value); + + XChangeProperty (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), + dpyinfo->Xatom_net_wm_sync_request_counter, + XA_CARDINAL, 32, PropModeReplace, + (unsigned char *) &FRAME_X_BASIC_COUNTER (f), 1); +#endif + } +#endif + unblock_input (); /* Works iff frame has been already mapped. */ diff --git a/src/xterm.c b/src/xterm.c index 34a85aa7456..4b4eae53be5 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -122,6 +122,10 @@ along with GNU Emacs. If not, see . */ #include #endif +#ifdef HAVE_XSYNC +#include +#endif + /* Load sys/types.h if not already loaded. In some systems loading it twice is suicidal. */ #ifndef makedev @@ -1849,6 +1853,17 @@ XTframe_up_to_date (struct frame *f) FRAME_MOUSE_UPDATE (f); if (!buffer_flipping_blocked_p () && FRAME_X_NEED_BUFFER_FLIP (f)) show_back_buffer (f); + +#ifdef HAVE_XSYNC + if (FRAME_X_OUTPUT (f)->sync_end_pending_p + && FRAME_X_BASIC_COUNTER (f)) + { + XSyncSetCounter (FRAME_X_DISPLAY (f), + FRAME_X_BASIC_COUNTER (f), + FRAME_X_OUTPUT (f)->pending_basic_counter_value); + FRAME_X_OUTPUT (f)->sync_end_pending_p = false; + } +#endif unblock_input (); } @@ -9086,6 +9101,26 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto done; } +#if defined HAVE_XSYNC && !defined HAVE_GTK3 + if (event->xclient.data.l[0] == dpyinfo->Xatom_net_wm_sync_request + && event->xclient.format == 32) + { + struct frame *f + = x_top_window_to_frame (dpyinfo, + event->xclient.window); + + if (f) + { + XSyncIntsToValue (&FRAME_X_OUTPUT (f)->pending_basic_counter_value, + event->xclient.data.l[2], event->xclient.data.l[3]); + FRAME_X_OUTPUT (f)->sync_end_pending_p = true; + + *finish = X_EVENT_DROP; + goto done; + } + } +#endif + goto done; } @@ -14745,9 +14780,15 @@ x_free_frame_resources (struct frame *f) 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 */ +#ifdef HAVE_XSYNC + if (FRAME_X_BASIC_COUNTER (f)) + XSyncDestroyCounter (FRAME_X_DISPLAY (f), + FRAME_X_BASIC_COUNTER (f)); +#endif + unload_color (f, FRAME_FOREGROUND_PIXEL (f)); unload_color (f, FRAME_BACKGROUND_PIXEL (f)); unload_color (f, f->output_data.x->cursor_pixel); @@ -15628,6 +15669,19 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) } #endif +#ifdef HAVE_XSYNC + int xsync_event_base, xsync_error_base; + dpyinfo->xsync_supported_p + = XSyncQueryExtension (dpyinfo->display, + &xsync_event_base, + &xsync_error_base); + + if (dpyinfo->xsync_supported_p) + dpyinfo->xsync_supported_p = XSyncInitialize (dpyinfo->display, + &dpyinfo->xsync_major, + &dpyinfo->xsync_minor); +#endif + /* See if a private colormap is requested. */ if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen)) { @@ -15887,6 +15941,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) ATOM_REFS_INIT ("ATOM", Xatom_ATOM) ATOM_REFS_INIT ("ATOM_PAIR", Xatom_ATOM_PAIR) ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER) + ATOM_REFS_INIT ("XATOM_COUNTER", Xatom_XEMBED_INFO) ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO) /* For properties of font. */ ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE) @@ -15921,6 +15976,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) ATOM_REFS_INIT ("_NET_FRAME_EXTENTS", Xatom_net_frame_extents) ATOM_REFS_INIT ("_NET_CURRENT_DESKTOP", Xatom_net_current_desktop) ATOM_REFS_INIT ("_NET_WORKAREA", Xatom_net_workarea) + ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request) + ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter) /* Session management */ ATOM_REFS_INIT ("SM_CLIENT_ID", Xatom_SM_CLIENT_ID) ATOM_REFS_INIT ("_XSETTINGS_SETTINGS", Xatom_xsettings_prop) diff --git a/src/xterm.h b/src/xterm.h index 99d339e1f94..25ea257b518 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -99,6 +99,10 @@ typedef GtkWidget *xt_or_gtk_widget; #include #endif +#ifdef HAVE_XSYNC +#include +#endif + #include "dispextern.h" #include "termhooks.h" @@ -366,9 +370,9 @@ struct x_display_info /* More atoms, which are selection types. */ Atom Xatom_CLIPBOARD, Xatom_TIMESTAMP, Xatom_TEXT, Xatom_DELETE, - Xatom_COMPOUND_TEXT, Xatom_UTF8_STRING, - Xatom_MULTIPLE, Xatom_INCR, Xatom_EMACS_TMP, Xatom_TARGETS, Xatom_NULL, - Xatom_ATOM, Xatom_ATOM_PAIR, Xatom_CLIPBOARD_MANAGER; + Xatom_COMPOUND_TEXT, Xatom_UTF8_STRING, + Xatom_MULTIPLE, Xatom_INCR, Xatom_EMACS_TMP, Xatom_TARGETS, Xatom_NULL, + Xatom_ATOM, Xatom_ATOM_PAIR, Xatom_CLIPBOARD_MANAGER, Xatom_COUNTER; /* More atoms for font properties. The last three are private properties, see the comments in src/fontset.h. */ @@ -498,7 +502,8 @@ struct x_display_info Xatom_net_wm_state_sticky, Xatom_net_wm_state_above, Xatom_net_wm_state_below, Xatom_net_wm_state_hidden, Xatom_net_wm_state_skip_taskbar, Xatom_net_frame_extents, Xatom_net_current_desktop, Xatom_net_workarea, - Xatom_net_wm_opaque_region, Xatom_net_wm_ping; + Xatom_net_wm_opaque_region, Xatom_net_wm_ping, Xatom_net_wm_sync_request, + Xatom_net_wm_sync_request_counter; /* XSettings atoms and windows. */ Atom Xatom_xsettings_sel, Xatom_xsettings_prop, Xatom_xsettings_mgr; @@ -565,6 +570,12 @@ struct x_display_info int xfixes_major; int xfixes_minor; #endif + +#ifdef HAVE_XSYNC + bool xsync_supported_p; + int xsync_major; + int xsync_minor; +#endif }; #ifdef HAVE_X_I18N @@ -801,6 +812,13 @@ struct x_output XFontSet xic_xfs; #endif +#ifdef HAVE_XSYNC + XSyncCounter basic_frame_counter; + XSyncValue pending_basic_counter_value; + + bool_bf sync_end_pending_p; +#endif + /* Relief GCs, colors etc. */ struct relief { @@ -963,6 +981,9 @@ extern void x_mark_frame_dirty (struct frame *f); || (FRAME_DISPLAY_INFO (f)->xrender_major > (major)))) #endif +#ifdef HAVE_XSYNC +#define FRAME_X_BASIC_COUNTER(f) FRAME_X_OUTPUT (f)->basic_frame_counter +#endif /* This is the Colormap which frame F uses. */ #define FRAME_X_COLORMAP(f) FRAME_DISPLAY_INFO (f)->cmap