Fix error handling for XCB Xlib
* src/xterm.c (xm_send_drop_message) (xm_send_top_level_enter_message, xm_send_drag_motion_message) (xm_send_top_level_leave_message, x_dnd_compute_toplevels) (x_dnd_send_enter, x_dnd_send_position, x_dnd_send_leave) (x_dnd_send_drop, handle_one_xevent, x_catch_errors_with_handler) (x_request_can_fail, x_clean_failable_requests) (x_ignore_errors_for_next_request, x_stop_ignoring_errors) (x_uncatch_errors, x_check_errors, x_had_errors_p, x_error_handler) (frame_set_mouse_pixel_position, x_focus_frame): Record serial sequences instead of simply the next request when ignoring a single request. Use XNextRequest instead of NextRequest, since the latter is unreliable when using Xlib built with XCB. * src/xterm.h (struct x_failable_request): New struct.. (struct x_display_info): Make failable request variables the right type.
This commit is contained in:
parent
59d109b73c
commit
b25ca54298
2 changed files with 84 additions and 33 deletions
99
src/xterm.c
99
src/xterm.c
|
@ -1117,6 +1117,7 @@ static void x_scroll_bar_end_update (struct x_display_info *, struct scroll_bar
|
|||
static int x_filter_event (struct x_display_info *, XEvent *);
|
||||
#endif
|
||||
static void x_ignore_errors_for_next_request (struct x_display_info *);
|
||||
static void x_stop_ignoring_errors (struct x_display_info *);
|
||||
static void x_clean_failable_requests (struct x_display_info *);
|
||||
|
||||
static struct frame *x_tooltip_window_to_frame (struct x_display_info *,
|
||||
|
@ -2444,6 +2445,7 @@ xm_send_drop_message (struct x_display_info *dpyinfo, Window source,
|
|||
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2470,6 +2472,7 @@ xm_send_top_level_enter_message (struct x_display_info *dpyinfo, Window source,
|
|||
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2500,6 +2503,7 @@ xm_send_drag_motion_message (struct x_display_info *dpyinfo, Window source,
|
|||
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2558,6 +2562,7 @@ xm_send_top_level_leave_message (struct x_display_info *dpyinfo, Window source,
|
|||
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -3211,6 +3216,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
|
|||
XShapeSelectInput (dpyinfo->display,
|
||||
toplevels[i],
|
||||
ShapeNotifyMask);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
|
||||
#ifndef HAVE_XCB_SHAPE
|
||||
x_catch_errors (dpyinfo->display);
|
||||
|
@ -4397,6 +4403,7 @@ x_dnd_send_enter (struct frame *f, Window target, int supported)
|
|||
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -4459,6 +4466,7 @@ x_dnd_send_position (struct frame *f, Window target, int supported,
|
|||
{
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
|
||||
x_dnd_waiting_for_status_window = target;
|
||||
}
|
||||
|
@ -4484,6 +4492,7 @@ x_dnd_send_leave (struct frame *f, Window target)
|
|||
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -4516,6 +4525,7 @@ x_dnd_send_drop (struct frame *f, Window target, Time timestamp,
|
|||
|
||||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -16454,6 +16464,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
XSendEvent (dpyinfo->display, target,
|
||||
False, NoEventMask,
|
||||
&x_dnd_pending_send_position);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
x_dnd_pending_send_position.type = 0;
|
||||
|
||||
/* Since we sent another XdndPosition message, we
|
||||
|
@ -22991,7 +23002,8 @@ x_error_catcher (Display *display, XErrorEvent *event,
|
|||
There is no need to use this mechanism for ignoring errors from
|
||||
single asynchronous requests, such as sending a ClientMessage to a
|
||||
window that might no longer exist. Use
|
||||
x_ignore_errors_for_next_request instead. */
|
||||
x_ignore_errors_for_next_request (paired with
|
||||
x_stop_ignoring_errors) instead. */
|
||||
|
||||
void
|
||||
x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
|
||||
|
@ -23004,7 +23016,7 @@ x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler,
|
|||
data->handler = handler;
|
||||
data->handler_data = handler_data;
|
||||
data->prev = x_error_message;
|
||||
data->first_request = NextRequest (dpy);
|
||||
data->first_request = XNextRequest (dpy);
|
||||
x_error_message = data;
|
||||
|
||||
++x_error_message_count;
|
||||
|
@ -23018,17 +23030,21 @@ x_catch_errors (Display *dpy)
|
|||
|
||||
/* Return if errors for REQUEST should be ignored even if there is no
|
||||
error handler applied. */
|
||||
static unsigned long *
|
||||
static struct x_failable_request *
|
||||
x_request_can_fail (struct x_display_info *dpyinfo,
|
||||
unsigned long request)
|
||||
{
|
||||
unsigned long *failable_requests;
|
||||
struct x_failable_request *failable_requests;
|
||||
|
||||
for (failable_requests = dpyinfo->failable_requests;
|
||||
failable_requests < dpyinfo->next_failable_request;
|
||||
failable_requests++)
|
||||
{
|
||||
if (*failable_requests == request)
|
||||
if (X_COMPARE_SERIALS (request, >=,
|
||||
failable_requests->start)
|
||||
&& (!failable_requests->end
|
||||
|| X_COMPARE_SERIALS (request, <=,
|
||||
failable_requests->end)))
|
||||
return failable_requests;
|
||||
}
|
||||
|
||||
|
@ -23040,13 +23056,17 @@ x_request_can_fail (struct x_display_info *dpyinfo,
|
|||
static void
|
||||
x_clean_failable_requests (struct x_display_info *dpyinfo)
|
||||
{
|
||||
unsigned long *first, *last;
|
||||
struct x_failable_request *first, *last;
|
||||
|
||||
last = dpyinfo->next_failable_request;
|
||||
|
||||
for (first = dpyinfo->failable_requests; first < last; first++)
|
||||
{
|
||||
if (*first > LastKnownRequestProcessed (dpyinfo->display))
|
||||
if (X_COMPARE_SERIALS (first->start, >,
|
||||
LastKnownRequestProcessed (dpyinfo->display))
|
||||
|| !first->end
|
||||
|| X_COMPARE_SERIALS (first->end, >,
|
||||
LastKnownRequestProcessed (dpyinfo->display)))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -23061,7 +23081,14 @@ x_clean_failable_requests (struct x_display_info *dpyinfo)
|
|||
static void
|
||||
x_ignore_errors_for_next_request (struct x_display_info *dpyinfo)
|
||||
{
|
||||
unsigned long *request, *max;
|
||||
struct x_failable_request *request, *max;
|
||||
|
||||
if ((dpyinfo->next_failable_request
|
||||
!= dpyinfo->failable_requests)
|
||||
&& (dpyinfo->next_failable_request - 1)->end == 0)
|
||||
/* A new sequence should never be started before an old one
|
||||
finishes. Use `x_catch_errors' to nest error handlers. */
|
||||
emacs_abort ();
|
||||
|
||||
request = dpyinfo->next_failable_request;
|
||||
max = dpyinfo->failable_requests + N_FAILABLE_REQUESTS;
|
||||
|
@ -23071,7 +23098,7 @@ x_ignore_errors_for_next_request (struct x_display_info *dpyinfo)
|
|||
/* There is no point in making this extra sync if all requests
|
||||
are known to have been fully processed. */
|
||||
if ((LastKnownRequestProcessed (dpyinfo->display)
|
||||
!= NextRequest (dpyinfo->display) - 1))
|
||||
!= XNextRequest (dpyinfo->display) - 1))
|
||||
XSync (dpyinfo->display, False);
|
||||
|
||||
x_clean_failable_requests (dpyinfo);
|
||||
|
@ -23083,10 +23110,21 @@ x_ignore_errors_for_next_request (struct x_display_info *dpyinfo)
|
|||
function. */
|
||||
emacs_abort ();
|
||||
|
||||
*request = NextRequest (dpyinfo->display);
|
||||
request->start = XNextRequest (dpyinfo->display);
|
||||
request->end = 0;
|
||||
|
||||
dpyinfo->next_failable_request++;
|
||||
}
|
||||
|
||||
static void
|
||||
x_stop_ignoring_errors (struct x_display_info *dpyinfo)
|
||||
{
|
||||
struct x_failable_request *range;
|
||||
|
||||
range = dpyinfo->next_failable_request - 1;
|
||||
range->end = XNextRequest (dpyinfo->display) - 1;
|
||||
}
|
||||
|
||||
/* Undo the last x_catch_errors call.
|
||||
DPY should be the display that was passed to x_catch_errors.
|
||||
|
||||
|
@ -23134,10 +23172,10 @@ x_uncatch_errors (void)
|
|||
/* There is no point in making this extra sync if all requests
|
||||
are known to have been fully processed. */
|
||||
&& (LastKnownRequestProcessed (x_error_message->dpy)
|
||||
!= NextRequest (x_error_message->dpy) - 1)
|
||||
!= XNextRequest (x_error_message->dpy) - 1)
|
||||
/* Likewise if no request was made since the trap was
|
||||
installed. */
|
||||
&& (NextRequest (x_error_message->dpy)
|
||||
&& (XNextRequest (x_error_message->dpy)
|
||||
> x_error_message->first_request))
|
||||
{
|
||||
XSync (x_error_message->dpy, False);
|
||||
|
@ -23171,8 +23209,8 @@ x_check_errors (Display *dpy, const char *format)
|
|||
/* There is no point in making this extra sync if all requests
|
||||
are known to have been fully processed. */
|
||||
if ((LastKnownRequestProcessed (dpy)
|
||||
!= NextRequest (dpy) - 1)
|
||||
&& (NextRequest (dpy)
|
||||
!= XNextRequest (dpy) - 1)
|
||||
&& (XNextRequest (dpy)
|
||||
> x_error_message->first_request))
|
||||
XSync (dpy, False);
|
||||
|
||||
|
@ -23206,8 +23244,8 @@ x_had_errors_p (Display *dpy)
|
|||
|
||||
/* Make sure to catch any errors incurred so far. */
|
||||
if ((LastKnownRequestProcessed (dpy)
|
||||
!= NextRequest (dpy) - 1)
|
||||
&& (NextRequest (dpy)
|
||||
!= XNextRequest (dpy) - 1)
|
||||
&& (XNextRequest (dpy)
|
||||
> x_error_message->first_request))
|
||||
XSync (dpy, False);
|
||||
|
||||
|
@ -23471,7 +23509,7 @@ x_error_handler (Display *display, XErrorEvent *event)
|
|||
{
|
||||
struct x_error_message_stack *stack;
|
||||
struct x_display_info *dpyinfo;
|
||||
unsigned long *fail, *last;
|
||||
struct x_failable_request *fail, *last;
|
||||
|
||||
#if defined USE_GTK && defined HAVE_GTK3
|
||||
if ((event->error_code == BadMatch
|
||||
|
@ -23488,13 +23526,17 @@ x_error_handler (Display *display, XErrorEvent *event)
|
|||
|
||||
if (fail)
|
||||
{
|
||||
/* Now that this request has been handled, remove it from
|
||||
the list of requests that can fail. */
|
||||
last = dpyinfo->next_failable_request;
|
||||
memmove (&dpyinfo->failable_requests, fail,
|
||||
sizeof *fail * (last - fail));
|
||||
dpyinfo->next_failable_request = (dpyinfo->failable_requests
|
||||
+ (last - fail));
|
||||
/* Now that this request sequence has been fully handled,
|
||||
remove it from the list of requests that can fail. */
|
||||
|
||||
if (event->serial == fail->end)
|
||||
{
|
||||
last = dpyinfo->next_failable_request;
|
||||
memmove (&dpyinfo->failable_requests, fail,
|
||||
sizeof *fail * (last - fail));
|
||||
dpyinfo->next_failable_request = (dpyinfo->failable_requests
|
||||
+ (last - fail));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -24882,11 +24924,9 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
|
|||
&deviceid))
|
||||
{
|
||||
x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f));
|
||||
|
||||
XIWarpPointer (FRAME_X_DISPLAY (f),
|
||||
deviceid, None,
|
||||
FRAME_X_WINDOW (f),
|
||||
0, 0, 0, 0, pix_x, pix_y);
|
||||
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));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -25025,6 +25065,7 @@ x_focus_frame (struct frame *f, bool noactivate)
|
|||
x_ignore_errors_for_next_request (dpyinfo);
|
||||
XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
|
||||
RevertToParent, CurrentTime);
|
||||
x_stop_ignoring_errors (dpyinfo);
|
||||
|
||||
if (!noactivate)
|
||||
x_ewmh_activate_frame (f);
|
||||
|
|
18
src/xterm.h
18
src/xterm.h
|
@ -261,6 +261,16 @@ struct xi_device_t
|
|||
Status x_parse_color (struct frame *f, const char *color_name,
|
||||
XColor *color);
|
||||
|
||||
struct x_failable_request
|
||||
{
|
||||
/* The first request making up this sequence. */
|
||||
unsigned long start;
|
||||
|
||||
/* If this is zero, then the request has not yet been made.
|
||||
Otherwise, this is the request that ends this sequence. */
|
||||
unsigned long end;
|
||||
};
|
||||
|
||||
|
||||
/* For each X display, we have a structure that records
|
||||
information about it. */
|
||||
|
@ -746,12 +756,12 @@ struct x_display_info
|
|||
int screen_mm_width;
|
||||
int screen_mm_height;
|
||||
|
||||
/* Circular buffer of request serials to ignore inside an error
|
||||
handler in increasing order. */
|
||||
unsigned long failable_requests[N_FAILABLE_REQUESTS];
|
||||
/* Circular buffer of request serial ranges to ignore inside an
|
||||
error handler in increasing order. */
|
||||
struct x_failable_request failable_requests[N_FAILABLE_REQUESTS];
|
||||
|
||||
/* Pointer to the next request in `failable_requests'. */
|
||||
unsigned long *next_failable_request;
|
||||
struct x_failable_request *next_failable_request;
|
||||
};
|
||||
|
||||
#ifdef HAVE_X_I18N
|
||||
|
|
Loading…
Add table
Reference in a new issue