emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master abf683bb03: Fix pieces of code being too expensive over slow netw


From: Po Lu
Subject: master abf683bb03: Fix pieces of code being too expensive over slow network connections
Date: Mon, 17 Oct 2022 09:00:21 -0400 (EDT)

branch: master
commit abf683bb0324b9c5d01adb90aedb6aa6fa7175e9
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix pieces of code being too expensive over slow network connections
    
    * lisp/menu-bar.el (menu-bar-edit-menu): Test buffer-read-only
    before gui-backend-selection-exists-p.  This places the less
    expensive condition before the more expensive one.
    * src/xfns.c (compute_tip_xy): Use cached monitor attributes
    whenever available.
    (Fx_show_tip): Remove code that really did nothing.
    (Fx_backspace_delete_keys_p): Do not download the entire keymap
    from the server upon creating a frame.
    * src/xmenu.c (create_and_show_popup_menu): Use
    x_translate_coordinates_to_root.
    (x_menu_show): Use x_translate_coordinates_to_root.
    * src/xselect.c (Fx_selection_exists_p): If a temporary
    selection owner can be found, use it.
    * src/xterm.c (x_translate_coordinates_to_root)
    (x_handle_selection_monitor_event, x_find_selection_owner): New
    functions.  These functions try to avoid downloading data from
    the X server in places that are called very often (i.e. during
    tool bar updates.)
    (handle_one_xevent): Handle selection notify events.  Also catch
    some mistakes found.  Fetch all kinds of key names as well.
    (x_create_special_window): New function.
    (x_term_init, x_delete_display): Ask for all key names.  Also,
    passively monitor selections that are given to
    `x-selection-exists-p' during redisplay, so we do not have to
    ask the server about them upon each redisplay.
    (syms_of_xterm): New variable `x-fast-selection-list'.
    * src/xterm.h (struct x_monitored_selection): New structure.
    (X_INVALID_WINDOW): New define.
    (struct x_display_info): New fields for selection monitoring.
    Also, record the fixes extension base.
---
 lisp/menu-bar.el |   6 +-
 src/xfns.c       | 115 +++++++++----------------
 src/xmenu.c      |  45 ++--------
 src/xselect.c    |  25 +++++-
 src/xterm.c      | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++++---
 src/xterm.h      |  34 ++++++++
 6 files changed, 348 insertions(+), 132 deletions(-)

diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el
index c2c18320b1..526bccbbac 100644
--- a/lisp/menu-bar.el
+++ b/lisp/menu-bar.el
@@ -527,12 +527,12 @@
       `(menu-item "Paste" yank
                   :enable (funcall
                            ',(lambda ()
-                               (and (or
+                               (and (not buffer-read-only)
+                                    (or
                                      (gui-backend-selection-exists-p 
'CLIPBOARD)
                                      (if (featurep 'ns) ; like paste-from-menu
                                          (cdr yank-menu)
-                                       kill-ring))
-                                    (not buffer-read-only))))
+                                       kill-ring)))))
                   :help "Paste (yank) text most recently cut/copied"
                   :keys ,(lambda ()
                            (if cua-mode
diff --git a/src/xfns.c b/src/xfns.c
index 9112448899..e8732986eb 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -8443,7 +8443,17 @@ compute_tip_xy (struct frame *f, Lisp_Object parms, 
Lisp_Object dx,
       unblock_input ();
 
       XSETFRAME (frame, f);
-      attributes = Fx_display_monitor_attributes_list (frame);
+
+#if defined HAVE_XRANDR || defined USE_GTK
+      if (!NILP (FRAME_DISPLAY_INFO (f)->last_monitor_attributes_list))
+       /* Use cached values if available to avoid fetching the
+          monitor list from the X server.  If XRandR is not
+          available, then fetching the attributes will probably not
+          sync anyway, and will thus be relatively harmless.  */
+       attributes = FRAME_DISPLAY_INFO (f)->last_monitor_attributes_list;
+      else
+#endif
+       attributes = Fx_display_monitor_attributes_list (frame);
 
       /* Try to determine the monitor where the mouse pointer is and
          its geometry.  See bug#22549.  */
@@ -8693,9 +8703,6 @@ Text larger than the specified size is clipped.  */)
   int old_windows_or_buffers_changed = windows_or_buffers_changed;
   specpdl_ref count = SPECPDL_INDEX ();
   Lisp_Object window, size, tip_buf;
-  Window child;
-  XWindowAttributes child_attrs;
-  int dest_x_return, dest_y_return;
   bool displayed;
 #ifdef ENABLE_CHECKING
   struct glyph_row *row, *end;
@@ -8946,41 +8953,6 @@ Text larger than the specified size is clipped.  */)
 
   /* Show tooltip frame.  */
   block_input ();
-  /* If the display is composited, then WM_TRANSIENT_FOR must be set
-     as well, or else the compositing manager won't display
-     decorations correctly, even though the tooltip window is override
-     redirect. See
-     https://specifications.freedesktop.org/wm-spec/1.4/ar01s08.html
-
-     Perhaps WM_TRANSIENT_FOR should be used in place of
-     override-redirect anyway.  The ICCCM only recommends
-     override-redirect if the pointer will be grabbed.  */
-
-  if (XTranslateCoordinates (FRAME_X_DISPLAY (f),
-                            FRAME_DISPLAY_INFO (f)->root_window,
-                            FRAME_DISPLAY_INFO (f)->root_window,
-                            root_x, root_y, &dest_x_return,
-                            &dest_y_return, &child)
-      && child != None)
-    {
-      /* But only if the child is not override-redirect, which can
-        happen if the pointer is above a menu.  */
-
-      if (XGetWindowAttributes (FRAME_X_DISPLAY (f),
-                               child, &child_attrs)
-         || child_attrs.override_redirect)
-       XDeleteProperty (FRAME_X_DISPLAY (tip_f),
-                        FRAME_X_WINDOW (tip_f),
-                        FRAME_DISPLAY_INFO (tip_f)->Xatom_wm_transient_for);
-      else
-       XSetTransientForHint (FRAME_X_DISPLAY (tip_f),
-                             FRAME_X_WINDOW (tip_f), child);
-    }
-  else
-    XDeleteProperty (FRAME_X_DISPLAY (tip_f),
-                    FRAME_X_WINDOW (tip_f),
-                    FRAME_DISPLAY_INFO (tip_f)->Xatom_wm_transient_for);
-
 #ifndef USE_XCB
   XMoveResizeWindow (FRAME_X_DISPLAY (tip_f), FRAME_X_WINDOW (tip_f),
                     root_x, root_y, width, height);
@@ -9452,13 +9424,21 @@ usual X keysyms.  Value is `lambda' if we cannot 
determine if both keys are
 present and mapped to the usual X keysyms.  */)
   (Lisp_Object frame)
 {
+#ifdef HAVE_XKB
+  XkbDescPtr kb;
+  struct frame *f;
+  Display *dpy;
+  Lisp_Object have_keys;
+  int delete_keycode, backspace_keycode, i;
+#endif
+
 #ifndef HAVE_XKB
   return Qlambda;
 #else
-  XkbDescPtr kb;
-  struct frame *f = decode_window_system_frame (frame);
-  Display *dpy = FRAME_X_DISPLAY (f);
-  Lisp_Object have_keys;
+  delete_keycode = 0;
+  backspace_keycode = 0;
+  f = decode_window_system_frame (frame);
+  dpy = FRAME_X_DISPLAY (f);
 
   if (!FRAME_DISPLAY_INFO (f)->supports_xkb)
     return Qlambda;
@@ -9474,50 +9454,39 @@ present and mapped to the usual X keysyms.  */)
      XK_Delete are mapped to any key.  But if any of those are mapped to
      some non-intuitive key combination (Meta-Shift-Ctrl-whatever) and the
      user doesn't know about it, it is better to return false here.
