diff options
author | Po Lu <luangruo@yahoo.com> | 2022-10-17 20:56:20 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-10-17 21:00:09 +0800 |
commit | abf683bb0324b9c5d01adb90aedb6aa6fa7175e9 (patch) | |
tree | 1f28271f1c12d4e7bbba87e39433f802d2d0d55c | |
parent | b9aff5fdb89092b68ebd7782c8dc85e6daca14b2 (diff) | |
download | emacs-abf683bb0324b9c5d01adb90aedb6aa6fa7175e9.tar.gz |
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.
-rw-r--r-- | lisp/menu-bar.el | 6 | ||||
-rw-r--r-- | src/xfns.c | 115 | ||||
-rw-r--r-- | src/xmenu.c | 45 | ||||
-rw-r--r-- | src/xselect.c | 25 | ||||
-rw-r--r-- | src/xterm.c | 255 | ||||
-rw-r--r-- | src/xterm.h | 34 |
6 files changed, 348 insertions, 132 deletions
diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index c2c18320b15..526bccbbac9 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 91124488994..e8732986eb9 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 1452b3c6d12..9d35e3529fb 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 66782d41723..498c28af536 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 ee6db62bb94..07a8c5e1c3f 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); } @@ -24064,6 +24138,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, 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 if (*finish != X_EVENT_DROP) @@ -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 55fd193a29f..0f00dc42f79 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 *); |