`x_dnd_begin_drag_and_drop'. */
static struct frame *x_dnd_return_frame_object;
-/* The last toplevel window the mouse pointer moved over. */
+/* The last drop target window the mouse pointer moved over. This can
+ be different from `x_dnd_last_seen_toplevel' if that window had an
+ XdndProxy. */
static Window x_dnd_last_seen_window;
+/* The last toplevel the mouse pointer moved over. */
+static Window x_dnd_last_seen_toplevel;
+
/* The window where the drop happened. Normally None, but it is set
when something is actually dropped. */
static Window x_dnd_end_window;
return rc;
}
+/* From the XDND protocol specification:
+
+ Dropping on windows that do not support XDND
+
+ Since middle clicking is the universal shortcut for pasting in X,
+ one can drop data into a window that does not support XDND by:
+
+ 1. After the mouse has been released to trigger the drop, obtain
+ ownership of XA_PRIMARY.
+
+ 2. Send a ButtonPress event and then a ButtonRelease event to the
+ deepest subwindow containing the mouse to simulate a middle click.
+ The times for these events should be the time of the actual button
+ release +1 and +2, respectively. These values will not be used by
+ anybody else, so one can unambiguously recognize the resulting
+ XConvertSelection() request.
+
+ 3. If a request for XA_PRIMARY arrives bearing the timestamp of
+ either the ButtonPress or the ButtonRelease event, treat it as a
+ request for XdndSelection. Note that you must use the X data
+ types instead of the MIME types in this case. (e.g. XA_STRING
+ instead of text/plain). */
+static void
+x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_window,
+ int root_x, int root_y, Time before)
+{
+ XEvent event;
+ int dest_x, dest_y;
+ Window child_return, child;
+ Lisp_Object frame;
+ int i;
+
+ for (i = 0; i < x_dnd_n_targets; ++i)
+ {
+ if (x_dnd_targets[i] == XA_STRING
+ || x_dnd_targets[i] == dpyinfo->Xatom_COMPOUND_TEXT
+ || x_dnd_targets[i] == dpyinfo->Xatom_UTF8_STRING)
+ break;
+ }
+
+ if (i == x_dnd_n_targets)
+ return;
+
+ event.xbutton.type = ButtonPress;
+ event.xbutton.serial = 0;
+ event.xbutton.send_event = True;
+ event.xbutton.display = dpyinfo->display;
+ event.xbutton.root = dpyinfo->root_window;
+ event.xbutton.x_root = root_x;
+ event.xbutton.y_root = root_y;
+
+ XSETFRAME (frame, x_dnd_frame);
+
+ x_catch_errors (dpyinfo->display);
+ child = dpyinfo->root_window;
+
+ while (XTranslateCoordinates (dpyinfo->display, child,
+ child, root_x, root_y, &dest_x,
+ &dest_y, &child_return)
+ && child_return != None
+ && XTranslateCoordinates (dpyinfo->display, child,
+ child_return, root_x, root_y,
+ &dest_x, &dest_y, &child))
+ {
+ child = child_return;
+ root_x = dest_x;
+ root_y = dest_y;
+ }
+
+ if (child != dpyinfo->root_window)
+ {
+ x_own_selection (QPRIMARY, Qnil, frame);
+
+ event.xbutton.window = child;
+ event.xbutton.x = dest_x;
+ event.xbutton.y = dest_y;
+ event.xbutton.state = 0;
+ event.xbutton.button = 2;
+ event.xbutton.same_screen = True;
+ event.xbutton.time = before + 1;
+ event.xbutton.time = before + 2;
+
+ x_set_pending_dnd_time (before);
+
+ XSendEvent (dpyinfo->display, child,
+ True, ButtonPressMask, &event);
+ event.xbutton.type = ButtonRelease;
+ XSendEvent (dpyinfo->display, child,
+ True, ButtonReleaseMask, &event);
+ }
+
+ x_uncatch_errors ();
+}
+
static Window
x_dnd_get_target_window (struct x_display_info *dpyinfo,
int root_x, int root_y, int *proto_out,
- int *motif_out)
+ int *motif_out, Window *toplevel_out)
{
Window child_return, child, dummy, proxy;
int dest_x_return, dest_y_return, rc, proto, motif;
proto = -1;
*motif_out = XM_DRAG_STYLE_NONE;
+ *toplevel_out = None;
if (x_dnd_use_toplevels)
{
&& FRAME_X_WINDOW (x_dnd_frame) == child)
*motif_out = XM_DRAG_STYLE_NONE;
+ *toplevel_out = child;
+
if (child != None)
{
#ifndef USE_XCB
{
*proto_out = -1;
*motif_out = XM_DRAG_STYLE_NONE;
+ *toplevel_out = None;
return None;
}
if (proto != -1)
{
*proto_out = proto;
+ *toplevel_out = overlay_window;
x_uncatch_errors_after_check ();
return proxy;
if (proto != -1)
{
+ *toplevel_out = dpyinfo->root_window;
*proto_out = proto;
return proxy;
}
/* No toplevel was found and the overlay and root windows were
not proxies, so return None. */
*proto_out = -1;
+ *toplevel_out = dpyinfo->root_window;
return None;
}
break;
}
- proxy = x_dnd_get_window_proxy (dpyinfo, child_return);
-
- if (proxy != None)
- {
- proto = x_dnd_get_window_proto (dpyinfo, proxy);
-
- if (proto != -1)
- {
- *proto_out = proto;
-
- x_uncatch_errors ();
- return proxy;
- }
- }
-
if (child_return)
{
if (x_dnd_get_wm_state_and_proto (dpyinfo, child_return,
{
*proto_out = proto;
*motif_out = motif;
+ *toplevel_out = child_return;
x_uncatch_errors ();
return child_return;
}
+ proxy = x_dnd_get_window_proxy (dpyinfo, child_return);
+
+ if (proxy != None)
+ {
+ proto = x_dnd_get_window_proto (dpyinfo, proxy);
+
+ if (proto != -1)
+ {
+ *proto_out = proto;
+ *toplevel_out = child_return;
+
+ x_uncatch_errors ();
+ return proxy;
+ }
+ }
+
rc = XTranslateCoordinates (dpyinfo->display,
child, child_return,
dest_x_return, dest_y_return,
{
x_uncatch_errors_after_check ();
*proto_out = -1;
+ *toplevel_out = dpyinfo->root_window;
return None;
}
}
if (proto != -1)
{
*proto_out = proto;
+ *toplevel_out = child;
return proxy;
}
}
if (proto != -1)
{
*proto_out = proto;
+ *toplevel_out = overlay_window;
x_uncatch_errors_after_check ();
return proxy;
if (proto != -1)
{
+ *toplevel_out = child;
*proto_out = proto;
return proxy;
}
}
*proto_out = x_dnd_get_window_proto (dpyinfo, child);
+ *toplevel_out = child;
return child;
#endif
}
x_dnd_end_window = x_dnd_last_seen_window;
x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
x_dnd_in_progress = false;
x_set_dnd_targets (NULL, 0);
}
x_dnd_in_progress = true;
x_dnd_frame = f;
x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
x_dnd_last_protocol_version = -1;
x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_mouse_rect_target = None;
x_dnd_end_window = x_dnd_last_seen_window;
x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
x_dnd_in_progress = false;
x_dnd_frame = NULL;
x_set_dnd_targets (NULL, 0);
{
int root_x, root_y, dummy_x, dummy_y, target_proto, motif_style;
unsigned int dummy_mask;
- Window dummy, dummy_child, target;
+ Window dummy, dummy_child, target, toplevel;
xm_top_level_leave_message lmsg;
xm_top_level_enter_message emsg;
xm_drag_motion_message dmsg;
{
target = x_dnd_get_target_window (dpyinfo, root_x,
root_y, &target_proto,
- &motif_style);
+ &motif_style, &toplevel);
- if (target != x_dnd_last_seen_window)
+ if (toplevel != x_dnd_last_seen_toplevel)
{
- if (target != FRAME_OUTER_WINDOW (x_dnd_frame)
+ if (toplevel != FRAME_OUTER_WINDOW (x_dnd_frame)
&& x_dnd_return_frame == 1)
x_dnd_return_frame = 2;
+ if (x_dnd_return_frame == 2
+ && x_any_window_to_frame (dpyinfo, toplevel))
+ {
+ x_dnd_end_window = x_dnd_last_seen_window;
+ x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
+ x_dnd_in_progress = false;
+ x_dnd_return_frame_object
+ = x_any_window_to_frame (dpyinfo, toplevel);
+ x_dnd_return_frame = 3;
+ x_dnd_waiting_for_finish = false;
+ target = None;
+ }
+
+ x_dnd_last_seen_toplevel = toplevel;
+ }
+
+ if (target != x_dnd_last_seen_window)
+ {
if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
x_dnd_last_seen_window, &lmsg);
}
- if (x_dnd_return_frame == 2
- && x_any_window_to_frame (dpyinfo, target))
- {
- x_dnd_end_window = x_dnd_last_seen_window;
- x_dnd_last_seen_window = None;
- x_dnd_in_progress = false;
- x_dnd_return_frame_object
- = x_any_window_to_frame (dpyinfo, target);
- x_dnd_return_frame = 3;
- x_dnd_waiting_for_finish = false;
- target = None;
- }
-
x_dnd_action = None;
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
x_dnd_end_window = x_dnd_last_seen_window;
x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
x_dnd_in_progress = false;
x_dnd_waiting_for_finish = false;
x_dnd_frame = NULL;
if (x_dnd_in_progress
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
- Window target;
+ Window target, toplevel;
int target_proto, motif_style;
xm_top_level_leave_message lmsg;
xm_top_level_enter_message emsg;
event->xmotion.x_root,
event->xmotion.y_root,
&target_proto,
- &motif_style);
+ &motif_style, &toplevel);
- if (target != x_dnd_last_seen_window)
+ if (toplevel != x_dnd_last_seen_toplevel)
{
- if (target != FRAME_OUTER_WINDOW (x_dnd_frame)
+ if (toplevel != FRAME_OUTER_WINDOW (x_dnd_frame)
&& x_dnd_return_frame == 1)
x_dnd_return_frame = 2;
+ if (x_dnd_return_frame == 2
+ && x_any_window_to_frame (dpyinfo, toplevel))
+ {
+ x_dnd_end_window = x_dnd_last_seen_window;
+ x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
+ x_dnd_in_progress = false;
+ x_dnd_return_frame_object
+ = x_any_window_to_frame (dpyinfo, toplevel);
+ x_dnd_return_frame = 3;
+ x_dnd_waiting_for_finish = false;
+ target = None;
+ }
+
+ x_dnd_last_seen_toplevel = toplevel;
+ }
+
+ if (target != x_dnd_last_seen_window)
+ {
if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
}
}
- if (x_dnd_return_frame == 2
- && x_any_window_to_frame (dpyinfo, target))
- {
- x_dnd_end_window = x_dnd_last_seen_window;
- x_dnd_last_seen_window = None;
- x_dnd_in_progress = false;
- x_dnd_return_frame_object
- = x_any_window_to_frame (dpyinfo, target);
- x_dnd_return_frame = 3;
- x_dnd_waiting_for_finish = false;
- target = None;
- }
-
x_dnd_action = None;
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
x_dnd_waiting_for_motif_finish = 1;
}
}
+ else
+ {
+ x_set_pending_dnd_time (event->xbutton.time);
+ x_dnd_send_unsupported_drop (dpyinfo, x_dnd_last_seen_window,
+ event->xbutton.x_root, event->xbutton.y_root,
+ event->xbutton.time);
+ }
}
x_dnd_last_protocol_version = -1;
x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
x_dnd_frame = NULL;
x_set_dnd_targets (NULL, 0);
}
if (x_dnd_in_progress
&& dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
{
- Window target;
+ Window target, toplevel;
int target_proto, motif_style;
/* Sometimes the drag-and-drop operation starts with the
xev->root_x,
xev->root_y,
&target_proto,
- &motif_style);
+ &motif_style,
+ &toplevel);
- if (target != x_dnd_last_seen_window)
+ if (toplevel != x_dnd_last_seen_toplevel)
{
- if (target != FRAME_OUTER_WINDOW (x_dnd_frame)
+ if (toplevel != FRAME_OUTER_WINDOW (x_dnd_frame)
&& x_dnd_return_frame == 1)
x_dnd_return_frame = 2;
+ if (x_dnd_return_frame == 2
+ && x_any_window_to_frame (dpyinfo, toplevel))
+ {
+ x_dnd_end_window = x_dnd_last_seen_window;
+ x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
+ x_dnd_in_progress = false;
+ x_dnd_return_frame_object
+ = x_any_window_to_frame (dpyinfo, toplevel);
+ x_dnd_return_frame = 3;
+ x_dnd_waiting_for_finish = false;
+ target = None;
+ }
+
+ x_dnd_last_seen_toplevel = toplevel;
+ }
+
+ if (target != x_dnd_last_seen_window)
+ {
if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1
&& x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame))
}
}
- if (x_dnd_return_frame == 2
- && x_any_window_to_frame (dpyinfo, target))
- {
- x_dnd_end_window = x_dnd_last_seen_window;
- x_dnd_last_seen_window = None;
- x_dnd_in_progress = false;
- x_dnd_return_frame_object
- = x_any_window_to_frame (dpyinfo, target);
- x_dnd_return_frame = 3;
- x_dnd_waiting_for_finish = false;
- target = None;
- }
-
x_dnd_action = None;
x_dnd_last_seen_window = target;
x_dnd_last_protocol_version = target_proto;
x_dnd_waiting_for_motif_finish = 1;
}
}
+ else
+ {
+ x_set_pending_dnd_time (xev->time);
+ x_dnd_send_unsupported_drop (dpyinfo, x_dnd_last_seen_window,
+ xev->root_x, xev->root_y, xev->time);
+ }
}
x_dnd_last_protocol_version = -1;
x_dnd_last_motif_style = XM_DRAG_STYLE_NONE;
x_dnd_last_seen_window = None;
+ x_dnd_last_seen_toplevel = None;
x_dnd_frame = NULL;
x_set_dnd_targets (NULL, 0);