-     It is more obvious to the user what to do if she/he has two keys
+     It is more obvious to the user what to do if there are two keys
      clearly marked with names/symbols and one key does something not
-     expected (i.e. she/he then tries the other).
+     expected (and the user then tries the other).
      The cases where Backspace/Delete is mapped to some other key combination
      are rare, and in those cases, normal-erase-is-backspace can be turned on
      manually.  */
 
   have_keys = Qnil;
-  kb = XkbGetMap (dpy, XkbAllMapComponentsMask, XkbUseCoreKbd);
-  if (kb)
+  kb = FRAME_DISPLAY_INFO (f)->xkb_desc;
+  if (kb && kb->names)
     {
-      int delete_keycode = 0, backspace_keycode = 0, i;
-
-      if (XkbGetNames (dpy, XkbAllNamesMask, kb) == Success)
+      for (i = kb->min_key_code; (i < kb->max_key_code
+                                 && (delete_keycode == 0
+                                     || backspace_keycode == 0));
+          ++i)
        {
-         for (i = kb->min_key_code;
-              (i < kb->max_key_code
-               && (delete_keycode == 0 || backspace_keycode == 0));
-              ++i)
-           {
-             /* The XKB symbolic key names can be seen most easily in
-                the PS file generated by `xkbprint -label name
-                $DISPLAY'.  */
-             if (memcmp ("DELE", kb->names->keys[i].name, 4) == 0)
-               delete_keycode = i;
-             else if (memcmp ("BKSP", kb->names->keys[i].name, 4) == 0)
-               backspace_keycode = i;
-           }
-
-         XkbFreeNames (kb, 0, True);
+         /* The XKB symbolic key names can be seen most easily in
+            the PS file generated by `xkbprint -label name
+            $DISPLAY'.  */
+         if (!memcmp ("DELE", kb->names->keys[i].name, 4))
+           delete_keycode = i;
+         else if (!memcmp ("BKSP", kb->names->keys[i].name, 4))
+           backspace_keycode = i;
        }
 
-      /* As of libX11-1.6.2, XkbGetMap manual says that you should use
-        XkbFreeClientMap to free the data returned by XkbGetMap.  But
-        this function just frees the data referenced from KB and not
-        KB itself.  To free KB as well, call XkbFreeKeyboard.  */
-      XkbFreeKeyboard (kb, XkbAllMapComponentsMask, True);
-
-      if (delete_keycode
-         && backspace_keycode
+      if (delete_keycode && backspace_keycode
          && XKeysymToKeycode (dpy, XK_Delete) == delete_keycode
          && XKeysymToKeycode (dpy, XK_BackSpace) == backspace_keycode)
        have_keys = Qt;
     }
+  else
+    /* The keyboard names couldn't be obtained for some reason.  */
+    have_keys = Qlambda;
   unblock_input ();
   return have_keys;
 #endif
diff --git a/src/xmenu.c b/src/xmenu.c
index 1452b3c6d1..9d35e3529f 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1521,26 +1521,15 @@ create_and_show_popup_menu (struct frame *f, 
widget_value *first_wv,
 
   if (use_pos_func)
     {
-      Window dummy_window;
-
       /* Not invoked by a click.  pop up at x/y.  */
       pos_func = menu_position_func;
 
       /* Adjust coordinates to be root-window-relative.  */
       block_input ();
-      XTranslateCoordinates (FRAME_X_DISPLAY (f),
-
-                             /* From-window, to-window.  */
-                             FRAME_X_WINDOW (f),
-                             FRAME_DISPLAY_INFO (f)->root_window,
-
-                             /* From-position, to-position.  */
-                             x, y, &x, &y,
-
-                             /* Child of win.  */
-                             &dummy_window);
+      x_translate_coordinates_to_root (f, x, y, &x, &y);
 #ifdef HAVE_GTK3
-      /* Use window scaling factor to adjust position for hidpi screens. */
+      /* Use window scaling factor to adjust position for scaled
+        outputs.  */
       x /= xg_get_scale (f);
       y /= xg_get_scale (f);
 #endif
@@ -1743,7 +1732,6 @@ create_and_show_popup_menu (struct frame *f, widget_value 
*first_wv,
   XButtonPressedEvent *event = &(dummy.xbutton);
   LWLIB_ID menu_id;
   Widget menu;
-  Window dummy_window;
 #if defined HAVE_XINPUT2 && defined USE_MOTIF
   XEvent property_dummy;
   Atom property_atom;
@@ -1775,17 +1763,7 @@ create_and_show_popup_menu (struct frame *f, 
widget_value *first_wv,
   /* Adjust coordinates to be root-window-relative.  */
   block_input ();
   x += FRAME_LEFT_SCROLL_BAR_AREA_WIDTH (f);
-  XTranslateCoordinates (FRAME_X_DISPLAY (f),
-
-                         /* From-window, to-window.  */
-                         FRAME_X_WINDOW (f),
-                         FRAME_DISPLAY_INFO (f)->root_window,
-
-                         /* From-position, to-position.  */
-                         x, y, &x, &y,
-
-                         /* Child of win.  */
-                         &dummy_window);
+  x_translate_coordinates_to_root (f, x, y, &x, &y);
   unblock_input ();
 
   event->x_root = x;
@@ -2569,9 +2547,6 @@ Lisp_Object
 x_menu_show (struct frame *f, int x, int y, int menuflags,
             Lisp_Object title, const char **error_name)
 {
-#ifdef HAVE_X_WINDOWS
-  Window dummy_window;
-#endif
   Window root;
   XMenu *menu;
   int pane, selidx, lpane, status;
@@ -2620,17 +2595,7 @@ x_menu_show (struct frame *f, int x, int y, int 
menuflags,
   inhibit_garbage_collection ();
 
 #ifdef HAVE_X_WINDOWS
-  XTranslateCoordinates (FRAME_X_DISPLAY (f),
-
-                         /* From-window, to-window.  */
-                         FRAME_X_WINDOW (f),
-                         FRAME_DISPLAY_INFO (f)->root_window,
-
-                         /* From-position, to-position.  */
-                         x, y, &x, &y,
-
-                         /* Child of win.  */
-                         &dummy_window);
+  x_translate_coordinates_to_root (f, x, y, &x, &y);
 #else
   /* MSDOS without X support.  */
   x += f->left_pos;
diff --git a/src/xselect.c b/src/xselect.c
index 66782d4172..498c28af53 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -2376,12 +2376,19 @@ On Nextstep, TERMINAL is unused.  */)
 {
   Window owner;
   Atom atom;
+#ifdef HAVE_XFIXES
+  Window temp_owner;
+#endif
   struct frame *f = frame_for_x_selection (terminal);
   struct x_display_info *dpyinfo;
 
   CHECK_SYMBOL (selection);
-  if (NILP (selection)) selection = QPRIMARY;
-  if (EQ (selection, Qt)) selection = QSECONDARY;
+
+  if (NILP (selection))
+    selection = QPRIMARY;
+
+  if (EQ (selection, Qt))
+    selection = QSECONDARY;
 
   if (!f)
     return Qnil;
@@ -2392,10 +2399,22 @@ On Nextstep, TERMINAL is unused.  */)
     return Qt;
 
   atom = symbol_to_x_atom (dpyinfo, selection);
-  if (atom == 0) return Qnil;
+
+  if (!atom)
+    return Qnil;
+
+#ifdef HAVE_XFIXES
+  /* See if this information can be obtained without a roundtrip.  */
+  temp_owner = x_find_selection_owner (dpyinfo, atom);
+
+  if (temp_owner != X_INVALID_WINDOW)
+    return (temp_owner != None ? Qt : Qnil);
+#endif
+
   block_input ();
   owner = XGetSelectionOwner (dpyinfo->display, atom);
   unblock_input ();
+
   return (owner ? Qt : Qnil);
 }
 
diff --git a/src/xterm.c b/src/xterm.c
index ee6db62bb9..07a8c5e1c3 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13659,6 +13659,43 @@ x_translate_coordinates (struct frame *f, int root_x, 
int root_y,
     }
 }
 
+/* Translate the given coordinates from the edit window of FRAME,
+   taking into account any cached root window offsets.  This is mainly
+   used from the popup menu code.  */
+
+void
+x_translate_coordinates_to_root (struct frame *f, int x, int y,
+                                int *x_out, int *y_out)
+{
+  struct x_output *output;
+  Window dummy;
+
+  output = FRAME_X_OUTPUT (f);
+
+  if (output->window_offset_certain_p)
+    {
+      /* Use the cached root window offset.  */
+      *x_out = x + output->root_x;
+      *y_out = y + output->root_y;
+
+      return;
+    }
+
+  /* Otherwise, do the transform manually and compute and cache the
+     root window position.  */
+  if (!XTranslateCoordinates (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+                             FRAME_DISPLAY_INFO (f)->root_window,
+                             x, y, x_out, y_out, &dummy))
+    *x_out = 0, *y_out = 0;
+  else
+    {
+      /* Cache the root window offset of the edit window.  */
+      output->window_offset_certain_p = true;
+      output->root_x = *x_out - x;
+      output->root_y = *y_out - y;
+    }
+}
+
 /* The same, but for an XIDeviceEvent.  */
 
 #ifdef HAVE_XINPUT2
@@ -17816,6 +17853,44 @@ x_handle_wm_state (struct frame *f, struct input_event 
*ie)
   XFree (data);
 }
 
+#ifdef HAVE_XFIXES
+
+static void
+x_handle_selection_monitor_event (struct x_display_info *dpyinfo,
+                                 XEvent *event)
+{
+  XFixesSelectionNotifyEvent *notify;
+  int i;
+
+  notify = (XFixesSelectionNotifyEvent *) event;
+
+  if (notify->window != dpyinfo->selection_tracking_window)
+    return;
+
+  for (i = 0; i < dpyinfo->n_monitored_selections; ++i)
+    {
+      /* We don't have to keep track of timestamps here.  */
+      if (notify->selection == dpyinfo->monitored_selections[i].name)
+       dpyinfo->monitored_selections[i].owner = notify->owner;
+    }
+}
+
+Window
+x_find_selection_owner (struct x_display_info *dpyinfo, Atom selection)
+{
+  int i;
+
+  for (i = 0; i < dpyinfo->n_monitored_selections; ++i)
+    {
+      if (selection == dpyinfo->monitored_selections[i].name)
+       return dpyinfo->monitored_selections[i].owner;
+    }
+
+  return X_INVALID_WINDOW;
+}
+
+#endif
+
 /* Handles the XEvent EVENT on display DPYINFO.
 
    *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
@@ -20495,7 +20570,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
            {
              int old_left = f->left_pos;
              int old_top = f->top_pos;
-             Lisp_Object frame = Qnil;
+             Lisp_Object frame;
 
              XSETFRAME (frame, f);
 
@@ -23348,7 +23423,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      /* Handle all disabled devices now, to prevent
                         things happening out-of-order later.  */
 
-                     if (ndevices)
+                     if (n_disabled)
                        {
                          xi_disable_devices (dpyinfo, disabled, n_disabled);
                          n_disabled = 0;
@@ -23753,12 +23828,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                         | XkbModifierMapMask
                                         | XkbVirtualModsMask),
                                        dpyinfo->xkb_desc) == Success)
-                   XkbGetNames (dpyinfo->display,
-                                XkbGroupNamesMask | XkbVirtualModNamesMask,
+                   XkbGetNames (dpyinfo->display, XkbAllNamesMask,
                                 dpyinfo->xkb_desc);
                  else
                    {
-                     XkbFreeKeyboard (dpyinfo->xkb_desc, XkbAllComponentsMask, 
True);
+                     XkbFreeKeyboard (dpyinfo->xkb_desc,
+                                      XkbAllComponentsMask, True);
                      dpyinfo->xkb_desc = NULL;
                    }
                }
@@ -23772,8 +23847,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                                 XkbUseCoreKbd);
 
                  if (dpyinfo->xkb_desc)
