X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/0158abbc71d93126d98c7a534013e5dc735dc438..eddd51c2807805e47aa70008234111b601e9a050:/src/xselect.c diff --git a/src/xselect.c b/src/xselect.c index ead207aedf..20a977b8fa 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -1,5 +1,5 @@ /* X Selection processing for Emacs. - Copyright (C) 1993, 1994, 1995 Free Software Foundation. + Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation. This file is part of GNU Emacs. @@ -27,8 +27,8 @@ Boston, MA 02111-1307, USA. */ #include "dispextern.h" /* frame.h seems to want this */ #include "frame.h" /* Need this to get the X window of selected_frame */ #include "blockinput.h" - -#define xfree free +#include "charset.h" +#include "coding.h" #define CUT_BUFFER_SUPPORT @@ -36,6 +36,8 @@ Lisp_Object QPRIMARY, QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP, QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL, QATOM_PAIR; +Lisp_Object QCOMPOUND_TEXT; /* This is a type of selection. */ + #ifdef CUT_BUFFER_SUPPORT Lisp_Object QCUT_BUFFER0, QCUT_BUFFER1, QCUT_BUFFER2, QCUT_BUFFER3, QCUT_BUFFER4, QCUT_BUFFER5, QCUT_BUFFER6, QCUT_BUFFER7; @@ -59,7 +61,8 @@ static Lisp_Object Vx_sent_selection_hooks; #endif /* The timestamp of the last input event Emacs received from the X server. */ -unsigned long last_event_timestamp; +/* Defined in keyboard.c. */ +extern unsigned long last_event_timestamp; /* This is an association list whose elements are of the form ( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME) @@ -111,6 +114,7 @@ symbol_to_x_atom (dpyinfo, display, sym) if (EQ (sym, QCLIPBOARD)) return dpyinfo->Xatom_CLIPBOARD; if (EQ (sym, QTIMESTAMP)) return dpyinfo->Xatom_TIMESTAMP; if (EQ (sym, QTEXT)) return dpyinfo->Xatom_TEXT; + if (EQ (sym, QCOMPOUND_TEXT)) return dpyinfo->Xatom_COMPOUND_TEXT; if (EQ (sym, QDELETE)) return dpyinfo->Xatom_DELETE; if (EQ (sym, QMULTIPLE)) return dpyinfo->Xatom_MULTIPLE; if (EQ (sym, QINCR)) return dpyinfo->Xatom_INCR; @@ -189,6 +193,8 @@ x_atom_to_symbol (dpyinfo, display, atom) return QTIMESTAMP; if (atom == dpyinfo->Xatom_TEXT) return QTEXT; + if (atom == dpyinfo->Xatom_COMPOUND_TEXT) + return QCOMPOUND_TEXT; if (atom == dpyinfo->Xatom_DELETE) return QDELETE; if (atom == dpyinfo->Xatom_MULTIPLE) @@ -230,15 +236,16 @@ x_own_selection (selection_name, selection_value) Time time = last_event_timestamp; Atom selection_atom; struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (selected_frame); + int count; CHECK_SYMBOL (selection_name, 0); selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name); BLOCK_INPUT; - x_catch_errors (display); + count = x_catch_errors (display); XSetSelectionOwner (display, selection_atom, selecting_window, time); x_check_errors (display, "Can't set selection: %s"); - x_uncatch_errors (display); + x_uncatch_errors (display, count); UNBLOCK_INPUT; /* Now update the local cache */ @@ -505,6 +512,7 @@ x_reply_selection_request (event, format, data, size, type) int format_bytes = format/8; int max_bytes = SELECTION_QUANTUM (display); struct x_display_info *dpyinfo = x_display_info_for_display (display); + int count; if (max_bytes > MAX_SELECTION_QUANTUM) max_bytes = MAX_SELECTION_QUANTUM; @@ -521,7 +529,7 @@ x_reply_selection_request (event, format, data, size, type) /* #### XChangeProperty can generate BadAlloc, and we must handle it! */ BLOCK_INPUT; - x_catch_errors (display); + count = x_catch_errors (display); /* Store the data on the requested property. If the selection is large, only store the first N bytes of it. @@ -543,7 +551,6 @@ x_reply_selection_request (event, format, data, size, type) /* Send an INCR selection. */ struct prop_location *wait_object; int had_errors; - int count = specpdl_ptr - specpdl; Lisp_Object frame; frame = some_frame_on_display (dpyinfo); @@ -625,12 +632,10 @@ x_reply_selection_request (event, format, data, size, type) XChangeProperty (display, window, reply.property, type, format, PropModeReplace, data, 0); - - unbind_to (count, Qnil); } XFlush (display); - x_uncatch_errors (display); + x_uncatch_errors (display, count); UNBLOCK_INPUT; } @@ -721,10 +726,10 @@ x_handle_selection_request (event) /* Indicate we have successfully processed this event. */ x_selection_current_request = 0; - /* Use xfree, not XFree, because lisp_data_to_selection_data + /* Use free, not XFree, because lisp_data_to_selection_data calls xmalloc itself. */ if (!nofree) - xfree (data); + free (data); } unbind_to (count, Qnil); @@ -836,7 +841,11 @@ x_clear_frame_selections (f) { for (; CONSP (hooks); hooks = Fcdr (hooks)) call1 (Fcar (hooks), selection_symbol); +#if 0 /* This can crash when deleting a frame + from x_connection_closed. Anyway, it seems unnecessary; + something else should cause a redisplay. */ redisplay_preserve_echo_area (); +#endif } Vselection_alist = Fcdr (Vselection_alist); @@ -856,7 +865,9 @@ x_clear_frame_selections (f) { for (; CONSP (hooks); hooks = Fcdr (hooks)) call1 (Fcar (hooks), selection_symbol); +#if 0 /* See above */ redisplay_preserve_echo_area (); +#endif } XCONS (rest)->cdr = Fcdr (XCONS (rest)->cdr); break; @@ -889,7 +900,7 @@ static struct prop_location * expect_property_change (display, window, property, state) Display *display; Window window; - Lisp_Object property; + Atom property; int state; { struct prop_location *pl @@ -921,7 +932,7 @@ unexpect_property_change (location) prev->next = rest->next; else property_change_wait_list = rest->next; - xfree (rest); + free (rest); return; } prev = rest; @@ -1010,7 +1021,7 @@ x_handle_property_notify (event) prev->next = rest->next; else property_change_wait_list = rest->next; - xfree (rest); + free (rest); return; } prev = rest; @@ -1097,7 +1108,7 @@ x_get_foreign_selection (selection_symbol, target_type) Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol); Atom type_atom; int secs, usecs; - int count = specpdl_ptr - specpdl; + int count; Lisp_Object frame; if (CONSP (target_type)) @@ -1106,7 +1117,7 @@ x_get_foreign_selection (selection_symbol, target_type) type_atom = symbol_to_x_atom (dpyinfo, display, target_type); BLOCK_INPUT; - x_catch_errors (display); + count = x_catch_errors (display); XConvertSelection (display, selection_atom, type_atom, target_property, requestor_window, requestor_time); XFlush (display); @@ -1137,8 +1148,7 @@ x_get_foreign_selection (selection_symbol, target_type) BLOCK_INPUT; x_check_errors (display, "Cannot get selection: %s"); - x_uncatch_errors (display); - unbind_to (count, Qnil); + x_uncatch_errors (display, count); UNBLOCK_INPUT; if (NILP (XCONS (reading_selection_reply)->car)) @@ -1155,7 +1165,7 @@ x_get_foreign_selection (selection_symbol, target_type) /* Subroutines of x_get_window_property_as_lisp_data */ -/* Use xfree, not XFree, to free the data obtained with this function. */ +/* Use free, not XFree, to free the data obtained with this function. */ static void x_get_window_property (display, window, property, data_ret, bytes_ret, @@ -1238,7 +1248,7 @@ x_get_window_property (display, window, property, data_ret, bytes_ret, *bytes_ret = offset; } -/* Use xfree, not XFree, to free the data obtained with this function. */ +/* Use free, not XFree, to free the data obtained with this function. */ static void receive_incremental_selection (display, window, property, target_type, @@ -1300,9 +1310,9 @@ receive_incremental_selection (display, window, property, target_type, if (! waiting_for_other_props_on_window (display, window)) XSelectInput (display, window, STANDARD_EVENT_SET); unexpect_property_change (wait_object); - /* Use xfree, not XFree, because x_get_window_property + /* Use free, not XFree, because x_get_window_property calls xmalloc itself. */ - if (tmp_data) xfree (tmp_data); + if (tmp_data) free (tmp_data); break; } @@ -1327,9 +1337,9 @@ receive_incremental_selection (display, window, property, target_type, } bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes); offset += tmp_size_bytes; - /* Use xfree, not XFree, because x_get_window_property + /* Use free, not XFree, because x_get_window_property calls xmalloc itself. */ - xfree (tmp_data); + free (tmp_data); } } @@ -1363,20 +1373,19 @@ x_get_window_property_as_lisp_data (display, window, property, target_type, there_is_a_selection_owner = XGetSelectionOwner (display, selection_atom); UNBLOCK_INPUT; - while (1) /* Note debugger can no longer return, so this is obsolete */ - Fsignal (Qerror, - there_is_a_selection_owner ? - Fcons (build_string ("selection owner couldn't convert"), + Fsignal (Qerror, + there_is_a_selection_owner + ? Fcons (build_string ("selection owner couldn't convert"), actual_type ? Fcons (target_type, Fcons (x_atom_to_symbol (dpyinfo, display, actual_type), Qnil)) : Fcons (target_type, Qnil)) - : Fcons (build_string ("no selection"), - Fcons (x_atom_to_symbol (dpyinfo, display, - selection_atom), - Qnil))); + : Fcons (build_string ("no selection"), + Fcons (x_atom_to_symbol (dpyinfo, display, + selection_atom), + Qnil))); } if (actual_type == dpyinfo->Xatom_INCR) @@ -1385,9 +1394,9 @@ x_get_window_property_as_lisp_data (display, window, property, target_type, unsigned int min_size_bytes = * ((unsigned int *) data); BLOCK_INPUT; - /* Use xfree, not XFree, because x_get_window_property + /* Use free, not XFree, because x_get_window_property calls xmalloc itself. */ - xfree ((char *) data); + free ((char *) data); UNBLOCK_INPUT; receive_incremental_selection (display, window, property, target_type, min_size_bytes, &data, &bytes, @@ -1405,9 +1414,9 @@ x_get_window_property_as_lisp_data (display, window, property, target_type, val = selection_data_to_lisp_data (display, data, bytes, actual_type, actual_format); - /* Use xfree, not XFree, because x_get_window_property + /* Use free, not XFree, because x_get_window_property calls xmalloc itself. */ - xfree ((char *) data); + free ((char *) data); return val; } @@ -1452,8 +1461,48 @@ selection_data_to_lisp_data (display, data, size, type, format) /* Convert any 8-bit data to a string, for compactness. */ else if (format == 8) - return make_string ((char *) data, size); - + { + Lisp_Object str; + int require_encoding = 0; + + /* If TYPE is `TEXT' or `COMPOUND_TEXT', we should decode DATA + to Emacs internal format because DATA may be encoded in + compound text format. In addtion, if TYPE is `STRING' and + DATA contains any 8-bit Latin-1 code, we should also decode + it. */ + if (type == dpyinfo->Xatom_TEXT || type == dpyinfo->Xatom_COMPOUND_TEXT) + require_encoding = 1; + else if (type == XA_STRING) + { + int i; + for (i = 0; i < size; i++) + { + if (data[i] >= 0x80) + { + require_encoding = 1; + break; + } + } + } + if (!require_encoding) + str = make_string ((char *) data, size); + else + { + int bufsize, dummy; + unsigned char *buf; + struct coding_system coding; + Lisp_Object sym = intern ("iso-8859-1"); + + setup_coding_system (Fcheck_coding_system (sym), &coding); + coding.last_block = 1; + bufsize = decoding_buffer_size (&coding, size); + buf = (unsigned char *) xmalloc (bufsize); + size = decode_coding (&coding, data, buf, size, bufsize, &dummy); + str = make_string ((char *) buf, size); + xfree (buf); + } + return str; + } /* Convert a single atom to a Lisp_Symbol. Convert a set of atoms to a vector of symbols. */ @@ -1509,7 +1558,7 @@ selection_data_to_lisp_data (display, data, size, type, format) } -/* Use xfree, not XFree, to free the data obtained with this function. */ +/* Use free, not XFree, to free the data obtained with this function. */ static void lisp_data_to_selection_data (display, obj, @@ -1545,11 +1594,55 @@ lisp_data_to_selection_data (display, obj, } else if (STRINGP (obj)) { + /* Since we are now handling multilingual text, we must consider + sending back compound text. */ + int charsets[MAX_CHARSET + 1]; + int num; + *format_ret = 8; *size_ret = XSTRING (obj)->size; *data_ret = XSTRING (obj)->data; - *nofree_ret = 1; - if (NILP (type)) type = QSTRING; + bzero (charsets, (MAX_CHARSET + 1) * sizeof (int)); + num = ((*size_ret <= 1) /* Check the possibility of short cut. */ + ? 0 + : find_charset_in_str (*data_ret, *size_ret, charsets, Qnil)); + + if (!num || (num == 1 && charsets[CHARSET_ASCII])) + { + /* No multibyte character in OBJ. We need not encode it. */ + *nofree_ret = 1; + if (NILP (type)) type = QSTRING; + } + else + { + /* We must encode contents of OBJ to compound text format. + The format is compatible with what the target `STRING' + expects if OBJ contains only ASCII and Latin-1 + characters. */ + int bufsize, dummy; + unsigned char *buf; + struct coding_system coding; + Lisp_Object sym = intern ("iso-8859-1"); + + setup_coding_system (Fcheck_coding_system (sym), &coding); + coding.last_block = 1; + bufsize = encoding_buffer_size (&coding, *size_ret); + buf = (unsigned char *) xmalloc (bufsize); + *size_ret = encode_coding (&coding, *data_ret, buf, + *size_ret, bufsize, &dummy); + *data_ret = buf; + if (charsets[charset_latin_iso8859_1] + && (num == 1 || (num == 2 && charsets[CHARSET_ASCII]))) + { + /* Ok, we can return it as `STRING'. */ + if (NILP (type)) type = QSTRING; + } + else + { + /* We must return it as `COMPOUND_TEXT'. */ + if (NILP (type)) type = QCOMPOUND_TEXT; + } + } } else if (SYMBOLP (obj)) { @@ -1731,9 +1824,8 @@ x_handle_selection_notify (event) } -DEFUN ("x-own-selection-internal", - Fx_own_selection_internal, Sx_own_selection_internal, - 2, 2, 0, +DEFUN ("x-own-selection-internal", Fx_own_selection_internal, + Sx_own_selection_internal, 2, 2, 0, "Assert an X selection of the given TYPE with the given VALUE.\n\ TYPE is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\ \(Those are literal upper-case symbol names, since that's what X expects.)\n\ @@ -1754,8 +1846,8 @@ anything that the functions on `selection-converter-alist' know about.") simply return our selection value. If we are not the owner, this will block until all of the data has arrived. */ -DEFUN ("x-get-selection-internal", - Fx_get_selection_internal, Sx_get_selection_internal, 2, 2, 0, +DEFUN ("x-get-selection-internal", Fx_get_selection_internal, + Sx_get_selection_internal, 2, 2, 0, "Return text selected from some X window.\n\ SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\ \(Those are literal upper-case symbol names, since that's what X expects.)\n\ @@ -1802,8 +1894,8 @@ TYPE is the type of data desired, typically `STRING'.") return val; } -DEFUN ("x-disown-selection-internal", - Fx_disown_selection_internal, Sx_disown_selection_internal, 1, 2, 0, +DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal, + Sx_disown_selection_internal, 1, 2, 0, "If we own the selection SELECTION, disown it.\n\ Disowning it means there is no such selection.") (selection, time) @@ -1996,9 +2088,9 @@ DEFUN ("x-get-cut-buffer-internal", Fx_get_cut_buffer_internal, Fcons (make_number (format), Qnil)))); ret = (bytes ? make_string ((char *) data, bytes) : Qnil); - /* Use xfree, not XFree, because x_get_window_property + /* Use free, not XFree, because x_get_window_property calls xmalloc itself. */ - xfree (data); + free (data); return ret; } @@ -2181,6 +2273,7 @@ A value of 0 means wait as long as necessary. This is initialized from the\n\ QCLIPBOARD = intern ("CLIPBOARD"); staticpro (&QCLIPBOARD); QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP); QTEXT = intern ("TEXT"); staticpro (&QTEXT); + QCOMPOUND_TEXT = intern ("COMPOUND_TEXT"); staticpro (&QCOMPOUND_TEXT); QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP); QDELETE = intern ("DELETE"); staticpro (&QDELETE); QMULTIPLE = intern ("MULTIPLE"); staticpro (&QMULTIPLE);