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
/* 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;
\f
/* Utility functions */
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);
#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);
}
}
\f
/* 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);
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;
}
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
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
#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)
{
{
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,
}
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);
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 */
}
}
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;
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)
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:
/* 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);
}
}
}
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
if (changed_owner_time != CurrentTime &&
local_selection_time > changed_owner_time)
return;
-
+
handle_selection_clear (selection_symbol);
}
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;
}
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)
/* 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)
{
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
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
*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;
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);
return val;
}
\f
+/* #### 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.
static Lisp_Object
selection_data_to_lisp_data (struct device *d,
- unsigned char *data,
+ Extbyte *data,
size_t size,
Atom type,
int format)
}
else if (STRINGP (obj))
{
- CONST Extbyte *extval;
+ const Extbyte *extval;
Extcount extvallen;
TO_EXTERNAL_FORMAT (LISP_STRING, obj,
{
Bufbyte buf[MAX_EMCHAR_LEN];
Bytecount len;
- CONST Extbyte *extval;
+ const Extbyte *extval;
Extcount extvallen;
*format_ret = 8;
}
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);
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);
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;
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
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)
{
ptr += 2;
continue;
}
+#endif
chartypes = WORLD;
break;
\"*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
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);
}