]> git.eshelyaron.com Git - emacs.git/commitdiff
Add support for basic syncing with the window manager on resize
authorPo Lu <luangruo@yahoo.com>
Sat, 5 Feb 2022 13:43:00 +0000 (21:43 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 5 Feb 2022 13:43:00 +0000 (21:43 +0800)
This is handled by GTK 3, so the code is disabled on that
specific build.  On other builds, this eliminates any unexposed
part of a frame from showing up after a resize when
`frame-resize-pixelwise' is t.

* configure.ac: Check for the X Synchronization Extension if
present.
* src/Makefile.in (EMACS_CFLAGS):
(LIBES): Add XSYNC_LIBS and XSYNC_CFLAGS.

* src/xfns.c (append_wm_protocols): Declare
`_NET_WM_SYNC_REQUEST' support if appropriate.
(x_window): Adjust location of call to `append_wm_protocols' on
Xt version to prevent it from being overwritten.
(Fx_create_frame): Create basic counter.
* src/xterm.c (XTframe_up_to_date): Set counter value to the one
asked for by the window manager.
(handle_one_xevent): Handle _NET_WM_SYNC_REQUEST.
(x_free_frame_resources): Free frame counter if present.
(x_term_init): Test for XSync and set fields accordingly.
* src/xterm.h (struct x_display_info): New fields for XSync
support and new atoms.
(struct x_output): New fields for counter status.
(FRAME_X_BASIC_COUNTER): New macro.

configure.ac
src/Makefile.in
src/xfns.c
src/xterm.c
src/xterm.h

index 2ad5f2312c13c152da8cb3a8031f2ce623514915..6f469cf0f0407313a268f631329665922b3f28b5 100644 (file)
@@ -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 <X11/Xlib.h>])
+
+  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
index 706beb453b6d44ef3cf5eb0cafff54bb92c680f1..186e06735cc25eef00c312b1e941f1784b2a74d8 100644 (file)
@@ -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) \
index 4719c5dac7d96f9194a697bb64c47b468ae5ddd9..bfb61c1205ec0be5b19ba6cd581d01b5ef5027fa 100644 (file)
@@ -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.  */
index 34a85aa7456377a8d733aae9b18857e1d8dbe0b8..4b4eae53be5b475246cd6c42c2b9d2cf5336374e 100644 (file)
@@ -122,6 +122,10 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <X11/extensions/Xrandr.h>
 #endif
 
+#ifdef HAVE_XSYNC
+#include <X11/extensions/sync.h>
+#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)
index 99d339e1f94f2e522dbfa3394fd05dc53a3d89b9..25ea257b518d3243ec1d3d81bac5d088e4b92a9d 100644 (file)
@@ -99,6 +99,10 @@ typedef GtkWidget *xt_or_gtk_widget;
 #include <X11/XKBlib.h>
 #endif
 
+#ifdef HAVE_XSYNC
+#include <X11/extensions/sync.h>
+#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