/* X Selection processing for Emacs.
- Copyright (C) 1993, 1994, 1995, 1996 Free Software Foundation.
+ Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation.
This file is part of GNU Emacs.
#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"
+#include "buffer.h"
#include "charset.h"
#include "coding.h"
+#include "process.h"
#define CUT_BUFFER_SUPPORT
static Lisp_Object Vx_lost_selection_hooks;
static Lisp_Object Vx_sent_selection_hooks;
+/* Coding system for communicating with other X clients via cutbuffer,
+ selection, and clipboard. */
+static Lisp_Object Vselection_coding_system;
+
+/* Coding system for the next communicating with other X clients. */
+static Lisp_Object Vnext_selection_coding_system;
/* If this is a smaller number than the max-request-size of the display,
emacs will use INCR selection transfer when the selection is larger
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 */
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;
/* #### 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.
/* 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);
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;
}
\f
/* Indicate we have successfully processed this event. */
x_selection_current_request = 0;
- /* Use free, not XFree, because lisp_data_to_selection_data
+ /* Use xfree, not XFree, because lisp_data_to_selection_data
calls xmalloc itself. */
if (!nofree)
- free (data);
+ xfree (data);
}
unbind_to (count, Qnil);
}
}
\f
-/* Handle a SelectionClear event EVENT, which indicates that some other
+/* Handle a SelectionClear event EVENT, which indicates that some
client cleared out our previously asserted selection.
This is called from keyboard.c when such an event is found in the queue. */
Lisp_Object selection_symbol, local_selection_data;
Time local_selection_time;
struct x_display_info *dpyinfo = x_display_info_for_display (display);
+ struct x_display_info *t_dpyinfo;
+
+ /* If the new selection owner is also Emacs,
+ don't clear the new selection. */
+ BLOCK_INPUT;
+ /* Check each display on the same terminal,
+ to see if this Emacs job now owns the selection
+ through that display. */
+ for (t_dpyinfo = x_display_list; t_dpyinfo; t_dpyinfo = t_dpyinfo->next)
+ if (t_dpyinfo->kboard == dpyinfo->kboard)
+ {
+ Window owner_window
+ = XGetSelectionOwner (t_dpyinfo->display, selection);
+ if (x_window_to_frame (t_dpyinfo, owner_window) != 0)
+ {
+ UNBLOCK_INPUT;
+ return;
+ }
+ }
+ UNBLOCK_INPUT;
selection_symbol = x_atom_to_symbol (dpyinfo, display, selection);
prev->next = rest->next;
else
property_change_wait_list = rest->next;
- free (rest);
+ xfree (rest);
return;
}
prev = rest;
prev->next = rest->next;
else
property_change_wait_list = rest->next;
- free (rest);
+ xfree (rest);
return;
}
prev = rest;
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))
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);
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))
\f
/* Subroutines of x_get_window_property_as_lisp_data */
-/* Use free, not XFree, to free the data obtained with this function. */
+/* Use xfree, not XFree, to free the data obtained with this function. */
static void
x_get_window_property (display, window, property, data_ret, bytes_ret,
*bytes_ret = offset;
}
\f
-/* Use free, not XFree, to free the data obtained with this function. */
+/* Use xfree, not XFree, to free the data obtained with this function. */
static void
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 free, not XFree, because x_get_window_property
+ /* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
- if (tmp_data) free (tmp_data);
+ if (tmp_data) xfree (tmp_data);
break;
}
}
bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes);
offset += tmp_size_bytes;
- /* Use free, not XFree, because x_get_window_property
+ /* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
- free (tmp_data);
+ xfree (tmp_data);
}
}
\f
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)
unsigned int min_size_bytes = * ((unsigned int *) data);
BLOCK_INPUT;
- /* Use free, not XFree, because x_get_window_property
+ /* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
- free ((char *) data);
+ xfree ((char *) data);
UNBLOCK_INPUT;
receive_incremental_selection (display, window, property, target_type,
min_size_bytes, &data, &bytes,
val = selection_data_to_lisp_data (display, data, bytes,
actual_type, actual_format);
- /* Use free, not XFree, because x_get_window_property
+ /* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
- free ((char *) data);
+ xfree ((char *) data);
return val;
}
\f
else if (format == 8)
{
Lisp_Object str;
+ int require_encoding = 0;
- if (type != dpyinfo->Xatom_TEXT && type != dpyinfo->Xatom_COMPOUND_TEXT)
- str = make_string ((char *) data, size);
- else
+ if (
+#if 1
+ 1
+#else
+ ! NILP (buffer_defaults.enable_multibyte_characters)
+#endif
+ )
{
/* If TYPE is `TEXT' or `COMPOUND_TEXT', we should decode
- DATA to Emacs internal format because DATA may be
- encoded in compound text format. */
- int bufsize, dummy;
+ 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_unibyte_string ((char *) data, size);
+ Vlast_coding_system_used = Qraw_text;
+ }
+ else
+ {
+ int bufsize;
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;
+ if (NILP (Vnext_selection_coding_system))
+ Vnext_selection_coding_system = Vselection_coding_system;
+ setup_coding_system
+ (Fcheck_coding_system(Vnext_selection_coding_system), &coding);
+ Vnext_selection_coding_system = Qnil;
+ coding.mode |= CODING_MODE_LAST_BLOCK;
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);
+ decode_coding (&coding, data, buf, size, bufsize);
+ size = (coding.fake_multibyte
+ ? multibyte_chars_in_text (buf, coding.produced)
+ : coding.produced_char);
+ str = make_string_from_bytes ((char *) buf, size, coding.produced);
xfree (buf);
+ Vlast_coding_system_used = coding.symbol;
}
return str;
}
return x_atom_to_symbol (dpyinfo, display, *((Atom *) data));
else
{
- Lisp_Object v = Fmake_vector (size / sizeof (Atom), 0);
+ Lisp_Object v = Fmake_vector (make_number (size / sizeof (Atom)),
+ make_number (0));
for (i = 0; i < size / sizeof (Atom); i++)
- Faset (v, i, x_atom_to_symbol (dpyinfo, display,
- ((Atom *) data) [i]));
+ Faset (v, make_number (i),
+ x_atom_to_symbol (dpyinfo, display, ((Atom *) data) [i]));
return v;
}
}
else if (format == 16)
{
int i;
- Lisp_Object v = Fmake_vector (size / 4, 0);
- for (i = 0; i < size / 4; i++)
+ Lisp_Object v;
+ v = Fmake_vector (make_number (size / 2), make_number (0));
+ for (i = 0; i < size / 2; i++)
{
int j = (int) ((unsigned short *) data) [i];
- Faset (v, i, make_number (j));
+ Faset (v, make_number (i), make_number (j));
}
return v;
}
else
{
int i;
- Lisp_Object v = Fmake_vector (size / 4, 0);
+ Lisp_Object v = Fmake_vector (make_number (size / 4), make_number (0));
for (i = 0; i < size / 4; i++)
{
unsigned long j = ((unsigned long *) data) [i];
- Faset (v, i, long_to_cons (j));
+ Faset (v, make_number (i), long_to_cons (j));
}
return v;
}
}
-/* Use free, not XFree, to free the data obtained with this function. */
+/* Use xfree, not XFree, to free the data obtained with this function. */
static void
lisp_data_to_selection_data (display, obj,
{
/* Since we are now handling multilingual text, we must consider
sending back compound text. */
- char charsets[MAX_CHARSET + 1];
+ int charsets[MAX_CHARSET + 1];
int num;
*format_ret = 8;
- *size_ret = XSTRING (obj)->size;
+ *size_ret = STRING_BYTES (XSTRING (obj));
*data_ret = XSTRING (obj)->data;
- bzero (charsets, MAX_CHARSET + 1);
- num = ((*size_ret <= 1) /* Check the possibility of short cut. */
+ bzero (charsets, (MAX_CHARSET + 1) * sizeof (int));
+ num = ((*size_ret <= 1 /* Check the possibility of short cut. */
+ || !STRING_MULTIBYTE (obj)
+ || *size_ret == XSTRING (obj)->size)
? 0
- : find_charset_in_str (*data_ret, *size_ret, charsets));
+ : find_charset_in_str (*data_ret, *size_ret, charsets, Qnil, 0, 1));
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;
+ Vlast_coding_system_used = Qraw_text;
}
else
{
The format is compatible with what the target `STRING'
expects if OBJ contains only ASCII and Latin-1
characters. */
- int bufsize, dummy;
+ int bufsize;
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;
+ if (NILP (Vnext_selection_coding_system))
+ Vnext_selection_coding_system = Vselection_coding_system;
+ setup_coding_system
+ (Fcheck_coding_system (Vnext_selection_coding_system), &coding);
+ Vnext_selection_coding_system = Qnil;
+ coding.mode |= CODING_MODE_LAST_BLOCK;
bufsize = encoding_buffer_size (&coding, *size_ret);
buf = (unsigned char *) xmalloc (bufsize);
- *size_ret = encode_coding (&coding, *data_ret, buf,
- *size_ret, bufsize, &dummy);
+ encode_coding (&coding, *data_ret, buf, *size_ret, bufsize);
+ *size_ret = coding.produced;
*data_ret = buf;
- if (charsets[charset_latin_iso8859_1]
+ if (charsets[charset_latin_iso8859_1]
&& (num == 1 || (num == 2 && charsets[CHARSET_ASCII])))
{
/* Ok, we can return it as `STRING'. */
/* We must return it as `COMPOUND_TEXT'. */
if (NILP (type)) type = QCOMPOUND_TEXT;
}
+ Vlast_coding_system_used = coding.symbol;
}
}
else if (SYMBOLP (obj))
Lisp_Object copy;
if (size == 1)
return clean_local_selection_data (XVECTOR (obj)->contents [0]);
- copy = Fmake_vector (size, Qnil);
+ copy = Fmake_vector (make_number (size), Qnil);
for (i = 0; i < size; i++)
XVECTOR (copy)->contents [i]
= clean_local_selection_data (XVECTOR (obj)->contents [i]);
{
Time timestamp;
Atom selection_atom;
- XSelectionClearEvent event;
+ struct selection_input_event event;
Display *display;
struct x_display_info *dpyinfo;
SELECTION_EVENT_DISPLAY (&event) = display;
SELECTION_EVENT_SELECTION (&event) = selection_atom;
SELECTION_EVENT_TIME (&event) = timestamp;
- x_handle_selection_clear (&event);
+ x_handle_selection_clear ((struct input_event *) &event);
return Qt;
}
x_get_window_property (display, window, buffer_atom, &data, &bytes,
&type, &format, &size, 0);
- if (!data) return Qnil;
+ if (!data || !format)
+ return Qnil;
if (format != 8 || type != XA_STRING)
Fsignal (Qerror,
Fcons (make_number (format), Qnil))));
ret = (bytes ? make_string ((char *) data, bytes) : Qnil);
- /* Use free, not XFree, because x_get_window_property
+ /* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
- free (data);
+ xfree (data);
return ret;
}
buffer_atom = symbol_to_x_atom (FRAME_X_DISPLAY_INFO (selected_frame),
display, buffer);
data = (unsigned char *) XSTRING (string)->data;
- bytes = XSTRING (string)->size;
+ bytes = STRING_BYTES (XSTRING (string));
bytes_remaining = bytes;
if (! FRAME_X_DISPLAY_INFO (selected_frame)->cut_buffers_initialized)
DEFUN ("x-rotate-cut-buffers-internal", Fx_rotate_cut_buffers_internal,
Sx_rotate_cut_buffers_internal, 1, 1, 0,
- "Rotate the values of the cut buffers by the given number of steps;\n\
-positive means move values forward, negative means backward.")
+ "Rotate the values of the cut buffers by the given number of step.\n\
+Positive means shift the values forward, negative means backward.")
(n)
Lisp_Object n;
{
staticpro (&Vselection_alist);
DEFVAR_LISP ("selection-converter-alist", &Vselection_converter_alist,
- "An alist associating X Windows selection-types with functions.\n\
+ "An alist associating X Windows selection-types with functions.\n\
These functions are called to convert the selection, with three args:\n\
the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
a desired type to which the selection should be converted;\n\
Vselection_converter_alist = Qnil;
DEFVAR_LISP ("x-lost-selection-hooks", &Vx_lost_selection_hooks,
- "A list of functions to be called when Emacs loses an X selection.\n\
+ "A list of functions to be called when Emacs loses an X selection.\n\
\(This happens when some other X client makes its own selection\n\
or when a Lisp program explicitly clears the selection.)\n\
The functions are called with one argument, the selection type\n\
Vx_lost_selection_hooks = Qnil;
DEFVAR_LISP ("x-sent-selection-hooks", &Vx_sent_selection_hooks,
- "A list of functions to be called when Emacs answers a selection request.\n\
+ "A list of functions to be called when Emacs answers a selection request.\n\
The functions are called with four arguments:\n\
- the selection name (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');\n\
- the selection-type which Emacs was asked to convert the\n\
it merely informs you that they have happened.");
Vx_sent_selection_hooks = Qnil;
+ DEFVAR_LISP ("selection-coding-system", &Vselection_coding_system,
+ "Coding system for communicating with other X clients.\n\
+When sending or receiving text via cut_buffer, selection, and clipboard,\n\
+the text is encoded or decoded by this coding system.\n\
+The default value is `compound-text'.");
+ Vselection_coding_system = intern ("compound-text");
+
+ DEFVAR_LISP ("next-selection-coding-system", &Vnext_selection_coding_system,
+ "Coding system for the next communication with other X clients.\n\
+Usually, `selection-coding-system' is used for communicating with\n\
+other X clients. But, if this variable is set, it is used for the\n\
+next communication only. After the communication, this variable is\n\
+set to nil.");
+ Vnext_selection_coding_system = Qnil;
+
DEFVAR_INT ("x-selection-timeout", &x_selection_timeout,
- "Number of milliseconds to wait for a selection reply.\n\
+ "Number of milliseconds to wait for a selection reply.\n\
If the selection owner doesn't reply in this time, we give up.\n\
A value of 0 means wait as long as necessary. This is initialized from the\n\
\"*selectionTimeout\" resource.");