-                   XkbGetNames (dpyinfo->display,
-                                XkbGroupNamesMask | XkbVirtualModNamesMask,
+                   XkbGetNames (dpyinfo->display, XkbAllNamesMask,
                                 dpyinfo->xkb_desc);
                }
 
@@ -24063,6 +24137,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
          if (inev.ie.kind != NO_EVENT)
            x_dnd_update_tooltip_now ();
        }
+#endif
+#ifdef HAVE_XFIXES
+      if (dpyinfo->xfixes_supported_p
+         && event->type == (dpyinfo->xfixes_event_base
+                            + XFixesSelectionNotify))
+       x_handle_selection_monitor_event (dpyinfo, event);
 #endif
     OTHER:
 #ifdef USE_X_TOOLKIT
@@ -28564,6 +28644,27 @@ xi_check_toolkit (Display *display)
 
 #endif
 
+#ifdef HAVE_XFIXES
+
+/* Create and return a special window for receiving events such as
+   selection notify events.  The window is an 1x1 unmapped
+   override-redirect InputOnly window at -1, -1, which should prevent
+   it from doing anything.  */
+
+static Window
+x_create_special_window (struct x_display_info *dpyinfo)
+{
+  XSetWindowAttributes attrs;
+
+  attrs.override_redirect = True;
+
+  return XCreateWindow (dpyinfo->display, dpyinfo->root_window,
+                       -1, -1, 1, 1, 0, CopyFromParent, InputOnly,
+                       CopyFromParent, CWOverrideRedirect, &attrs);
+}
+
+#endif
+
 /* Open a connection to X display DISPLAY_NAME, and return the
    structure that describes the open display.  If obtaining the XCB
    connection or toolkit-specific display fails, return NULL.  Signal
@@ -28585,6 +28686,22 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
   GdkDisplay *gdpy;
   GdkScreen *gscr;
 #endif
+#ifdef HAVE_XFIXES
+  Lisp_Object tem, lisp_name;
+  int num_fast_selections;
+  Atom selection_name;
+#ifdef USE_XCB
+  xcb_get_selection_owner_cookie_t *selection_cookies;
+  xcb_get_selection_owner_reply_t *selection_reply;
+  xcb_generic_error_t *selection_error;
+#endif
+#endif
+  int i;
+
+  USE_SAFE_ALLOCA;
+
+  /* Avoid warnings when SAFE_ALLOCA is not actually used.  */
+  ((void) SAFE_ALLOCA (0));
 
   block_input ();
 
