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.
This commit is contained in:
parent
b9aff5fdb8
commit
abf683bb03
6 changed files with 348 additions and 132 deletions
|
@ -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
|
||||
|
|
115
src/xfns.c
115
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
|
||||
|
|
45
src/xmenu.c
45
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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
255
src/xterm.c
255
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);
|
||||
}
|
||||
|
|
34
src/xterm.h
34
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 *);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue