X-Git-Url: http://git.chise.org/gitweb/?p=chise%2Fxemacs-chise.git.1;a=blobdiff_plain;f=src%2Fselect-x.c;h=2ab3161ee2687878ecdb576684d0e8ba01c788ec;hp=2a15974be7a8ab62907e28a8026da44bae05054a;hb=14ac73276fa152e8f0b74602792afc0b9c3236c9;hpb=716cfba952c1dc0d2cf5c968971f3780ba728a89 diff --git a/src/select-x.c b/src/select-x.c index 2a15974..2ab3161 100644 --- a/src/select-x.c +++ b/src/select-x.c @@ -46,7 +46,8 @@ Lisp_Object time_to_lisp (time_t); static void hack_motif_clipboard_selection (Atom selection_atom, Lisp_Object selection_value, Time thyme, Display *display, - Window selecting_window); + Window selecting_window, + int owned_p); #endif #define CUT_BUFFER_SUPPORT @@ -72,7 +73,10 @@ Lisp_Object Vx_sent_selection_hooks; /* If the selection owner takes too long to reply to a selection request, we give up on it. This is in seconds (0 = no timeout). */ -int x_selection_timeout; +Fixnum x_selection_timeout; + +/* Enable motif selection optimizations. */ +int x_selection_strict_motif_ownership; /* Utility functions */ @@ -84,7 +88,7 @@ static void lisp_data_to_selection_data (struct device *, unsigned int *size_ret, int *format_ret); static Lisp_Object selection_data_to_lisp_data (struct device *, - unsigned char *data, + Extbyte *data, size_t size, Atom type, int format); @@ -138,10 +142,8 @@ symbol_to_x_atom (struct device *d, Lisp_Object sym, int only_if_exists) #endif /* CUT_BUFFER_SUPPORT */ { - CONST char *nameext; - TO_EXTERNAL_FORMAT (LISP_STRING, Fsymbol_name (sym), - C_STRING_ALLOCA, nameext, - Qctext); + const char *nameext; + LISP_STRING_TO_EXTERNAL (Fsymbol_name (sym), nameext, Qctext); return XInternAtom (display, nameext, only_if_exists ? True : False); } } @@ -200,11 +202,11 @@ x_atom_to_symbol (struct device *d, Atom atom) /* Do protocol to assert ourself as a selection owner. - Update the Vselection_alist so that we can reply to later requests for - our selection. */ static Lisp_Object -x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value) +x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value, + Lisp_Object how_to_add, Lisp_Object selection_type, + int owned_p) { struct device *d = decode_x_device (Qnil); Display *display = DEVICE_X_DISPLAY (d); @@ -229,14 +231,14 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value) That assumed equivalence of time_t and Time, which is not necessarily the case (e.g. under OSF on the Alphas, where Time is a 64-bit quantity and time_t is a 32-bit quantity). - + Opaque pointers are the clean way to go here. */ selection_time = make_opaque (&thyme, sizeof (thyme)); #ifdef MOTIF_CLIPBOARDS hack_motif_clipboard_selection (selection_atom, selection_value, - thyme, display, selecting_window); + thyme, display, selecting_window, owned_p); #endif return selection_time; } @@ -252,8 +254,8 @@ hack_motif_clipboard_selection (Atom selection_atom, Lisp_Object selection_value, Time thyme, Display *display, - Window selecting_window) - /* Bool owned_p)*/ + Window selecting_window, + int owned_p) { struct device *d = get_device_from_display (display); /* Those Motif wankers can't be bothered to follow the ICCCM, and do @@ -273,7 +275,10 @@ hack_motif_clipboard_selection (Atom selection_atom, to look up the new value, and you can't Copy from a buffer, Paste into a text field, then Copy something else from the buffer and paste it into the text field -- it pastes the first thing again. */ -/* && !owned_p */ + && (!owned_p + /* Selectively re-enable this because for most users its + just too painful - especially over a remote link. */ + || x_selection_strict_motif_ownership) ) { #ifdef MOTIF_INCREMENTAL_CLIPBOARDS_WORK @@ -287,13 +292,13 @@ hack_motif_clipboard_selection (Atom selection_atom, #endif XmString fmh; String encoding = "STRING"; - CONST Extbyte *data = XSTRING_DATA (selection_value); - Extcount bytes = XSTRING_LENGTH (selection_value); + const Bufbyte *data = XSTRING_DATA (selection_value); + Bytecount bytes = XSTRING_LENGTH (selection_value); #ifdef MULE { enum { ASCII, LATIN_1, WORLD } chartypes = ASCII; - CONST Bufbyte *ptr = data, *end = ptr + bytes; + const Bufbyte *ptr = data, *end = ptr + bytes; /* Optimize for the common ASCII case */ while (ptr <= end) { @@ -375,10 +380,34 @@ motif_clipboard_cb (Widget widget, int *data_id, int *private_id, int *reason) { Display *dpy = XtDisplay (widget); Window window = (Window) *private_id; - Lisp_Object selection = assq_no_quit (QCLIPBOARD, Vselection_alist); - if (NILP (selection)) abort (); - selection = XCDR (selection); - if (!STRINGP (selection)) abort (); + Lisp_Object selection = select_convert_out (QCLIPBOARD, Qnil, Qnil); + + /* Whichever lazy git wrote this originally just called ABORT() + when anything didn't go their way... */ + + /* Try some other text types */ + if (NILP (selection)) + selection = select_convert_out (QCLIPBOARD, QSTRING, Qnil); + if (NILP (selection)) + selection = select_convert_out (QCLIPBOARD, QTEXT, Qnil); + if (NILP (selection)) + selection = select_convert_out (QCLIPBOARD, QCOMPOUND_TEXT, Qnil); + + if (CONSP (selection) && SYMBOLP (XCAR (selection)) + && (EQ (XCAR (selection), QSTRING) + || EQ (XCAR (selection), QTEXT) + || EQ (XCAR (selection), QCOMPOUND_TEXT))) + selection = XCDR (selection); + + if (NILP (selection)) + signal_error (Qselection_conversion_error, + build_string ("no selection")); + + if (!STRINGP (selection)) + signal_error (Qselection_conversion_error, + build_string ("couldn't convert selection to string")); + + XmClipboardCopyByName (dpy, window, *data_id, (char *) XSTRING_DATA (selection), XSTRING_LENGTH (selection) + 1, @@ -480,14 +509,41 @@ x_reply_selection_request (XSelectionRequestEvent *event, int format, } else { +#ifndef HAVE_XTREGISTERDRAWABLE + invalid_operation("Copying that much data requires X11R6.", Qunbound); +#else /* Send an INCR selection. */ int prop_id; + Widget widget = FRAME_X_TEXT_WIDGET (XFRAME(DEVICE_SELECTED_FRAME(d))); if (x_window_to_frame (d, window)) /* #### debug */ error ("attempt to transfer an INCR to ourself!"); #if 0 stderr_out ("\nINCR %d\n", bytes_remaining); #endif + /* Tell Xt not to drop PropertyNotify events that arrive for the + target window, rather, pass them to us. This would be a hack, but + the Xt selection routines are broken for our purposes--we can't + pass them callbacks from Lisp, for example. Let's call it a + workaround. + + The call to wait_for_property_change means we can break out of that + function, switch to another frame on the same display (which will + be another Xt widget), select a huge amount of text, and have the + same (foreign) app ask for another incremental selection + transfer. Programming like X11 made sense, would mean that, in that + case, XtRegisterDrawable is called twice with different widgets. + + Since the results of calling XtRegisterDrawable when the drawable + is already registered with another widget are undefined, we want to + avoid that--so, only call it when XtWindowToWidget returns NULL, + which it will only do with a valid Window if it's not already + registered. */ + if (NULL == XtWindowToWidget(display, window)) + { + XtRegisterDrawable(display, (Drawable)window, widget); + } + prop_id = expect_property_change (display, window, reply.property, PropertyDelete); @@ -531,10 +587,14 @@ x_reply_selection_request (XSelectionRequestEvent *event, int format, stderr_out (" INCR done\n"); #endif if (! waiting_for_other_props_on_window (display, window)) - XSelectInput (display, window, 0L); + { + XSelectInput (display, window, 0L); + XtUnregisterDrawable(display, (Drawable)window); + } XChangeProperty (display, window, reply.property, type, format, PropModeReplace, data, 0); +#endif /* HAVE_XTREGISTERDRAWABLE */ } } @@ -546,8 +606,8 @@ void x_handle_selection_request (XSelectionRequestEvent *event) { /* This function can GC */ - struct gcpro gcpro1, gcpro2, gcpro3; - Lisp_Object local_selection_data = Qnil; + struct gcpro gcpro1, gcpro2; + Lisp_Object temp_obj; Lisp_Object selection_symbol; Lisp_Object target_symbol = Qnil; Lisp_Object converted_selection = Qnil; @@ -556,32 +616,27 @@ x_handle_selection_request (XSelectionRequestEvent *event) int count; struct device *d = get_device_from_display (event->display); - GCPRO3 (local_selection_data, converted_selection, target_symbol); + GCPRO2 (converted_selection, target_symbol); selection_symbol = x_atom_to_symbol (d, event->selection); + target_symbol = x_atom_to_symbol (d, event->target); - local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); - -#if 0 - /* This list isn't user-visible, so it can't "go bad." */ - assert (CONSP (local_selection_data)); - assert (CONSP (XCDR (local_selection_data))); - assert (CONSP (XCDR (XCDR (local_selection_data)))); - assert (NILP (XCDR (XCDR (XCDR (local_selection_data))))); - assert (CONSP (XCAR (XCDR (XCDR (local_selection_data))))); - assert (INTP (XCAR (XCAR (XCDR (XCDR (local_selection_data)))))); - assert (INTP (XCDR (XCAR (XCDR (XCDR (local_selection_data)))))); +#if 0 /* #### MULTIPLE doesn't work yet */ + if (EQ (target_symbol, QMULTIPLE)) + target_symbol = fetch_multiple_target (event); #endif - if (NILP (local_selection_data)) + temp_obj = Fget_selection_timestamp (selection_symbol); + + if (NILP (temp_obj)) { - /* Someone asked for the selection, but we don't have it any more. */ + /* We don't appear to have the selection. */ x_decline_selection_request (event); + goto DONE_LABEL; } - local_selection_time = - * (Time *) XOPAQUE_DATA (XCAR (XCDR (XCDR (local_selection_data)))); + local_selection_time = * (Time *) XOPAQUE_DATA (temp_obj); if (event->time != CurrentTime && local_selection_time > event->time) @@ -592,35 +647,36 @@ x_handle_selection_request (XSelectionRequestEvent *event) goto DONE_LABEL; } + converted_selection = select_convert_out (selection_symbol, + target_symbol, Qnil); + + /* #### Is this the right thing to do? I'm no X expert. -- ajh */ + if (NILP (converted_selection)) + { + /* We don't appear to have a selection in that data type. */ + x_decline_selection_request (event); + goto DONE_LABEL; + } + count = specpdl_depth (); record_unwind_protect (x_selection_request_lisp_error, make_opaque_ptr (event)); - target_symbol = x_atom_to_symbol (d, event->target); - -#if 0 /* #### MULTIPLE doesn't work yet */ - if (EQ (target_symbol, QMULTIPLE)) - target_symbol = fetch_multiple_target (event); -#endif - /* Convert lisp objects back into binary data */ - - converted_selection = - get_local_selection (selection_symbol, target_symbol); + { + unsigned char *data; + unsigned int size; + int format; + Atom type; + lisp_data_to_selection_data (d, converted_selection, + &data, &type, &size, &format); + + x_reply_selection_request (event, format, data, size, type); + successful_p = Qt; + /* Tell x_selection_request_lisp_error() it's cool. */ + event->type = 0; + xfree (data); + } - if (! NILP (converted_selection)) - { - unsigned char *data; - unsigned int size; - int format; - Atom type; - lisp_data_to_selection_data (d, converted_selection, - &data, &type, &size, &format); - - x_reply_selection_request (event, format, data, size, type); - successful_p = Qt; - /* Tell x_selection_request_lisp_error() it's cool. */ event->type = 0; - xfree (data); - } unbind_to (count, Qnil); DONE_LABEL: @@ -629,17 +685,15 @@ x_handle_selection_request (XSelectionRequestEvent *event) /* Let random lisp code notice that the selection has been asked for. */ { - Lisp_Object rest; Lisp_Object val = Vx_sent_selection_hooks; if (!UNBOUNDP (val) && !NILP (val)) { + Lisp_Object rest; if (CONSP (val) && !EQ (XCAR (val), Qlambda)) for (rest = val; !NILP (rest); rest = Fcdr (rest)) - call3 (Fcar(rest), selection_symbol, target_symbol, - successful_p); + call3 (Fcar (rest), selection_symbol, target_symbol, successful_p); else - call3 (val, selection_symbol, target_symbol, - successful_p); + call3 (val, selection_symbol, target_symbol, successful_p); } } } @@ -655,18 +709,18 @@ x_handle_selection_clear (XSelectionClearEvent *event) Atom selection = event->selection; Time changed_owner_time = event->time; - Lisp_Object selection_symbol, local_selection_data; + Lisp_Object selection_symbol, local_selection_time_lisp; Time local_selection_time; selection_symbol = x_atom_to_symbol (d, selection); - local_selection_data = assq_no_quit (selection_symbol, Vselection_alist); + local_selection_time_lisp = Fget_selection_timestamp (selection_symbol); - /* Well, we already believe that we don't own it, so that's just fine. */ - if (NILP (local_selection_data)) return; + /* We don't own the selection, so that's fine. */ + if (NILP (local_selection_time_lisp)) + return; - local_selection_time = - * (Time *) XOPAQUE_DATA (XCAR (XCDR (XCDR (local_selection_data)))); + local_selection_time = * (Time *) XOPAQUE_DATA (local_selection_time_lisp); /* This SelectionClear is for a selection that we no longer own, so we can disregard it. (That is, we have reasserted the selection since this @@ -675,7 +729,7 @@ x_handle_selection_clear (XSelectionClearEvent *event) if (changed_owner_time != CurrentTime && local_selection_time > changed_owner_time) return; - + handle_selection_clear (selection_symbol); } @@ -920,20 +974,24 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type) unbind_to (speccount, Qnil); /* otherwise, the selection is waiting for us on the requested property. */ - return - x_get_window_property_as_lisp_data (display, requestor_window, - target_property, target_type, - selection_atom); + + return select_convert_in (selection_symbol, + target_type, + x_get_window_property_as_lisp_data(display, + requestor_window, + target_property, + target_type, + selection_atom)); } static void x_get_window_property (Display *display, Window window, Atom property, - unsigned char **data_ret, int *bytes_ret, + Extbyte **data_ret, int *bytes_ret, Atom *actual_type_ret, int *actual_format_ret, unsigned long *actual_size_ret, int delete_p) { - int total_size; + size_t total_size; unsigned long bytes_remaining; int offset = 0; unsigned char *tmp_data = 0; @@ -964,7 +1022,7 @@ x_get_window_property (Display *display, Window window, Atom property, } total_size = bytes_remaining + 1; - *data_ret = (unsigned char *) xmalloc (total_size); + *data_ret = (Extbyte *) xmalloc (total_size); /* Now read, until we've gotten it all. */ while (bytes_remaining) @@ -1001,7 +1059,7 @@ receive_incremental_selection (Display *display, Window window, Atom property, /* this one is for error messages only */ Lisp_Object target_type, unsigned int min_size_bytes, - unsigned char **data_ret, int *size_bytes_ret, + Extbyte **data_ret, int *size_bytes_ret, Atom *type_ret, int *format_ret, unsigned long *size_ret) { @@ -1009,7 +1067,7 @@ receive_incremental_selection (Display *display, Window window, Atom property, int offset = 0; int prop_id; *size_bytes_ret = min_size_bytes; - *data_ret = (unsigned char *) xmalloc (*size_bytes_ret); + *data_ret = (Extbyte *) xmalloc (*size_bytes_ret); #if 0 stderr_out ("\nread INCR %d\n", min_size_bytes); #endif @@ -1025,7 +1083,7 @@ receive_incremental_selection (Display *display, Window window, Atom property, PropertyNewValue); while (1) { - unsigned char *tmp_data; + Extbyte *tmp_data; int tmp_size_bytes; wait_for_property_change (prop_id); /* expect it again immediately, because x_get_window_property may @@ -1057,7 +1115,7 @@ receive_incremental_selection (Display *display, Window window, Atom property, *size_bytes_ret, offset + tmp_size_bytes); #endif *size_bytes_ret = offset + tmp_size_bytes; - *data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret); + *data_ret = (Extbyte *) xrealloc (*data_ret, *size_bytes_ret); } memcpy ((*data_ret) + offset, tmp_data, tmp_size_bytes); offset += tmp_size_bytes; @@ -1078,7 +1136,7 @@ x_get_window_property_as_lisp_data (Display *display, Atom actual_type; int actual_format; unsigned long actual_size; - unsigned char *data = NULL; + Extbyte *data = NULL; int bytes = 0; Lisp_Object val; struct device *d = get_device_from_display (display); @@ -1123,6 +1181,9 @@ x_get_window_property_as_lisp_data (Display *display, return val; } +/* #### These are going to move into Lisp code(!) with the aid of + some new functions I'm working on - ajh */ + /* These functions convert from the selection data read from the server into something that we can use from elisp, and vice versa. @@ -1157,7 +1218,7 @@ x_get_window_property_as_lisp_data (Display *display, static Lisp_Object selection_data_to_lisp_data (struct device *d, - unsigned char *data, + Extbyte *data, size_t size, Atom type, int format) @@ -1266,7 +1327,7 @@ lisp_data_to_selection_data (struct device *d, } else if (STRINGP (obj)) { - CONST Extbyte *extval; + const Extbyte *extval; Extcount extvallen; TO_EXTERNAL_FORMAT (LISP_STRING, obj, @@ -1286,7 +1347,7 @@ lisp_data_to_selection_data (struct device *d, { Bufbyte buf[MAX_EMCHAR_LEN]; Bytecount len; - CONST Extbyte *extval; + const Extbyte *extval; Extcount extvallen; *format_ret = 8; @@ -1467,7 +1528,8 @@ x_disown_selection (Lisp_Object selection, Lisp_Object timeval) } static Lisp_Object -x_selection_exists_p (Lisp_Object selection) +x_selection_exists_p (Lisp_Object selection, + Lisp_Object selection_type) { struct device *d = decode_x_device (Qnil); Display *dpy = DEVICE_X_DISPLAY (d); @@ -1484,7 +1546,7 @@ static int cut_buffers_initialized; /* Whether we're sure they all exist */ static void initialize_cut_buffers (Display *display, Window window) { - static unsigned CONST char * CONST data = (unsigned CONST char *) ""; + static unsigned const char * const data = (unsigned const char *) ""; #define FROB(atom) XChangeProperty (display, window, atom, XA_STRING, 8, \ PropModeAppend, data, 0) FROB (XA_CUT_BUFFER0); @@ -1521,7 +1583,7 @@ Return the value of the named CUTBUFFER (typically CUT_BUFFER0). Display *display = DEVICE_X_DISPLAY (d); Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */ Atom cut_buffer_atom; - unsigned char *data; + Extbyte *data; int bytes; Atom type; int format; @@ -1563,12 +1625,12 @@ Set the value of the named CUTBUFFER (typically CUT_BUFFER0) to STRING. Display *display = DEVICE_X_DISPLAY (d); Window window = RootWindow (display, 0); /* Cutbuffers are on frame 0 */ Atom cut_buffer_atom; - CONST Extbyte *data = XSTRING_DATA (string); - Extcount bytes = XSTRING_LENGTH (string); - Extcount bytes_remaining; + const Bufbyte *data = XSTRING_DATA (string); + Bytecount bytes = XSTRING_LENGTH (string); + Bytecount bytes_remaining; int max_bytes = SELECTION_QUANTUM (display); #ifdef MULE - CONST Bufbyte *ptr, *end; + const Bufbyte *ptr, *end; enum { ASCII, LATIN_1, WORLD } chartypes = ASCII; #endif @@ -1597,6 +1659,14 @@ Set the value of the named CUTBUFFER (typically CUT_BUFFER0) to STRING. continue; } +#ifdef UTF2000 + if ((*ptr) <= 0xC3) + { + chartypes = LATIN_1; + ptr += 2; + continue; + } +#else if ((*ptr) == LEADING_BYTE_LATIN_ISO8859_1 || (*ptr) == LEADING_BYTE_CONTROL_1) { @@ -1604,6 +1674,7 @@ Set the value of the named CUTBUFFER (typically CUT_BUFFER0) to STRING. ptr += 2; continue; } +#endif chartypes = WORLD; break; @@ -1749,6 +1820,17 @@ A value of 0 means wait as long as necessary. This is initialized from the \"*selectionTimeout\" resource (which is expressed in milliseconds). */ ); x_selection_timeout = 0; + + DEFVAR_BOOL ("x-selection-strict-motif-ownership", &x_selection_strict_motif_ownership /* +*If nil and XEmacs already owns the clipboard, don't own it again in the +Motif way. Owning the selection on the Motif way does a huge amount of +X protocol, and it makes killing text incredibly slow when using an +X terminal. However, when enabled Motif text fields don't bother to look up +the new value, and you can't Copy from a buffer, Paste into a text +field, then Copy something else from the buffer and paste it into the +text field; it pastes the first thing again. +*/ ); + x_selection_strict_motif_ownership = 1; } void @@ -1767,5 +1849,7 @@ Xatoms_of_select_x (struct device *d) DEVICE_XATOM_NULL (d) = XInternAtom (D, "NULL", False); DEVICE_XATOM_ATOM_PAIR (d) = XInternAtom (D, "ATOM_PAIR", False); DEVICE_XATOM_COMPOUND_TEXT (d) = XInternAtom (D, "COMPOUND_TEXT", False); + + /* #### I don't like the looks of this... what is it for? - ajh */ DEVICE_XATOM_EMACS_TMP (d) = XInternAtom (D, "_EMACS_TMP_", False); }