@@ -28737,12 +28854,14 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
 #endif
 
       unblock_input ();
+
+      SAFE_FREE ();
       return 0;
     }
 
 #ifdef USE_XCB
   xcb_conn = XGetXCBConnection (dpy);
-  if (xcb_conn == 0)
+  if (!xcb_conn)
     {
 #ifdef USE_GTK
       xg_display_close (dpy);
@@ -28755,6 +28874,8 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
 #endif /* ! USE_GTK */
 
       unblock_input ();
+
+      SAFE_FREE ();
       return 0;
     }
 #endif
@@ -29307,8 +29428,7 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
                                     XkbUseCoreKbd);
 
       if (dpyinfo->xkb_desc)
-       XkbGetNames (dpyinfo->display,
-                    XkbGroupNamesMask | XkbVirtualModNamesMask,
+       XkbGetNames (dpyinfo->display, XkbAllNamesMask,
                     dpyinfo->xkb_desc);
 
       XkbSelectEvents (dpyinfo->display, XkbUseCoreKbd,
@@ -29318,9 +29438,10 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
 #endif
 
 #ifdef HAVE_XFIXES
-  int xfixes_event_base, xfixes_error_base;
+  int xfixes_error_base;
   dpyinfo->xfixes_supported_p
-    = XFixesQueryExtension (dpyinfo->display, &xfixes_event_base,
+    = XFixesQueryExtension (dpyinfo->display,
+                           &dpyinfo->xfixes_event_base,
                            &xfixes_error_base);
 
   if (dpyinfo->xfixes_supported_p)
@@ -29371,7 +29492,6 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
           XScreenNumberOfScreen (dpyinfo->screen));
 
   {
-    int i;
     enum { atom_count = ARRAYELTS (x_atom_refs) };
     /* 1 for _XSETTINGS_SN.  */
     enum { total_atom_count = 2 + atom_count };
@@ -29539,8 +29659,100 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
   dpyinfo->protected_windows_max = 256;
 #endif
 
+#ifdef HAVE_XFIXES
+  /* Initialize selection tracking for the selections in
+     x-fast-selection-list.  */
+
+  if (CONSP (Vx_fast_selection_list)
+      && dpyinfo->xfixes_supported_p
+      && dpyinfo->xfixes_major >= 1)
+    {
+      num_fast_selections = 0;
+      tem = Vx_fast_selection_list;
+
+      FOR_EACH_TAIL_SAFE (tem)
+       {
+         if (!SYMBOLP (XCAR (tem)))
+           continue;
+
+         num_fast_selections++;
+       }
+
+      dpyinfo->n_monitored_selections = num_fast_selections;
+      dpyinfo->selection_tracking_window
+       = x_create_special_window (dpyinfo);
+      dpyinfo->monitored_selections
+       = xmalloc (num_fast_selections
+                  * sizeof *dpyinfo->monitored_selections);
+
+      num_fast_selections = 0;
+      tem = Vx_fast_selection_list;
+
+      FOR_EACH_TAIL_SAFE (tem)
+       {
+         lisp_name = XCAR (tem);
+
+         if (!SYMBOLP (lisp_name))
+           continue;
+
+         selection_name = symbol_to_x_atom (dpyinfo, lisp_name);
+         dpyinfo->monitored_selections[num_fast_selections++].name
+           = selection_name;
+         dpyinfo->monitored_selections[num_fast_selections - 1].owner
+           = X_INVALID_WINDOW;
+
+         /* Select for selection input.  */
+         XFixesSelectSelectionInput (dpyinfo->display,
+                                     dpyinfo->selection_tracking_window,
+                                     selection_name,
+                                     (XFixesSetSelectionOwnerNotifyMask
+                                      | XFixesSetSelectionOwnerNotifyMask
+                                      | XFixesSelectionClientCloseNotifyMask));
+       }
+
+#ifdef USE_XCB
+      selection_cookies = SAFE_ALLOCA (sizeof *selection_cookies
+                                      * num_fast_selections);
+#endif
+
+      /* Now, ask for the current owners of all those selections.  */
+      for (i = 0; i < num_fast_selections; ++i)
+       {
+#ifdef USE_XCB
+         selection_cookies[i]
+           = xcb_get_selection_owner (dpyinfo->xcb_connection,
+                                      dpyinfo->monitored_selections[i].name);
+#else
+         dpyinfo->monitored_selections[i].owner
+           = XGetSelectionOwner (dpyinfo->display,
+                                 dpyinfo->monitored_selections[i].name);
+#endif
+       }
+
+#ifdef USE_XCB
+      for (i = 0; i < num_fast_selections; ++i)
+       {
+         selection_reply
+           = xcb_get_selection_owner_reply (dpyinfo->xcb_connection,
+                                            selection_cookies[i],
+                                            &selection_error);
+
+         if (selection_reply)
+           {
+             dpyinfo->monitored_selections[i].owner
+               = selection_reply->owner;
+             free (selection_reply);
+           }
+         else if (selection_error)
+           free (selection_error);
+       }
+#endif
+    }
+#endif
+
   unblock_input ();
 
+  SAFE_FREE ();
   return dpyinfo;
 }
 
@@ -29676,6 +29888,10 @@ x_delete_display (struct x_display_info *dpyinfo)
   xfree (dpyinfo->x_id_name);
   xfree (dpyinfo->x_dnd_atoms);
   xfree (dpyinfo->color_cells);
+#ifdef HAVE_XFIXES
+  if (dpyinfo->monitored_selections)
+    xfree (dpyinfo->monitored_selections);
+#endif
 #ifdef USE_TOOLKIT_SCROLL_BARS
   xfree (dpyinfo->protected_windows);
 #endif
@@ -30643,4 +30859,17 @@ It should accept a single argument, a string 
describing the locale of
 the input method, and return a coding system that can decode keyboard
 input generated by said input method.  */);
   Vx_input_coding_function = Qnil;
+
+  DEFVAR_LISP ("x-fast-selection-list", Vx_fast_selection_list,
+    doc: /* List of selections for which `x-selection-exists-p' should be fast.
+
+List of selection names as atoms that will be monitored by Emacs for
+ownership changes when the X server supports the XFIXES extension.
+The result of the monitoring is then used by `x-selection-exists-p' to
+avoid a server round trip, which is important as it is called while
+updating the tool bar.  The value of this variable is only read upon
+connection setup.  */);
+  /* The default value of this variable is chosen so that updating the
+     tool bar does not require a call to _XReply.  */
+  Vx_fast_selection_list = list1 (QCLIPBOARD);
 }
