Mercurial > emacs
changeset 4373:02a515f35abc
(prop_location_identifier): Was named prop_location_tick.
(property_change_reply_identifier): Renamed from ...-tick.
(struct prop_location): Field `identifier' renamed from `tick'.
Various functions changed accordingly.
(x_handle_selection_request): Delete local struct var `reply'.
(wait_for_property_change_unwind): New function.
(wait_for_property_change): Add unwind protect.
(wait_for_property_change): Eventually time out with error.
(x_reply_selection_request): XFlushQueue and UNBLOCK_INPUT
before calling wait_for_property_change.
(x_get_window_property): Simplify input blocking/unblocking.
Don't delete the property here.
(receive_incremental_selection): Delete property here.
Call XSelectInput to enable and disable PropertyChangeMask.
(x_get_window_property_as_lisp_data): And here.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Sat, 31 Jul 1993 05:55:52 +0000 |
parents | 189b84c7dbc5 |
children | 1a64d641cea4 |
files | src/xselect.c |
diffstat | 1 files changed, 93 insertions(+), 64 deletions(-) [+] |
line wrap: on
line diff
--- a/src/xselect.c Sat Jul 31 05:53:23 1993 +0000 +++ b/src/xselect.c Sat Jul 31 05:55:52 1993 +0000 @@ -471,7 +471,6 @@ /* #### XChangeProperty can generate BadAlloc, and we must handle it! */ - BLOCK_INPUT; /* Store the data on the requested property. If the selection is large, only store the first N bytes of it. */ @@ -482,16 +481,21 @@ #if 0 fprintf (stderr,"\nStoring all %d\n", bytes_remaining); #endif + BLOCK_INPUT; XChangeProperty (display, window, reply.property, type, format, PropModeReplace, data, size); /* At this point, the selection was successfully stored; ack it. */ - (void) XSendEvent (display, window, False, 0L, (XEvent *) &reply); + XSendEvent (display, window, False, 0L, (XEvent *) &reply); + XFlushQueue (); + UNBLOCK_INPUT; } else { /* Send an INCR selection. */ int prop_id; + BLOCK_INPUT; + if (x_window_to_frame (window)) /* #### debug */ error ("attempt to transfer an INCR to ourself!"); #if 0 @@ -506,6 +510,8 @@ XSelectInput (display, window, PropertyChangeMask); /* Tell 'em the INCR data is there... */ (void) XSendEvent (display, window, False, 0L, (XEvent *) &reply); + XFlushQueue (); + UNBLOCK_INPUT; /* First, wait for the requestor to ack by deleting the property. This can run random lisp code (process handlers) or signal. */ @@ -516,6 +522,9 @@ int i = ((bytes_remaining < max_bytes) ? bytes_remaining : max_bytes); + + BLOCK_INPUT; + prop_id = expect_property_change (display, window, reply.property, PropertyDelete); #if 0 @@ -526,6 +535,8 @@ PropModeAppend, data, i / format_bytes); bytes_remaining -= i; data += i; + XFlushQueue (); + UNBLOCK_INPUT; /* Now wait for the requestor to ack this chunk by deleting the property. This can run random lisp code or signal. @@ -537,14 +548,15 @@ #if 0 fprintf (stderr," INCR done\n"); #endif + BLOCK_INPUT; if (! waiting_for_other_props_on_window (display, window)) XSelectInput (display, window, 0L); XChangeProperty (display, window, reply.property, type, format, PropModeReplace, data, 0); + XFlushQueue (); + UNBLOCK_INPUT; } - XFlushQueue (); - UNBLOCK_INPUT; } /* Handle a SelectionRequest event EVENT. @@ -555,7 +567,6 @@ struct input_event *event; { struct gcpro gcpro1, gcpro2, gcpro3; - XSelectionEvent reply; Lisp_Object local_selection_data = Qnil; Lisp_Object selection_symbol; Lisp_Object target_symbol = Qnil; @@ -566,35 +577,10 @@ GCPRO3 (local_selection_data, converted_selection, target_symbol); - reply.type = SelectionNotify; /* Construct the reply event */ - reply.display = SELECTION_EVENT_DISPLAY (event); - reply.requestor = SELECTION_EVENT_REQUESTOR (event); - reply.selection = SELECTION_EVENT_SELECTION (event); - reply.time = SELECTION_EVENT_TIME (event); - reply.target = SELECTION_EVENT_TARGET (event); - reply.property = SELECTION_EVENT_PROPERTY (event); - if (reply.property == None) - reply.property = reply.target; - - selection_symbol = x_atom_to_symbol (reply.display, + selection_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event), SELECTION_EVENT_SELECTION (event)); local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); - -#if 0 -# define CDR(x) (XCONS (x)->cdr) -# define CAR(x) (XCONS (x)->car) - /* This list isn't user-visible, so it can't "go bad." */ - if (!CONSP (local_selection_data)) abort (); - if (!CONSP (CDR (local_selection_data))) abort (); - if (!CONSP (CDR (CDR (local_selection_data)))) abort (); - if (!NILP (CDR (CDR (CDR (local_selection_data))))) abort (); - if (!CONSP (CAR (CDR (CDR (local_selection_data))))) abort (); - if (!INTEGERP (CAR (CAR (CDR (CDR (local_selection_data)))))) abort (); - if (!INTEGERP (CDR (CAR (CDR (CDR (local_selection_data)))))) abort (); -# undef CAR -# undef CDR -#endif if (NILP (local_selection_data)) { @@ -621,7 +607,7 @@ x_selection_current_request = event; record_unwind_protect (x_selection_request_lisp_error, Qnil); - target_symbol = x_atom_to_symbol (reply.display, + target_symbol = x_atom_to_symbol (SELECTION_EVENT_DISPLAY (event), SELECTION_EVENT_TARGET (event)); #if 0 /* #### MULTIPLE doesn't work yet */ @@ -642,7 +628,8 @@ Atom type; int nofree; - lisp_data_to_selection_data (reply.display, converted_selection, + lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event), + converted_selection, &data, &type, &size, &format, &nofree); x_reply_selection_request (event, format, data, size, type); @@ -733,16 +720,16 @@ be servicing multiple INCR selection requests simultaneously.) I haven't actually tested that yet. */ -static int prop_location_tick; +static int prop_location_identifier; static Lisp_Object property_change_reply; -static int property_change_reply_tick; +static int property_change_reply_identifier; /* Keep a list of the property changes that are awaited. */ struct prop_location { - int tick; + int identifier; Display *display; Window window; Atom property; @@ -753,12 +740,12 @@ static struct prop_location *property_change_wait_list; static int -property_deleted_p (tick) - void *tick; +property_deleted_p (identifier) + void *identifier; { struct prop_location *rest = property_change_wait_list; while (rest) - if (rest->tick == (int) tick) + if (rest->identifier == (int) identifier) return 0; else rest = rest->next; @@ -796,27 +783,27 @@ { struct prop_location *pl = (struct prop_location *) xmalloc (sizeof (struct prop_location)); - pl->tick = ++prop_location_tick; + pl->identifier = ++prop_location_identifier; pl->display = display; pl->window = window; pl->property = property; pl->desired_state = state; pl->next = property_change_wait_list; property_change_wait_list = pl; - return pl->tick; + return pl->identifier; } /* Delete an entry from the list of property changes we are waiting for. - TICK is the number that uniquely identifies the entry. */ + IDENTIFIER is the number that uniquely identifies the entry. */ static void -unexpect_property_change (tick) - int tick; +unexpect_property_change (identifier) + int identifier; { struct prop_location *prev = 0, *rest = property_change_wait_list; while (rest) { - if (rest->tick == tick) + if (rest->identifier == identifier) { if (prev) prev->next = rest->next; @@ -830,15 +817,38 @@ } } +/* Remove the property change expectation element for IDENTIFIER. */ + +static Lisp_Object +wait_for_property_change_unwind (identifierval) + Lisp_Object identifierval; +{ + unexpect_property_change (XFASTINT (identifierval)); +} + /* Actually wait for a property change. - TICK should be the value that expect_property_change returned. */ + IDENTIFIER should be the value that expect_property_change returned. */ static void -wait_for_property_change (tick) +wait_for_property_change (identifier) { + int secs, usecs; + int count = specpdl_ptr - specpdl; + + /* Make sure to do unexpect_property_change if we quit or err. */ + record_unwind_protect (wait_for_property_change_unwind, + make_number (identifier)); + XCONS (property_change_reply)->car = Qnil; - property_change_reply_tick = tick; - wait_reading_process_input (0, 0, property_change_reply, 0); + property_change_reply_identifier = identifier; + secs = x_selection_timeout / 1000; + usecs = (x_selection_timeout % 1000) * 1000; + wait_reading_process_input (secs, usecs, property_change_reply, 0); + + if (NILP (XCONS (property_change_reply)->car)) + error ("timed out waiting for property-notify event"); + + unbind_to (count, Qnil); } /* Called from XTread_socket in response to a PropertyNotify event. */ @@ -865,7 +875,7 @@ /* If this is the one wait_for_property_change is waiting for, tell it to wake up. */ - if (rest->tick == property_change_reply_tick) + if (rest->identifier == property_change_reply_identifier) XCONS (property_change_reply)->car = Qt; if (prev) @@ -1024,20 +1034,18 @@ actual_type_ret, actual_format_ret, actual_size_ret, &bytes_remaining, &tmp_data); - UNBLOCK_INPUT; if (result != Success) { + UNBLOCK_INPUT; *data_ret = 0; *bytes_ret = 0; return; } - BLOCK_INPUT; - XFree ((char *) tmp_data); - UNBLOCK_INPUT; + xfree ((char *) tmp_data); if (*actual_type_ret == None || *actual_format_ret == 0) { - if (delete_p) XDeleteProperty (display, window, property); + UNBLOCK_INPUT; return; } @@ -1045,7 +1053,6 @@ *data_ret = (unsigned char *) xmalloc (total_size); /* Now read, until weve gotten it all. */ - BLOCK_INPUT; while (bytes_remaining) { #if 0 @@ -1054,7 +1061,7 @@ result = XGetWindowProperty (display, window, property, offset/4, buffer_size/4, - (delete_p ? True : False), + False, AnyPropertyType, actual_type_ret, actual_format_ret, actual_size_ret, &bytes_remaining, &tmp_data); @@ -1069,8 +1076,10 @@ *actual_size_ret *= *actual_format_ret / 8; bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret); offset += *actual_size_ret; - XFree ((char *) tmp_data); + xfree ((char *) tmp_data); } + + XFlushQueue (); UNBLOCK_INPUT; *bytes_ret = offset; } @@ -1097,16 +1106,23 @@ #if 0 fprintf (stderr, "\nread INCR %d\n", min_size_bytes); #endif - /* At this point, we have read an INCR property, and deleted it (which - is how we ack its receipt: the sending window will be selecting - PropertyNotify events on our window to notice this.) + + /* At this point, we have read an INCR property. + Delete the property to ack it. + (But first, prepare to receive the next event in this handshake.) Now, we must loop, waiting for the sending window to put a value on that property, then reading the property, then deleting it to ack. We are done when the sender places a property of length 0. */ + BLOCK_INPUT; + XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask); + XDeleteProperty (display, window, property); prop_id = expect_property_change (display, window, property, PropertyNewValue); + XFlushQueue (); + UNBLOCK_INPUT; + while (1) { unsigned char *tmp_data; @@ -1116,8 +1132,6 @@ .. no it wont, I dont get it. .. Ok, I get it now, the Xt code that implements INCR is broken. */ - prop_id = expect_property_change (display, window, property, - PropertyNewValue); x_get_window_property (display, window, property, &tmp_data, &tmp_size_bytes, type_ret, format_ret, size_ret, 1); @@ -1127,10 +1141,20 @@ #if 0 fprintf (stderr, " read INCR done\n"); #endif + if (! waiting_for_other_props_on_window (display, window)) + XSelectInput (display, window, STANDARD_EVENT_SET); unexpect_property_change (prop_id); if (tmp_data) xfree (tmp_data); break; } + + BLOCK_INPUT; + XDeleteProperty (display, window, property); + prop_id = expect_property_change (display, window, property, + PropertyNewValue); + XFlushQueue (); + UNBLOCK_INPUT; + #if 0 fprintf (stderr, " read INCR %d\n", tmp_size_bytes); #endif @@ -1206,6 +1230,11 @@ &actual_size); } + BLOCK_INPUT; + XDeleteProperty (display, window, property); + XFlushQueue (); + UNBLOCK_INPUT; + /* It's been read. Now convert it to a lisp object in some semi-rational manner. */ val = selection_data_to_lisp_data (display, data, bytes, @@ -1899,7 +1928,7 @@ reading_which_selection = 0; property_change_wait_list = 0; - prop_location_tick = 0; + prop_location_identifier = 0; property_change_reply = Fcons (Qnil, Qnil); staticpro (&property_change_reply);