diff options
Diffstat (limited to 'src/xterm.c')
-rw-r--r-- | src/xterm.c | 654 |
1 files changed, 488 insertions, 166 deletions
diff --git a/src/xterm.c b/src/xterm.c index a4ce228e9e6..1eef8e7a724 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -26,6 +26,22 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ contains subroutines comprising the redisplay interface, setting up scroll bars and widgets, and handling input. + X WINDOW SYSTEM + + The X Window System is a windowing system for bitmap graphics + displays which originated at MIT in 1984. Version 11, which is + currently supported by Emacs, first appeared in September 1987. + + X has a long history and has been developed by many different + organizations over the years; at present, it is being primarily + developed by the X.Org Foundation. It is the main window system + that Emacs is developed and tested against, and X version 10 was + the first window system that Emacs was ported to. As a consequence + of its age and wide availability, X contains many idiosyncrasies, + but that has not prevented it from becoming the dominant free + window system, and the platform of reference for all GUI code in + Emacs. + Some of what is explained below also applies to the other window systems that Emacs supports, to varying degrees. YMMV. @@ -555,7 +571,56 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ drop happening with the primary selection and synthetic button events (see `x_dnd_do_unsupported_drop'). That function implements the OffiX drag-and-drop protocol by default. See - `x-dnd-handle-unsupported-drop' in `x-dnd.el' for more details. */ + `x-dnd-handle-unsupported-drop' in `x-dnd.el' for more details. + + DISPLAY ERROR HANDLING + + While error handling under X was originally designed solely as a + mechanism for the X server to report fatal errors to clients, most + clients (including Emacs) have adopted a system of "error traps" to + handle or discard these errors as they arrive. Discarding errors is + usually necessary when Emacs performs an X request that might fail: + for example, sending a message to a window that may no longer exist, + or might not exist at all. Handling errors is then necessary when + the detailed error must be reported to another piece of code: for + example, as a Lisp error. + + It is not acceptable for Emacs to crash when it is sent invalid data + by another client, or by Lisp. As a result, errors must be caught + around Xlib functions generating requests containing resource + identifiers that could potentially be invalid, such as window or + atom identifiers provided in a client message from another program, + or a child window ID obtained through XTranslateCoordinates that may + refer to a window that has been deleted in the meantime. + + There are two sets of functions used to perform this "error + trapping". Which one should be used depends on what kind of + processing must be done on the error. The first consists of the + functions `x_ignore_errors_for_next_request' and + `x_stop_ignoring_errors', which ignore errors generated by requests + made in between a call to the first function and a corresponding + call to the second. They should be used for simple asynchronous + requests that do not require a reply from the X server: using them + instead of the second set improves performance, as they simply + record a range of request serials to ignore errors from, instead of + synchronizing with the X server to handle errors. + + The second set consists of the following functions: + + - x_catch_errors_with_handler + - x_catch_errors + - x_uncatch_errors_after_check + - x_uncatch_errors + - x_check_errors + - x_had_errors_p + - x_clear_errors + + Callers using this set should consult the comment(s) on top of the + aformentioned functions. They should not be used when the requests + being made do not require roundtrips to the X server, and obtaining + the details of any error generated is unecessary, as + `x_uncatch_errors' will always synchronize with the X server, which + is a potentially slow operation. */ #include <config.h> #include <stdlib.h> @@ -574,7 +639,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #ifdef USE_XCB #include <xcb/xproto.h> #include <xcb/xcb.h> -#include <xcb/xcb_aux.h> #endif /* If we have Xfixes extension, use it for pointer blanking. */ @@ -1052,6 +1116,20 @@ static const struct x_atom_ref x_atom_refs[] = /* Old OffiX (a.k.a. old KDE) drop protocol support. */ ATOM_REFS_INIT ("DndProtocol", Xatom_DndProtocol) ATOM_REFS_INIT ("_DND_PROTOCOL", Xatom_DND_PROTOCOL) + /* Here are some atoms that are not actually used from C, just + defined to make replying to selection requests fast. */ + ATOM_REFS_INIT ("text/plain;charset=utf-8", Xatom_text_plain_charset_utf_8) + ATOM_REFS_INIT ("LENGTH", Xatom_LENGTH) + ATOM_REFS_INIT ("FILE_NAME", Xatom_FILE_NAME) + ATOM_REFS_INIT ("CHARACTER_POSITION", Xatom_CHARACTER_POSITION) + ATOM_REFS_INIT ("LINE_NUMBER", Xatom_LINE_NUMBER) + ATOM_REFS_INIT ("COLUMN_NUMBER", Xatom_COLUMN_NUMBER) + ATOM_REFS_INIT ("OWNER_OS", Xatom_OWNER_OS) + ATOM_REFS_INIT ("HOST_NAME", Xatom_HOST_NAME) + ATOM_REFS_INIT ("USER", Xatom_USER) + ATOM_REFS_INIT ("CLASS", Xatom_CLASS) + ATOM_REFS_INIT ("NAME", Xatom_NAME) + ATOM_REFS_INIT ("SAVE_TARGETS", Xatom_SAVE_TARGETS) }; enum @@ -2509,7 +2587,7 @@ xm_send_drop_message (struct x_display_info *dpyinfo, Window source, *((uint32_t *) &msg.xclient.data.b[12]) = dmsg->index_atom; *((uint32_t *) &msg.xclient.data.b[16]) = dmsg->source_window; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2536,7 +2614,7 @@ xm_send_top_level_enter_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2567,7 +2645,7 @@ xm_send_drag_motion_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2626,7 +2704,7 @@ xm_send_top_level_leave_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2921,7 +2999,7 @@ x_dnd_free_toplevels (bool display_alive) if (n_windows) { eassume (dpyinfo); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); for (i = 0; i < n_windows; ++i) { @@ -3058,7 +3136,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) 0, 0); get_property_cookies[i] = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i], - (xcb_atom_t) dpyinfo->Xatom_wm_state, XCB_ATOM_ANY, + (xcb_atom_t) dpyinfo->Xatom_wm_state, 0, 0, 2); xm_property_cookies[i] = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i], @@ -3069,7 +3147,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) toplevels[i], (xcb_atom_t) dpyinfo->Xatom_net_frame_extents, - XCB_ATOM_CARDINAL, 0, 4); + XA_CARDINAL, 0, 4); get_geometry_cookies[i] = xcb_get_geometry (dpyinfo->xcb_connection, (xcb_window_t) toplevels[i]); @@ -3197,7 +3275,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) { if (xcb_get_property_value_length (extent_property_reply) == 16 && extent_property_reply->format == 32 - && extent_property_reply->type == XCB_ATOM_CARDINAL) + && extent_property_reply->type == XA_CARDINAL) { fextents = xcb_get_property_value (extent_property_reply); frame_extents[0] = fextents[0]; @@ -3291,7 +3369,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) if (dpyinfo->xshape_supported_p) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XShapeSelectInput (dpyinfo->display, toplevels[i], ShapeNotifyMask); @@ -3456,7 +3534,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) } #endif - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSelectInput (dpyinfo->display, toplevels[i], (attrs.your_event_mask | StructureNotifyMask @@ -3571,13 +3649,13 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, Window wdesc, xdnd_proxy_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) wdesc, (xcb_atom_t) dpyinfo->Xatom_XdndProxy, - XCB_ATOM_WINDOW, 0, 1); + XA_WINDOW, 0, 1); if (proto_out) xdnd_proto_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) wdesc, (xcb_atom_t) dpyinfo->Xatom_XdndAware, - XCB_ATOM_ATOM, 0, 1); + XA_ATOM, 0, 1); if (proxy_out) { @@ -3589,7 +3667,7 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, Window wdesc, else { if (reply->format == 32 - && reply->type == XCB_ATOM_WINDOW + && reply->type == XA_WINDOW && (xcb_get_property_value_length (reply) >= 4)) *proxy_out = *(xcb_window_t *) xcb_get_property_value (reply); @@ -3607,7 +3685,7 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, Window wdesc, else { if (reply->format == 32 - && reply->type == XCB_ATOM_ATOM + && reply->type == XA_ATOM && (xcb_get_property_value_length (reply) >= 4)) *proto_out = (int) *(xcb_atom_t *) xcb_get_property_value (reply); @@ -3791,15 +3869,15 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo, wmstate_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_wm_state, - XCB_ATOM_ANY, 0, 2); + 0, 0, 2); xdnd_proto_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_XdndAware, - XCB_ATOM_ATOM, 0, 1); + XA_ATOM, 0, 1); xdnd_proxy_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_XdndProxy, - XCB_ATOM_WINDOW, 0, 1); + XA_WINDOW, 0, 1); xm_style_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) window, (xcb_atom_t) dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO, @@ -3846,7 +3924,7 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo, else { if (reply->format == 32 - && reply->type == XCB_ATOM_WINDOW + && reply->type == XA_WINDOW && (xcb_get_property_value_length (reply) >= 4)) *proxy_out = *(xcb_window_t *) xcb_get_property_value (reply); @@ -3962,6 +4040,12 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo, if (owner != FRAME_X_WINDOW (f)) return; + /* mouse-drag-and-drop-region will immediately deactivate the mark + after this is set. Make sure the primary selection is not + clobbered in that case by setting `deactivate-mark' to + Qdont_save. */ + Vdeactivate_mark = Qdont_save; + event.xbutton.window = child; event.xbutton.subwindow = None; event.xbutton.x = dest_x; @@ -3975,7 +4059,7 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo, event.xbutton.type = ButtonPress; event.xbutton.time = before + 1; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, child, True, ButtonPressMask, &event); @@ -4487,7 +4571,7 @@ x_dnd_send_enter (struct frame *f, Window target, Window toplevel, so we don't have to set it again. */ x_dnd_init_type_lists = true; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -4559,7 +4643,7 @@ x_dnd_send_position (struct frame *f, Window target, Window toplevel, return; } - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); @@ -4586,7 +4670,7 @@ x_dnd_send_leave (struct frame *f, Window target, Window toplevel) x_dnd_waiting_for_status_window = None; x_dnd_pending_send_position.type = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -4619,7 +4703,7 @@ x_dnd_send_drop (struct frame *f, Window target, Window toplevel, if (supported >= 1) msg.xclient.data.l[2] = timestamp; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); return true; @@ -6731,7 +6815,7 @@ x_set_frame_alpha (struct frame *f) Do this unconditionally as this function is called on reparent when alpha has not changed on the frame. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); if (!FRAME_PARENT_FRAME (f)) { @@ -6907,6 +6991,7 @@ static void x_sync_wait_for_frame_drawn_event (struct frame *f) { XEvent event; + struct x_display_info *dpyinfo; if (!FRAME_X_WAITING_FOR_DRAW (f) /* The compositing manager can't draw a frame if it is @@ -6914,6 +6999,8 @@ x_sync_wait_for_frame_drawn_event (struct frame *f) || !FRAME_VISIBLE_P (f)) return; + dpyinfo = FRAME_DISPLAY_INFO (f); + /* Wait for the frame drawn message to arrive. */ if (x_if_event (FRAME_X_DISPLAY (f), &event, x_sync_is_frame_drawn_event, (XPointer) f, @@ -6929,6 +7016,11 @@ x_sync_wait_for_frame_drawn_event (struct frame *f) "been disabled\n"); FRAME_X_OUTPUT (f)->use_vsync_p = false; + /* Remove the compositor bypass property from the outer + window. */ + XDeleteProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f), + dpyinfo->Xatom_net_wm_bypass_compositor); + /* Also change the frame parameter to reflect the new state. */ store_frame_param (f, Quse_frame_synchronization, Qnil); @@ -6942,7 +7034,7 @@ x_sync_wait_for_frame_drawn_event (struct frame *f) } } else - x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event); + x_sync_note_frame_times (dpyinfo, f, &event); FRAME_X_WAITING_FOR_DRAW (f) = false; } @@ -7553,6 +7645,46 @@ x_after_update_window_line (struct window *w, struct glyph_row *desired_row) #endif } +/* Generate a premultiplied pixel value for COLOR with ALPHA applied + on the given display. COLOR will be modified. The display must + use a visual that supports an alpha channel. + + This is possibly dead code on builds which do not support + XRender. */ + +#ifndef USE_CAIRO + +static unsigned long +x_premultiply_pixel (struct x_display_info *dpyinfo, + XColor *color, double alpha) +{ + unsigned long pixel; + + eassert (dpyinfo->alpha_bits); + + /* Multiply the RGB channels. */ + color->red *= alpha; + color->green *= alpha; + color->blue *= alpha; + + /* First, allocate a fully opaque pixel. */ + pixel = x_make_truecolor_pixel (dpyinfo, color->red, + color->green, + color->blue); + + /* Next, erase the alpha component. */ + pixel &= ~dpyinfo->alpha_mask; + + /* And add an alpha channel. */ + pixel |= (((unsigned long) (alpha * 65535) + >> (16 - dpyinfo->alpha_bits)) + << dpyinfo->alpha_offset); + + return pixel; +} + +#endif + static void x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fringe_bitmap_params *p) @@ -7642,18 +7774,15 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, if (FRAME_DISPLAY_INFO (f)->alpha_bits && f->alpha_background < 1.0) { + /* Extend the background color with an alpha channel + according to f->alpha_background. */ bg.pixel = background; x_query_colors (f, &bg, 1); - bg.red *= f->alpha_background; - bg.green *= f->alpha_background; - bg.blue *= f->alpha_background; - background = x_make_truecolor_pixel (FRAME_DISPLAY_INFO (f), - bg.red, bg.green, bg.blue); - background &= ~FRAME_DISPLAY_INFO (f)->alpha_mask; - background |= (((unsigned long) (f->alpha_background * 0xffff) - >> (16 - FRAME_DISPLAY_INFO (f)->alpha_bits)) - << FRAME_DISPLAY_INFO (f)->alpha_offset); + background + = x_premultiply_pixel (FRAME_DISPLAY_INFO (f), + &bg, + f->alpha_background); } /* Draw the bitmap. I believe these small pixmaps can be cached @@ -8802,7 +8931,11 @@ x_color_cells (Display *dpy, int *ncells) /* On frame F, translate pixel colors to RGB values for the NCOLORS - colors in COLORS. Use cached information, if available. */ + colors in COLORS. Use cached information, if available. + + Pixel values are in unsigned normalized format, meaning that + extending missing bits is done straightforwardly without any + complex colorspace conversions. */ void x_query_colors (struct frame *f, XColor *colors, int ncolors) @@ -8850,6 +8983,7 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors) colors[i].green = (g * gmult) >> 16; colors[i].blue = (b * bmult) >> 16; } + return; } @@ -8892,16 +9026,10 @@ x_query_frame_background_color (struct frame *f, XColor *bgcolor) { bg.pixel = background; x_query_colors (f, &bg, 1); - bg.red *= f->alpha_background; - bg.green *= f->alpha_background; - bg.blue *= f->alpha_background; - background = x_make_truecolor_pixel (FRAME_DISPLAY_INFO (f), - bg.red, bg.green, bg.blue); - background &= ~FRAME_DISPLAY_INFO (f)->alpha_mask; - background |= (((unsigned long) (f->alpha_background * 0xffff) - >> (16 - FRAME_DISPLAY_INFO (f)->alpha_bits)) - << FRAME_DISPLAY_INFO (f)->alpha_offset); + background + = x_premultiply_pixel (FRAME_DISPLAY_INFO (f), + &bg, f->alpha_background); } #endif } @@ -10991,6 +11119,31 @@ x_clear_frame (struct frame *f) unblock_input (); } +/* Send a message to frame F telling the event loop to track whether + or not an hourglass is being displayed. This is required to ignore + the right events when the hourglass is mapped without callig XSync + after displaying or hiding the hourglass. */ + +static void +x_send_hourglass_message (struct frame *f, bool hourglass_enabled) +{ + struct x_display_info *dpyinfo; + XEvent msg; + + dpyinfo = FRAME_DISPLAY_INFO (f); + memset (&msg, 0, sizeof msg); + + msg.xclient.type = ClientMessage; + msg.xclient.message_type + = dpyinfo->Xatom_EMACS_TMP; + msg.xclient.format = 8; + msg.xclient.window = FRAME_X_WINDOW (f); + msg.xclient.data.b[0] = hourglass_enabled ? 1 : 0; + + XSendEvent (dpyinfo->display, FRAME_X_WINDOW (f), + False, NoEventMask, &msg); +} + /* RIF: Show hourglass cursor on frame F. */ static void @@ -11011,14 +11164,14 @@ x_show_hourglass (struct frame *f) if (popup_activated ()) return; + x_send_hourglass_message (f, true); + #ifdef USE_X_TOOLKIT if (x->widget) #else if (FRAME_OUTER_WINDOW (f)) #endif { - x->hourglass_p = true; - if (!x->hourglass_window) { #ifndef USE_XCB @@ -11085,15 +11238,11 @@ x_hide_hourglass (struct frame *f) { #ifndef USE_XCB XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window); - /* Sync here because XTread_socket looks at the - hourglass_p flag that is reset to zero below. */ - XSync (FRAME_X_DISPLAY (f), False); #else xcb_unmap_window (FRAME_DISPLAY_INFO (f)->xcb_connection, (xcb_window_t) x->hourglass_window); - xcb_aux_sync (FRAME_DISPLAY_INFO (f)->xcb_connection); #endif - x->hourglass_p = false; + x_send_hourglass_message (f, false); } } @@ -11217,21 +11366,32 @@ XTflash (struct frame *f) static void XTring_bell (struct frame *f) { - if (FRAME_X_DISPLAY (f)) + struct x_display_info *dpyinfo; + + if (!FRAME_X_DISPLAY (f)) + return; + + dpyinfo = FRAME_DISPLAY_INFO (f); + + if (visible_bell) + XTflash (f); + else { - if (visible_bell) - XTflash (f); - else - { - block_input (); + /* When Emacs is untrusted, Bell requests sometimes generate + Access errors. This is not in the security extension + specification but seems to be a bug in the X consortium XKB + implementation. */ + + block_input (); + x_ignore_errors_for_next_request (dpyinfo, 0); #ifdef HAVE_XKB - XkbBell (FRAME_X_DISPLAY (f), None, 0, None); + XkbBell (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, None); #else - XBell (FRAME_X_DISPLAY (f), 0); + XBell (FRAME_X_DISPLAY (f), 0); #endif - XFlush (FRAME_X_DISPLAY (f)); - unblock_input (); - } + XFlush (FRAME_X_DISPLAY (f)); + x_stop_ignoring_errors (dpyinfo); + unblock_input (); } } @@ -11477,7 +11637,7 @@ x_frame_highlight (struct frame *f) the window-manager in use, tho something more is at play since I've been using that same window-manager binary for ever. Let's not crash just because of this (bug#9310). */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->border_pixel); x_stop_ignoring_errors (dpyinfo); @@ -11500,7 +11660,7 @@ x_frame_unhighlight (struct frame *f) block_input (); /* Same as above for XSetWindowBorder (bug#9310). */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->border_tile); x_stop_ignoring_errors (dpyinfo); @@ -11564,7 +11724,7 @@ x_new_focus_frame (struct x_display_info *dpyinfo, struct frame *frame) x_frame_rehighlight (dpyinfo); } -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 /* True if the display in DPYINFO supports a version of Xfixes sufficient for pointer blanking. */ @@ -11576,11 +11736,12 @@ x_fixes_pointer_blanking_supported (struct x_display_info *dpyinfo) && dpyinfo->xfixes_major >= 4); } -#endif /* HAVE_XFIXES */ +#endif /* HAVE_XFIXES && XFIXES_VERSION >= 40000 */ /* Toggle mouse pointer visibility on frame F using the XFixes extension. */ -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 + static void xfixes_toggle_visible_pointer (struct frame *f, bool invisible) @@ -11591,6 +11752,7 @@ xfixes_toggle_visible_pointer (struct frame *f, bool invisible) XFixesShowCursor (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); f->pointer_invisible = invisible; } + #endif /* HAVE_XFIXES */ /* Create invisible cursor on the X display referred by DPYINFO. */ @@ -11639,7 +11801,7 @@ x_toggle_visible_pointer (struct frame *f, bool invisible) if (dpyinfo->invisible_cursor == None) dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo); -#ifndef HAVE_XFIXES +#if !defined HAVE_XFIXES || XFIXES_VERSION < 40000 if (dpyinfo->invisible_cursor == None) invisible = false; #else @@ -11672,7 +11834,7 @@ static void XTtoggle_invisible_pointer (struct frame *f, bool invisible) { block_input (); -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 if (FRAME_DISPLAY_INFO (f)->fixes_pointer_blanking && x_fixes_pointer_blanking_supported (FRAME_DISPLAY_INFO (f))) xfixes_toggle_visible_pointer (f, invisible); @@ -12261,6 +12423,13 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, struct xi_device_t *device; #endif + if (FRAME_DISPLAY_INFO (f)->untrusted) + /* Untrusted clients cannot send messages to trusted clients or + read the window tree, so drag and drop will likely not work at + all. */ + error ("Drag-and-drop is not possible when the client is" + " not trusted by the X server."); + base = SPECPDL_INDEX (); /* Bind this here to avoid juggling bindings and SAFE_FREE in @@ -15032,9 +15201,7 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, XClientMessageEvent *ev = &event.xclient; struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); - intptr_t iw = (intptr_t) w; verify (INTPTR_WIDTH <= 64); - int sign_shift = INTPTR_WIDTH - 32; /* Don't do anything if too many scroll bar events have been sent but not received. */ @@ -15051,15 +15218,11 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, ev->window = FRAME_X_WINDOW (f); ev->format = 32; - /* A 32-bit X client can pass a window pointer through the X server - as-is. - - A 64-bit client is in trouble because a pointer does not fit in - the 32 bits given for ClientMessage data and will be truncated by - Xlib. So use two slots and hope that X12 will resolve such - issues someday. */ - ev->data.l[0] = iw >> 31 >> 1; - ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift; + /* These messages formerly contained a pointer to the window, but + now that information is kept internally. The following two + fields are thus zero. */ + ev->data.l[0] = 0; + ev->data.l[1] = 0; ev->data.l[2] = part; ev->data.l[3] = portion; ev->data.l[4] = whole; @@ -18490,7 +18653,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_waiting_for_status_window = None; else { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &x_dnd_pending_send_position); @@ -18604,6 +18767,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } + if (event->xclient.message_type == dpyinfo->Xatom_EMACS_TMP + && event->xclient.format == 8) + { + /* This is actually an hourglass message. Set whether or + not events from here on have the hourglass enabled. */ + + if (any) + FRAME_X_OUTPUT (any)->hourglass_p = event->xclient.data.b[0]; + } + if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols && event->xclient.format == 32) { @@ -19192,7 +19365,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) FRAME_OUTER_WINDOW (f), (xcb_atom_t) dpyinfo->Xatom_net_wm_window_opacity, - XCB_ATOM_CARDINAL, 0, 1); + XA_CARDINAL, 0, 1); opacity_reply = xcb_get_property_reply (dpyinfo->xcb_connection, opacity_cookie, &error); @@ -19201,9 +19374,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, free (error), rc = false; else rc = (opacity_reply->format == 32 - && (opacity_reply->type == XCB_ATOM_CARDINAL - || opacity_reply->type == XCB_ATOM_ATOM - || opacity_reply->type == XCB_ATOM_WINDOW) + && (opacity_reply->type == XA_CARDINAL + || opacity_reply->type == XA_ATOM + || opacity_reply->type == XA_WINDOW) && (xcb_get_property_value_length (opacity_reply) >= 4)); if (rc) @@ -21349,7 +21522,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf))) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), RevertToParent, event->xbutton.time); x_stop_ignoring_errors (dpyinfo); @@ -21570,9 +21743,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, case VisibilityNotify: f = x_top_window_to_frame (dpyinfo, event->xvisibility.window); - if (f && (event->xvisibility.state == VisibilityUnobscured - || event->xvisibility.state == VisibilityPartiallyObscured)) - SET_FRAME_VISIBLE (f, 1); + + if (f) + FRAME_X_OUTPUT (f)->visibility_state = event->xvisibility.state; goto OTHER; @@ -23047,7 +23220,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* This can generate XI_BadDevice if the device's attachment was destroyed server-side. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XISetFocus (dpyinfo->display, device->attachment, /* Note that the input extension only supports RevertToParent-type @@ -23060,7 +23233,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, events to handle focus. Errors are still caught here in case the window is not viewable. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), RevertToParent, xev->time); x_stop_ignoring_errors (dpyinfo); @@ -24069,7 +24242,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifndef HAVE_GTK3 else if (x_input_grab_touch_events) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XIAllowTouchEvents (dpyinfo->display, xev->deviceid, xev->detail, xev->event, XIRejectTouch); x_stop_ignoring_errors (dpyinfo); @@ -25506,10 +25679,17 @@ x_clean_failable_requests (struct x_display_info *dpyinfo) x_uncatch_errors_after_check is that this function does not sync to catch errors if requests were made. It should be used instead of those two functions for catching errors around requests that do not - require a reply. */ + require a reply. + + As a special feature intended to support xselect.c, + SELECTION_SERIAL may be an arbitrary number greater than zero: when + that is the case, x_select_handle_selection_error is called with + the specified number to delete the selection request that + encountered the error. */ void -x_ignore_errors_for_next_request (struct x_display_info *dpyinfo) +x_ignore_errors_for_next_request (struct x_display_info *dpyinfo, + unsigned int selection_serial) { struct x_failable_request *request, *max; unsigned long next_request; @@ -25563,6 +25743,7 @@ x_ignore_errors_for_next_request (struct x_display_info *dpyinfo) request->start = next_request; request->end = 0; + request->selection_serial = selection_serial; dpyinfo->next_failable_request++; } @@ -25984,9 +26165,11 @@ For details, see etc/PROBLEMS.\n", if (!ioerror && dpyinfo) { /* Dump the list of error handlers for debugging - purposes. */ + purposes if the list exists. */ - fprintf (stderr, "X error handlers currently installed:\n"); + if ((dpyinfo->failable_requests + != dpyinfo->next_failable_request) || x_error_message) + fprintf (stderr, "X error handlers currently installed:\n"); for (failable = dpyinfo->failable_requests; failable < dpyinfo->next_failable_request; @@ -26075,6 +26258,12 @@ x_error_handler (Display *display, XErrorEvent *event) + (last - fail)); } + /* If a selection transfer is the cause of this error, + remove the selection transfer now. */ + if (fail->selection_serial) + x_handle_selection_error (fail->selection_serial, + event); + return 0; } } @@ -26111,8 +26300,10 @@ x_error_handler (Display *display, XErrorEvent *event) static void NO_INLINE x_error_quitter (Display *display, XErrorEvent *event) { - char buf[256], buf1[400 + INT_STRLEN_BOUND (int) - + INT_STRLEN_BOUND (unsigned long)]; + char buf[256], buf1[800 + INT_STRLEN_BOUND (int) + + INT_STRLEN_BOUND (unsigned long) + + INT_STRLEN_BOUND (XID) + + INT_STRLEN_BOUND (int)]; /* Ignore BadName errors. They can happen because of fonts or colors that are not defined. */ @@ -26125,8 +26316,12 @@ x_error_quitter (Display *display, XErrorEvent *event) XGetErrorText (display, event->error_code, buf, sizeof (buf)); sprintf (buf1, "X protocol error: %s on protocol request %d\n" - "Serial no: %lu\n", buf, event->request_code, - event->serial); + "Serial no: %lu\n" + "Failing resource ID (if any): 0x%lx\n" + "Minor code: %d\n" + "This is a bug! Please report this to bug-gnu-emacs@gnu.org!\n", + buf, event->request_code, event->serial, event->resourceid, + event->minor_code); x_connection_closed (display, buf1, false); } @@ -26627,38 +26822,43 @@ x_set_offset (struct frame *f, int xoff, int yoff, int change_gravity) modified_left, modified_top); #endif - /* 'x_sync_with_move' is too costly for dragging child frames. */ - if (!FRAME_PARENT_FRAME (f) - /* If no window manager exists, just calling XSync will be - sufficient to ensure that the window geometry has been - updated. */ - && NILP (Vx_no_window_manager)) - { - x_sync_with_move (f, f->left_pos, f->top_pos, - FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); - - /* change_gravity is non-zero when this function is called from Lisp to - programmatically move a frame. In that case, we call - x_check_expected_move to discover if we have a "Type A" or "Type B" - window manager, and, for a "Type A" window manager, adjust the position - of the frame. - - We call x_check_expected_move if a programmatic move occurred, and - either the window manager type (A/B) is unknown or it is Type A but we - need to compute the top/left offset adjustment for this frame. */ - - if (change_gravity != 0 - && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN - || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A - && (FRAME_X_OUTPUT (f)->move_offset_left == 0 - && FRAME_X_OUTPUT (f)->move_offset_top == 0)))) - x_check_expected_move (f, modified_left, modified_top); - } - /* Instead, just wait for the last ConfigureWindow request to - complete. No window manager is involved when moving child - frames. */ - else - XSync (FRAME_X_DISPLAY (f), False); + /* The following code is too slow over a latent network + connection. */ + if (NILP (Vx_lax_frame_positioning)) + { + /* 'x_sync_with_move' is too costly for dragging child frames. */ + if (!FRAME_PARENT_FRAME (f) + /* If no window manager exists, just calling XSync will be + sufficient to ensure that the window geometry has been + updated. */ + && NILP (Vx_no_window_manager)) + { + x_sync_with_move (f, f->left_pos, f->top_pos, + FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN); + + /* change_gravity is non-zero when this function is called from Lisp to + programmatically move a frame. In that case, we call + x_check_expected_move to discover if we have a "Type A" or "Type B" + window manager, and, for a "Type A" window manager, adjust the position + of the frame. + + We call x_check_expected_move if a programmatic move occurred, and + either the window manager type (A/B) is unknown or it is Type A but we + need to compute the top/left offset adjustment for this frame. */ + + if (change_gravity != 0 + && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN + || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A + && (FRAME_X_OUTPUT (f)->move_offset_left == 0 + && FRAME_X_OUTPUT (f)->move_offset_top == 0)))) + x_check_expected_move (f, modified_left, modified_top); + } + /* Instead, just wait for the last ConfigureWindow request to + complete. No window manager is involved when moving child + frames. */ + else + XSync (FRAME_X_DISPLAY (f), False); + } unblock_input (); } @@ -26718,6 +26918,12 @@ x_wm_supports_1 (struct x_display_info *dpyinfo, Atom want_atom) if (!NILP (Vx_no_window_manager)) return false; + /* If the window system says Emacs is untrusted, there will be no + way to send any information to the window manager, making any + hints useless. */ + if (dpyinfo->untrusted) + return false; + block_input (); x_catch_errors (dpy); @@ -27188,13 +27394,12 @@ do_ewmh_fullscreen (struct frame *f) static void XTfullscreen_hook (struct frame *f) { - if (FRAME_VISIBLE_P (f)) - { - block_input (); - x_check_fullscreen (f); - x_sync (f); - unblock_input (); - } + if (!FRAME_VISIBLE_P (f)) + return; + + block_input (); + x_check_fullscreen (f); + unblock_input (); } @@ -27288,10 +27493,7 @@ x_check_fullscreen (struct frame *f) if (FRAME_VISIBLE_P (f)) x_wait_for_event (f, ConfigureNotify); else - { - change_frame_size (f, width, height, false, true, false); - x_sync (f); - } + change_frame_size (f, width, height, false, true, false); } /* `x_net_wm_state' might have reset the fullscreen frame parameter, @@ -27465,6 +27667,12 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, we have to make sure to do it here. */ SET_FRAME_GARBAGED (f); + /* The following code is too slow over a latent network + connection, so skip it when the user says so. */ + + if (!NILP (Vx_lax_frame_positioning)) + return; + /* Now, strictly speaking, we can't be sure that this is accurate, but the window manager will get around to dealing with the size change request eventually, and we'll hear how it went when the @@ -27505,8 +27713,6 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, adjust_frame_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, width), FRAME_PIXEL_TO_TEXT_HEIGHT (f, height), 5, 0, Qx_set_window_size_1); - - x_sync (f); } } @@ -27560,7 +27766,7 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) && deviceid != -1) { block_input (); - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y); x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); @@ -27857,7 +28063,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, Window window, { eassert (device->use == XIMasterPointer); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XISetFocus (dpyinfo->display, device->attachment, /* Note that the input extension only supports RevertToParent-type @@ -27872,7 +28078,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, Window window, /* Otherwise, use the pointer device that the X server says is the client pointer. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (dpyinfo->display, window, RevertToParent, time); x_stop_ignoring_errors (dpyinfo); } @@ -27892,12 +28098,17 @@ x_focus_frame (struct frame *f, bool noactivate) struct x_display_info *dpyinfo; Time time; + dpyinfo = FRAME_DISPLAY_INFO (f); + + if (dpyinfo->untrusted) + /* The X server ignores all input focus related requests from + untrusted clients. */ + return; + /* The code below is not reentrant wrt to dpyinfo->x_focus_frame and friends being set. */ block_input (); - dpyinfo = FRAME_DISPLAY_INFO (f); - if (FRAME_X_EMBEDDED_P (f)) /* For Xembedded frames, normally the embedder forwards key events. See XEmbed Protocol Specification at @@ -28009,7 +28220,7 @@ xembed_send_message (struct frame *f, Time t, enum xembed_message msg, but I don't understand why: there is no way for clients to survive the death of the parent anyway. */ - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc, False, NoEventMask, &event); x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); @@ -28160,6 +28371,7 @@ x_make_frame_visible (struct frame *f) && !FRAME_ICONIFIED_P (f) && !FRAME_X_EMBEDDED_P (f) && !FRAME_PARENT_FRAME (f) + && NILP (Vx_lax_frame_positioning) && f->win_gravity == NorthWestGravity && previously_visible) { @@ -28188,7 +28400,8 @@ x_make_frame_visible (struct frame *f) } /* Try to wait for a MapNotify event (that is what tells us when a - frame becomes visible). */ + frame becomes visible). Unless `x-lax-frame-positioning' is + non-nil: there, that is a little slow. */ #ifdef CYGWIN /* On Cygwin, which uses input polling, we need to force input to @@ -28206,7 +28419,8 @@ x_make_frame_visible (struct frame *f) poll_suppress_count = old_poll_suppress_count; #endif - if (!FRAME_VISIBLE_P (f)) + if (!FRAME_VISIBLE_P (f) + && NILP (Vx_lax_frame_positioning)) { if (CONSP (frame_size_history)) frame_size_history_plain @@ -28263,7 +28477,10 @@ x_make_frame_invisible (struct frame *f) error ("Can't notify window manager of window withdrawal"); } - x_sync (f); + /* Don't perform the synchronization if the network connection is + slow, and the user says it is unwanted. */ + if (NILP (Vx_lax_frame_positioning)) + XSync (FRAME_X_DISPLAY (f), False); /* We can't distinguish this from iconification just by the event that we get from the server. @@ -28274,8 +28491,7 @@ x_make_frame_invisible (struct frame *f) SET_FRAME_ICONIFIED (f, false); if (CONSP (frame_size_history)) - frame_size_history_plain - (f, build_string ("x_make_frame_invisible")); + frame_size_history_plain (f, build_string ("x_make_frame_invisible")); unblock_input (); } @@ -28861,6 +29077,53 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom atom, return value; } +/* Intern an array of atoms, and do so quickly, avoiding extraneous + roundtrips to the X server. + + Avoid sending atoms that have already been found to the X server. + This cannot do anything that will end up triggering garbage + collection. */ + +void +x_intern_atoms (struct x_display_info *dpyinfo, char **names, int count, + Atom *atoms_return) +{ + int i, j, indices[256]; + char *new_names[256]; + Atom results[256], candidate; + + if (count > 256) + /* Atoms array too big to inspect reasonably, just send it to the + server and back. */ + XInternAtoms (dpyinfo->display, new_names, count, False, atoms_return); + else + { + for (i = 0, j = 0; i < count; ++i) + { + candidate = x_intern_cached_atom (dpyinfo, names[i], + true); + + if (candidate) + atoms_return[i] = candidate; + else + { + indices[j++] = i; + new_names[j - 1] = names[i]; + } + } + + if (!j) + return; + + /* Now, get the results back from the X server. */ + XInternAtoms (dpyinfo->display, new_names, j, False, + results); + + for (i = 0; i < j; ++i) + atoms_return[indices[i]] = results[i]; + } +} + #ifndef USE_GTK /* Set up XEmbed for F, and change its save set to handle the parent @@ -29409,6 +29672,7 @@ struct x_display_info * x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) { Display *dpy; + XKeyboardState keyboard_state; struct terminal *terminal; struct x_display_info *dpyinfo; XrmDatabase xrdb; @@ -29628,6 +29892,32 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) dpyinfo = xzalloc (sizeof *dpyinfo); terminal = x_create_terminal (dpyinfo); + if (!NILP (Vx_detect_server_trust)) + { + /* Detect whether or not the X server trusts this client, which + is done by making a SetKeyboardControl request and checking + for an Access error. */ + XGrabServer (dpy); + XGetKeyboardControl (dpy, &keyboard_state); + + x_catch_errors (dpy); + + /* At this point, the display is not on x_display_list, so + x_uncatch_errors won't sync. However, that's okay because + x_had_errors_p will. */ + + if (keyboard_state.global_auto_repeat + == AutoRepeatModeOn) + XAutoRepeatOn (dpy); + else + XAutoRepeatOff (dpy); + + if (x_had_errors_p (dpy)) + dpyinfo->untrusted = true; + x_uncatch_errors_after_check (); + XUngrabServer (dpy); + } + dpyinfo->next_failable_request = dpyinfo->failable_requests; { @@ -29648,13 +29938,17 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) { char *vendor = ServerVendor (dpy); - /* Temporarily hide the partially initialized terminal. */ + /* Temporarily hide the partially initialized terminal. + Use safe_call so that if a signal happens, a partially + initialized display (and display connection) is not + kept around. */ terminal_list = terminal->next_terminal; unblock_input (); - kset_system_key_alist - (terminal->kboard, - call1 (Qvendor_specific_keysyms, - vendor ? build_string (vendor) : empty_unibyte_string)); + kset_system_key_alist (terminal->kboard, + safe_call1 (Qvendor_specific_keysyms, + (vendor + ? build_string (vendor) + : empty_unibyte_string))); block_input (); terminal->next_terminal = terminal_list; terminal_list = terminal; @@ -30272,7 +30566,7 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) 1, 0, 1); dpyinfo->invisible_cursor = make_invisible_cursor (dpyinfo); -#ifdef HAVE_XFIXES +#if defined HAVE_XFIXES && XFIXES_VERSION >= 40000 dpyinfo->fixes_pointer_blanking = egetenv ("EMACS_XFIXES"); #endif @@ -30600,8 +30894,13 @@ x_delete_display (struct x_display_info *dpyinfo) last = ie; } + /* Delete selection requests bound for dpyinfo from the keyboard + buffer. */ x_delete_selection_requests (dpyinfo); + /* And remove any outstanding selection transfers. */ + x_remove_selection_transfers (dpyinfo); + if (next_noop_dpyinfo == dpyinfo) next_noop_dpyinfo = dpyinfo->next; @@ -31107,7 +31406,7 @@ x_catch_errors_for_lisp (struct x_display_info *dpyinfo) if (!x_fast_protocol_requests) x_catch_errors (dpyinfo->display); else - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); } void @@ -31316,6 +31615,8 @@ syms_of_xterm (void) DEFSYM (Qnow, "now"); DEFSYM (Qx_dnd_targets_list, "x-dnd-targets-list"); DEFSYM (Qx_auto_preserve_selections, "x-auto-preserve-selections"); + DEFSYM (Qexpose, "expose"); + DEFSYM (Qdont_save, "dont-save"); #ifdef USE_GTK xg_default_icon_file = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg"); @@ -31485,7 +31786,6 @@ always uses gtk_window_move and ignores the value of this variable. */); This option is only effective when Emacs is built with XInput 2 support. */); Vx_scroll_event_delta_factor = make_float (1.0); - DEFSYM (Qexpose, "expose"); DEFVAR_BOOL ("x-gtk-use-native-input", x_gtk_use_native_input, doc: /* Non-nil means to use GTK for input method support. @@ -31699,4 +31999,26 @@ select text over slow X connections. If that is still too slow, setting this variable to the symbol `really-fast' will make Emacs return only cached values. */); Vx_use_fast_mouse_position = Qnil; + + DEFVAR_LISP ("x-detect-server-trust", Vx_detect_server_trust, + doc: /* If non-nil, Emacs should detect whether or not it is trusted by X. + +If non-nil, Emacs will make an X request at connection startup that is +prohibited to untrusted clients under the X Security Extension and +check whether or not a resulting Access error is generated by the X +server. If the X server reports the error, Emacs will disable certain +features that do not work for untrusted clients. */); + Vx_detect_server_trust = Qnil; + + DEFVAR_LISP ("x-lax-frame-positioning", Vx_lax_frame_positioning, + doc: /* If non-nil, Emacs won't compensate for WM geometry behavior. + +Setting this to non-nil is useful when the compensation proves to be +too slow, which is usually true when the X server is located over a +network connection with high latency. Doing so will make frame +creation and placement faster at the cost of reducing the accuracy of +frame placement via frame parameters, `set-frame-position', and +`set-frame-size', along with the actual state of a frame after +`x_make_frame_invisible'. */); + Vx_lax_frame_positioning = Qnil; } |