static void x_decline_selection_request (struct selection_input_event *);
static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom, bool,
- struct x_display_info *);
+ struct x_display_info *, bool);
static bool waiting_for_other_props_on_window (Display *, Window);
static struct prop_location *expect_property_change (Display *, Window,
Atom, int);
\f
/* Do protocol to assert ourself as a selection owner.
FRAME shall be the owner; it must be a valid X frame.
+ TIMESTAMP should be the timestamp where selection ownership will be
+ assumed.
+ DND_DATA is the local value that will be used for selection requests
+ with `pending_dnd_time'.
Update the Vselection_alist so that we can reply to later requests for
our selection. */
void
x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
- Lisp_Object frame)
+ Lisp_Object frame, Lisp_Object dnd_data, Time timestamp)
{
struct frame *f = XFRAME (frame);
Window selecting_window = FRAME_X_WINDOW (f);
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Display *display = dpyinfo->display;
- Time timestamp = dpyinfo->last_user_time;
Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_name);
+ if (!timestamp)
+ timestamp = dpyinfo->last_user_time;
+
block_input ();
x_catch_errors (display);
XSetSelectionOwner (display, selection_atom, selecting_window, timestamp);
Lisp_Object selection_data;
Lisp_Object prev_value;
- selection_data = list4 (selection_name, selection_value,
- INT_TO_INTEGER (timestamp), frame);
+ selection_data = list5 (selection_name, selection_value,
+ INT_TO_INTEGER (timestamp), frame,
+ dnd_data);
prev_value = LOCAL_SELECTION (selection_name, dpyinfo);
tset_selection_alist
If LOCAL_VALUE is non-nil, use it as the local copy. Also allow
quitting in that case, and let DPYINFO be NULL.
+ If NEED_ALTERNATE is true, use the drag-and-drop local value
+ instead.
+
This calls random Lisp code, and may signal or gc. */
static Lisp_Object
x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
bool local_request, struct x_display_info *dpyinfo,
- Lisp_Object local_value)
+ Lisp_Object local_value, bool need_alternate)
{
Lisp_Object tem;
Lisp_Object handler_fn, value, check;
if (CONSP (handler_fn))
handler_fn = XCDR (handler_fn);
- tem = XCAR (XCDR (local_value));
+ if (!need_alternate)
+ tem = XCAR (XCDR (local_value));
+ else
+ tem = XCAR (XCDR (XCDR (XCDR (XCDR (local_value)))));
if (STRINGP (tem))
{
Lisp_Object local_selection_data;
bool success = false;
specpdl_ref count = SPECPDL_INDEX ();
- bool pushed;
+ bool pushed, use_alternate;
Lisp_Object alias, tem;
alias = Vx_selection_alias_alist;
if (!dpyinfo)
goto REALLY_DONE;
- /* This is how the XDND protocol recommends dropping text onto a
- target that doesn't support XDND. */
- if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1
- || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2)
- /* Always reply with the contents of PRIMARY, since that's where
- the selection data is. */
- selection_symbol = QPRIMARY;
-
local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
/* Decline if we don't own any selections. */
&& local_selection_time > SELECTION_EVENT_TIME (event))
goto DONE;
+ use_alternate = false;
+
+ /* This is how the XDND protocol recommends dropping text onto a
+ target that doesn't support XDND. */
+ if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1
+ || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2)
+ use_alternate = true;
+
block_input ();
pushed = true;
x_push_current_selection_request (event, dpyinfo);
if (subproperty != None)
subsuccess = x_convert_selection (selection_symbol, subtarget,
- subproperty, true, dpyinfo);
+ subproperty, true, dpyinfo,
+ use_alternate);
if (!subsuccess)
ASET (multprop, 2*j+1, Qnil);
}
property = SELECTION_EVENT_TARGET (event);
success = x_convert_selection (selection_symbol,
target_symbol, property,
- false, dpyinfo);
+ false, dpyinfo,
+ use_alternate);
}
DONE:
static bool
x_convert_selection (Lisp_Object selection_symbol,
Lisp_Object target_symbol, Atom property,
- bool for_multiple, struct x_display_info *dpyinfo)
+ bool for_multiple, struct x_display_info *dpyinfo,
+ bool use_alternate)
{
Lisp_Object lisp_selection;
struct selection_data *cs;
lisp_selection
= x_get_local_selection (selection_symbol, target_symbol,
- false, dpyinfo, Qnil);
+ false, dpyinfo, Qnil, use_alternate);
frame = selection_request_stack;
CHECK_SYMBOL (selection);
if (NILP (value)) error ("VALUE may not be nil");
- x_own_selection (selection, value, frame);
+ x_own_selection (selection, value, frame, Qnil, 0);
return value;
}
}
val = x_get_local_selection (selection_symbol, target_type, true,
- FRAME_DISPLAY_INFO (f), Qnil);
+ FRAME_DISPLAY_INFO (f), Qnil, false);
if (NILP (val) && FRAME_LIVE_P (f))
{
check_window_system (decode_live_frame (frame));
result = x_get_local_selection (name, target, true,
- NULL, value);
+ NULL, value, false);
if (CONSP (result) && SYMBOLP (XCAR (result)))
{
{
XEvent event;
int dest_x, dest_y;
- Window child_return, child;
+ Window child_return, child, owner;
+ Lisp_Object current_value;
+ struct frame *f;
+
+ f = decode_window_system_frame (frame);
+
+ if (NILP (value))
+ return;
event.xbutton.serial = 0;
event.xbutton.send_event = True;
event.xbutton.root = dpyinfo->root_window;
event.xbutton.x_root = root_x;
event.xbutton.y_root = root_y;
-
x_catch_errors (dpyinfo->display);
child = dpyinfo->root_window;
&& child_return != None)
child = child_return;
- if (CONSP (value))
- x_own_selection (QPRIMARY, Fnth (make_fixnum (1), value),
- frame);
- else
- error ("Lost ownership of XdndSelection");
+ if (!CONSP (value))
+ goto cancel;
+
+ current_value = assq_no_quit (QPRIMARY,
+ dpyinfo->terminal->Vselection_alist);
+
+ if (!NILP (current_value))
+ current_value = XCAR (XCDR (current_value));
+
+ x_own_selection (QPRIMARY, current_value, frame,
+ XCAR (XCDR (value)), before);
+
+ owner = XGetSelectionOwner (dpyinfo->display, XA_PRIMARY);
+
+ /* If we didn't successfully obtain selection ownership, refrain
+ from generating events that will insert something else. */
+
+ if (owner != FRAME_X_WINDOW (f))
+ goto cancel;
event.xbutton.window = child;
event.xbutton.subwindow = None;
XSendEvent (dpyinfo->display, child,
True, ButtonReleaseMask, &event);
+ cancel:
x_uncatch_errors ();
}