diff --git a/src/xterm.h b/src/xterm.h
index 55fd193a29..0f00dc42f7 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -308,6 +308,22 @@ struct x_failable_request
   unsigned long end;
 };
 
+#ifdef HAVE_XFIXES
+
+struct x_monitored_selection
+{
+  /* The name of the selection.  */
+  Atom name;
+
+  /* The current owner of the selection.  */
+  Window owner;
+};
+
+/* An invalid window.  */
+#define X_INVALID_WINDOW 0xffffffff
+
+#endif
+
 
 /* For each X display, we have a structure that records
    information about it.  */
@@ -778,6 +794,7 @@ struct x_display_info
   bool xfixes_supported_p;
   int xfixes_major;
   int xfixes_minor;
+  int xfixes_event_base;
 #endif
 
 #ifdef HAVE_XSYNC
@@ -828,6 +845,17 @@ struct x_display_info
   /* Pointer to the next request in `failable_requests'.  */
   struct x_failable_request *next_failable_request;
 
+#ifdef HAVE_XFIXES
+  /* Array of selections being monitored and their owners.  */
+  struct x_monitored_selection *monitored_selections;
+
+  /* Window used to monitor those selections.  */
+  Window selection_tracking_window;
+
+  /* The number of those selections.  */
+  int n_monitored_selections;
+#endif
+
   /* The pending drag-and-drop time for middle-click based
      drag-and-drop emulation.  */
   Time pending_dnd_time;
@@ -1656,6 +1684,10 @@ extern void x_cr_draw_frame (cairo_t *, struct frame *);
 extern Lisp_Object x_cr_export_frames (Lisp_Object, cairo_surface_type_t);
 #endif
 
+#ifdef HAVE_XFIXES
+extern Window x_find_selection_owner (struct x_display_info *, Atom);
+#endif
+
 #ifdef HAVE_XRENDER
 extern void x_xrender_color_from_gc_background (struct frame *, GC,
                                                XRenderColor *, bool);
@@ -1664,6 +1696,8 @@ extern void x_xr_apply_ext_clip (struct frame *, GC);
 extern void x_xr_reset_ext_clip (struct frame *);
 #endif
 
+extern void x_translate_coordinates_to_root (struct frame *, int, int,
+                                            int *, int *);
 extern Bool x_query_pointer (Display *, Window, Window *, Window *, int *,
                             int *, int *, int *, unsigned int *);
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]