diff options
author | Po Lu <luangruo@yahoo.com> | 2022-12-15 20:06:37 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-12-15 20:06:59 +0800 |
commit | db69249b761a80158c1469b2a169d6f5c8509ae1 (patch) | |
tree | 8d2e5f817c399f3b86bb777062651b9bba25faf7 /src/xselect.c | |
parent | 09a985ae9f486b7bba933c17e99eeff22207a87e (diff) | |
download | emacs-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.c | 74 |
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); |