summaryrefslogtreecommitdiff
path: root/src/xselect.c
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2022-12-15 20:06:37 +0800
committerPo Lu <luangruo@yahoo.com>2022-12-15 20:06:59 +0800
commitdb69249b761a80158c1469b2a169d6f5c8509ae1 (patch)
tree8d2e5f817c399f3b86bb777062651b9bba25faf7 /src/xselect.c
parent09a985ae9f486b7bba933c17e99eeff22207a87e (diff)
downloademacs-db69249b761a80158c1469b2a169d6f5c8509ae1.tar.gz
Handle selection transfer errors earlier
* src/xselect.c (x_decline_selection_request, struct transfer) (struct x_selection_request, x_cancel_selection_transfer) (x_start_selection_transfer, x_continue_selection_transfer): Give the right serial to x_ignore_errors_for_next_request. (x_handle_selection_error): New function. (x_reply_selection_request): Give the right serial to x_ignore_errors_for_next_request. * src/xterm.c (x_ignore_errors_for_next_request): New arg `selection_serial'. All callers changed. (x_error_handler): Call selection error handler. * src/xterm.h (struct x_failable_request): New field `selection_serial'.
Diffstat (limited to 'src/xselect.c')
-rw-r--r--src/xselect.c74
1 files changed, 65 insertions, 9 deletions
diff --git a/src/xselect.c b/src/xselect.c
index 191f0770337..05548be311f 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -460,7 +460,7 @@ x_decline_selection_request (struct selection_input_event *event)
/* The reason for the error may be that the receiver has
died in the meantime. Handle that case. */
block_input ();
- x_ignore_errors_for_next_request (dpyinfo);
+ x_ignore_errors_for_next_request (dpyinfo, 0);
XSendEvent (dpyinfo->display, reply->requestor,
False, 0, &reply_base);
x_stop_ignoring_errors (dpyinfo);
@@ -523,6 +523,9 @@ struct transfer
/* The atimer for the timeout. */
struct atimer *timeout;
+ /* The selection serial. */
+ unsigned int serial;
+
/* Flags. */
int flags;
};
@@ -543,6 +546,9 @@ struct x_selection_request
/* Linked list of the above (in support of MULTIPLE targets). */
struct selection_data *converted_selections;
+ /* The serial used to handle X errors. */
+ unsigned int serial;
+
/* Whether or not conversion was successful. */
bool converted;
};
@@ -557,6 +563,10 @@ struct x_selection_request *selection_request_stack;
struct transfer outstanding_transfers;
+/* A counter for selection serials. */
+
+static unsigned int selection_serial;
+
struct prop_location
@@ -793,7 +803,7 @@ x_cancel_selection_transfer (struct transfer *transfer)
/* Ignore errors generated by the change window request in case
the window has gone away. */
block_input ();
- x_ignore_errors_for_next_request (transfer->dpyinfo);
+ x_ignore_errors_for_next_request (transfer->dpyinfo, 0);
XSelectInput (transfer->dpyinfo->display,
transfer->requestor, NoEventMask);
x_stop_ignoring_errors (transfer->dpyinfo);
@@ -885,12 +895,23 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor,
transfer->next->last = transfer;
transfer->last->next = transfer;
+ /* Find a valid (non-zero) serial for the selection transfer.
+ Any asynchronously trapped errors will then cause the
+ selection transfer to be cancelled. */
+ transfer->serial = (++selection_serial
+ ? selection_serial
+ : ++selection_serial);
+
/* Now, write the INCR property to begin incremental selection
transfer. offset is currently 0. */
data_size = selection_data_size (&transfer->data);
- x_ignore_errors_for_next_request (dpyinfo);
+ /* Set SELECTED_EVENTS before the actual XSelectInput
+ request. */
+ transfer->flags |= SELECTED_EVENTS;
+
+ x_ignore_errors_for_next_request (dpyinfo, transfer->serial);
XChangeProperty (dpyinfo->display, requestor,
transfer->data.property,
dpyinfo->Xatom_INCR, 32, PropModeReplace,
@@ -903,7 +924,6 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor,
manager) asks Emacs for selection data, things will subtly go
wrong. */
XSelectInput (dpyinfo->display, requestor, PropertyChangeMask);
- transfer->flags |= SELECTED_EVENTS;
x_stop_ignoring_errors (dpyinfo);
}
else
@@ -917,7 +937,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor,
" %zu elements directly to requestor window",
remaining);
- x_ignore_errors_for_next_request (dpyinfo);
+ x_ignore_errors_for_next_request (dpyinfo, 0);
XChangeProperty (dpyinfo->display, requestor,
transfer->data.property,
transfer->data.type,
@@ -951,7 +971,7 @@ x_continue_selection_transfer (struct transfer *transfer)
signal EOF and remove the transfer. */
TRACE0 (" x_continue_selection_transfer: writing 0 items to"
" indicate EOF");
- x_ignore_errors_for_next_request (transfer->dpyinfo);
+ x_ignore_errors_for_next_request (transfer->dpyinfo, 0);
XChangeProperty (transfer->dpyinfo->display,
transfer->requestor,
transfer->data.property,
@@ -970,7 +990,10 @@ x_continue_selection_transfer (struct transfer *transfer)
"; current offset is %zu", remaining, transfer->offset);
eassert (remaining <= INT_MAX);
- x_ignore_errors_for_next_request (transfer->dpyinfo);
+ transfer->offset += remaining;
+
+ x_ignore_errors_for_next_request (transfer->dpyinfo,
+ transfer->serial);
XChangeProperty (transfer->dpyinfo->display,
transfer->requestor,
transfer->data.property,
@@ -979,7 +1002,6 @@ x_continue_selection_transfer (struct transfer *transfer)
PropModeReplace, xdata,
remaining);
x_stop_ignoring_errors (transfer->dpyinfo);
- transfer->offset += remaining;
}
}
@@ -999,6 +1021,40 @@ x_remove_selection_transfers (struct x_display_info *dpyinfo)
}
}
+/* Handle an X error generated trying to write to a window. SERIAL
+ identifies the outstanding incremental selection transfer, which is
+ immediately removed. */
+
+void
+x_handle_selection_error (unsigned int serial, XErrorEvent *error)
+{
+ struct transfer *next, *last;
+
+ if (error->error_code != BadWindow)
+ /* The error was not caused by the window going away. As such,
+ Emacs must deselect for PropertyChangeMask from the requestor
+ window, which isn't safe here. Return and wait for the timeout
+ to run. */
+ return;
+
+ next = outstanding_transfers.next;
+ while (next != &outstanding_transfers)
+ {
+ last = next;
+ next = next->next;
+
+ if (last->serial == serial)
+ {
+ /* Clear SELECTED_EVENTS, so x_cancel_selection_transfer
+ will not make X requests. That is unsafe inside an error
+ handler, and unnecessary because the window has already
+ gone. */
+ last->flags &= ~SELECTED_EVENTS;
+ x_cancel_selection_transfer (last);
+ }
+ }
+}
+
/* Send the reply to a selection request event EVENT. */
static void
@@ -1033,7 +1089,7 @@ x_reply_selection_request (struct selection_input_event *event,
/* Send the SelectionNotify event to the requestor, telling it that
the property data has arrived. */
- x_ignore_errors_for_next_request (dpyinfo);
+ x_ignore_errors_for_next_request (dpyinfo, 0);
XSendEvent (dpyinfo->display, SELECTION_EVENT_REQUESTOR (event),
False, NoEventMask, &message);
x_stop_ignoring_errors (dpyinfo);