#endif
static bool x_dnd_in_progress;
+static bool x_dnd_waiting_for_finish;
+static Window x_dnd_pending_finish_target;
+static int x_dnd_waiting_for_finish_proto;
/* Whether or not to return a frame from `x_dnd_begin_drag_and_drop'.
static Atom *x_dnd_targets = NULL;
static int x_dnd_n_targets;
static struct frame *x_dnd_frame;
+static XWindowAttributes x_dnd_old_window_attrs;
+static XIC x_dnd_old_ic;
+static bool x_dnd_unwind_flag;
#define X_DND_SUPPORTED_VERSION 5
x_dnd_n_targets = ntargets;
}
+static void
+x_dnd_cleanup_drag_and_drop (void *frame)
+{
+ struct frame *f = frame;
+
+ if (!x_dnd_unwind_flag)
+ return;
+
+ if (x_dnd_in_progress)
+ {
+ eassert (x_dnd_frame);
+
+ block_input ();
+ if (x_dnd_last_seen_window != None
+ && x_dnd_last_protocol_version != -1)
+ x_dnd_send_leave (x_dnd_frame,
+ x_dnd_last_seen_window);
+ unblock_input ();
+
+ x_dnd_in_progress = false;
+ x_set_dnd_targets (NULL, 0);
+ }
+
+ FRAME_DISPLAY_INFO (f)->grabbed = 0;
+#ifdef USE_GTK
+ current_hold_quit = NULL;
+#endif
+#ifdef HAVE_X_I18N
+ FRAME_XIC (f) = x_dnd_old_ic;
+#endif
+
+ block_input ();
+ /* Restore the old event mask. */
+ XSelectInput (FRAME_X_DISPLAY (f),
+ FRAME_DISPLAY_INFO (f)->root_window,
+ x_dnd_old_window_attrs.your_event_mask);
+ unblock_input ();
+
+ x_dnd_frame = NULL;
+}
+
Lisp_Object
x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
bool return_frame_p)
struct input_event hold_quit;
char *atom_name;
Lisp_Object action, ltimestamp;
+ specpdl_ref ref;
if (!FRAME_VISIBLE_P (f))
error ("Frame is invisible");
x_dnd_action = None;
x_dnd_wanted_action = xaction;
x_dnd_return_frame = 0;
+ x_dnd_waiting_for_finish = false;
if (return_frame_p)
x_dnd_return_frame = 1;
Otherwise, the ibus XIM server gets very confused. */
FRAME_XIC (f) = NULL;
#endif
- while (x_dnd_in_progress)
+ while (x_dnd_in_progress || x_dnd_waiting_for_finish)
{
hold_quit.kind = NO_EVENT;
#ifdef USE_GTK
if (hold_quit.kind != NO_EVENT)
{
+ if (hold_quit.kind == SELECTION_REQUEST_EVENT)
+ {
+ x_dnd_old_ic = ic;
+ x_dnd_old_window_attrs = root_window_attrs;
+ x_dnd_unwind_flag = true;
+
+ ref = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+ x_handle_selection_event ((struct selection_input_event *) &hold_quit);
+ x_dnd_unwind_flag = false;
+ unbind_to (ref, Qnil);
+ continue;
+ }
+
if (x_dnd_in_progress)
{
if (x_dnd_last_seen_window != None
}
}
+ if (event->xclient.message_type == dpyinfo->Xatom_XdndFinished
+ && x_dnd_waiting_for_finish
+ && event->xclient.data.l[0] == x_dnd_pending_finish_target)
+ {
+ x_dnd_waiting_for_finish = false;
+
+ if (x_dnd_waiting_for_finish_proto >= 5)
+ x_dnd_wanted_action = event->xclient.data.l[2];
+
+ if (x_dnd_waiting_for_finish_proto >= 5
+ && !(event->xclient.data.l[1] & 1))
+ x_dnd_wanted_action = None;
+ }
+
if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols
&& event->xclient.format == 32)
{
SELECTION_EVENT_TARGET (&inev.sie) = eventp->target;
SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property;
SELECTION_EVENT_TIME (&inev.sie) = eventp->time;
+
+ /* If drag-and-drop is in progress, handle SelectionRequest
+ events immediately, by setting hold_quit to the input
+ event. */
+
+ if (x_dnd_in_progress || x_dnd_waiting_for_finish)
+ {
+ *hold_quit = inev.ie;
+ EVENT_INIT (inev.ie);
+ }
}
break;
if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1)
- x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window,
- x_dnd_selection_timestamp,
- x_dnd_last_protocol_version);
+ {
+ x_dnd_waiting_for_finish = true;
+ x_dnd_pending_finish_target = x_dnd_last_seen_window;
+ x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version;
+
+ x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window,
+ x_dnd_selection_timestamp,
+ x_dnd_last_protocol_version);
+ }
x_dnd_last_protocol_version = -1;
x_dnd_last_seen_window = None;
if (x_dnd_last_seen_window != None
&& x_dnd_last_protocol_version != -1)
- x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window,
- x_dnd_selection_timestamp,
- x_dnd_last_protocol_version);
+ {
+ x_dnd_waiting_for_finish = true;
+ x_dnd_pending_finish_target = x_dnd_last_seen_window;
+ x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version;
+
+ x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window,
+ x_dnd_selection_timestamp,
+ x_dnd_last_protocol_version);
+ }
x_dnd_last_protocol_version = -1;
x_dnd_last_seen_window = None;