]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix error handling for XCB Xlib
authorPo Lu <luangruo@yahoo.com>
Sat, 2 Jul 2022 13:55:22 +0000 (21:55 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 2 Jul 2022 13:56:59 +0000 (21:56 +0800)
* 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.

src/xterm.c
src/xterm.h

index 0c695324f3b09b25e29fbccfb39133ca7c159084..7ab22f256f6dbe8846878112eb1cf8f286e756a9 100644 (file)
@@ -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);
index eee76724268152e34186045202864c36aa64f910..7c09073d765d7ebaba2c0f8b965b9e08dcb59787 100644 (file)
@@ -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;
+};
+
 \f
 /* 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