/* Whether or not Motif drag initiator info was set up. */
static bool x_dnd_motif_setup_p;
+/* The Motif drag atom used during the drag-and-drop operation. */
+static Atom x_dnd_motif_atom;
+
/* The target window we are waiting for an XdndFinished message
from. */
static Window x_dnd_pending_finish_target;
{
drag_window = *(Window *) tmp_data;
x_catch_errors (dpyinfo->display);
- /* We use ButtonPressMask since it's one of the events an
- input-only window can never get. */
XSelectInput (dpyinfo->display, drag_window,
- ButtonPressMask);
+ StructureNotifyMask);
rc = !x_had_errors_p (dpyinfo->display);
x_uncatch_errors_after_check ();
punt. */
if (error)
{
+ XSetCloseDownMode (temp_display, DestroyAll);
+
/* If the drag window was actually created, delete it now.
Probably, a BadAlloc happened during the XChangeProperty
request. */
current display, and the XOpenDisplay above didn't
accidentally connect to some other display. */
x_catch_errors (dpyinfo->display);
- /* We use ButtonPressMask since it's one of the events an
- input-only window can never get. */
- XSelectInput (dpyinfo->display, drag_window,
- ButtonPressMask);
+ XSelectInput (dpyinfo->display, drag_window, StructureNotifyMask);
rc = !x_had_errors_p (dpyinfo->display);
x_uncatch_errors_after_check ();
unblock_input ();
return idx;
}
+/* Allocate an atom that will be used for the Motif selection during
+ the drag-and-drop operation.
+
+ Grab the server, and then retrieve a list of atoms named
+ _EMACS_DRAG_ATOM from the root window. Find the first atom that
+ has no selection owner, own it and return it. If there is no such
+ atom, add a unique atom to the end of the list and return that
+ instead. */
+
static Atom
-xm_get_drag_atom_1 (struct x_display_info *dpyinfo)
+xm_get_drag_atom_1 (struct x_display_info *dpyinfo,
+ struct frame *source_frame)
{
- Atom actual_type, atom;
+ Atom actual_type, *atoms, atom;
unsigned long nitems, bytes_remaining;
unsigned char *tmp_data;
- unsigned long inumber;
int rc, actual_format;
+ unsigned long i;
char *buffer;
/* Make sure this operation is done atomically. */
rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
dpyinfo->Xatom_EMACS_DRAG_ATOM,
- 0, 1, False, XA_CARDINAL, &actual_type,
+ 0, LONG_MAX, False, XA_ATOM, &actual_type,
&actual_format, &nitems, &bytes_remaining,
&tmp_data);
+ atom = None;
+ /* GCC thinks i is used unitialized, but it's always initialized if
+ `atoms' exists at that particular spot. */
+ i = 0;
if (rc == Success
- && actual_format == 32 && nitems == 1
- && actual_type == XA_CARDINAL)
+ && actual_format == 32 && nitems
+ && actual_type == XA_ATOM)
{
- inumber = *(unsigned long *) tmp_data;
- inumber &= 0xffffffff;
+ atoms = (Atom *) tmp_data;
+
+ x_catch_errors (dpyinfo->display);
+
+ for (i = 0; i < nitems; ++i)
+ {
+ if (XGetSelectionOwner (dpyinfo->display,
+ atoms[i]) == None
+ && !x_had_errors_p (dpyinfo->display))
+ {
+ atom = atoms[i];
+ break;
+ }
+ }
+
+ x_uncatch_errors ();
}
- else
- inumber = 0;
if (tmp_data)
XFree (tmp_data);
- if (X_LONG_MAX - inumber < 1)
- inumber = 0;
-
- inumber += 1;
buffer = dpyinfo->motif_drag_atom_name;
- /* FIXME: this interns a unique atom for every Emacs session.
- Eventually the atoms simply pile up. It may be worth
- implementing the Motif atoms table logic here. */
- sprintf (buffer, "_EMACS_ATOM_%lu", inumber);
- atom = XInternAtom (dpyinfo->display, buffer, False);
+ if (atom)
+ {
+ sprintf (buffer, "_EMACS_ATOM_%lu", i + 1);
+ XSetSelectionOwner (dpyinfo->display, atom,
+ FRAME_X_WINDOW (source_frame),
+ dpyinfo->last_user_time);
+
+ /* The selection's last-change time is newer than our
+ last_user_time, so create a new selection instead. */
+ if (XGetSelectionOwner (dpyinfo->display, atom)
+ != FRAME_X_WINDOW (source_frame))
+ atom = None;
+ }
+
+ while (!atom)
+ {
+ sprintf (buffer, "_EMACS_ATOM_%lu", nitems + 1);
+ atom = XInternAtom (dpyinfo->display, buffer, False);
+
+ XSetSelectionOwner (dpyinfo->display, atom,
+ FRAME_X_WINDOW (source_frame),
+ dpyinfo->last_user_time);
+
+ XChangeProperty (dpyinfo->display, dpyinfo->root_window,
+ dpyinfo->Xatom_EMACS_DRAG_ATOM, XA_ATOM, 32,
+ (rc == Success && (actual_format != 32
+ || actual_type != XA_ATOM)
+ ? PropModeReplace : PropModeAppend),
+ (unsigned char *) &atom, 1);
- XChangeProperty (dpyinfo->display, dpyinfo->root_window,
- dpyinfo->Xatom_EMACS_DRAG_ATOM, XA_CARDINAL, 32,
- PropModeReplace, (unsigned char *) &inumber, 1);
+ actual_format = 32;
+ actual_type = XA_ATOM;
+ rc = Success;
+ nitems += 1;
+
+ /* The selection's last-change time is newer than our
+ last_user_time, so create a new selection (again). */
+ if (XGetSelectionOwner (dpyinfo->display, atom)
+ != FRAME_X_WINDOW (source_frame))
+ atom = None;
+ }
+
+ dpyinfo->motif_drag_atom_time = dpyinfo->last_user_time;
XUngrabServer (dpyinfo->display);
return atom;
if (dpyinfo->motif_drag_atom != None)
atom = dpyinfo->motif_drag_atom;
else
- atom = xm_get_drag_atom_1 (dpyinfo);
+ atom = xm_get_drag_atom_1 (dpyinfo, x_dnd_frame);
dpyinfo->motif_drag_atom = atom;
return atom;
{
Atom atom;
xm_drag_initiator_info drag_initiator_info;
- int idx, rc;
+ int idx;
atom = xm_get_drag_atom (dpyinfo);
- x_catch_errors (dpyinfo->display);
- XSetSelectionOwner (dpyinfo->display, atom,
- FRAME_X_WINDOW (source_frame),
- dpyinfo->last_user_time);
- rc = x_had_errors_p (dpyinfo->display);
- x_uncatch_errors_after_check ();
-
- if (rc)
+ if (atom == None)
return;
XSETCAR (x_dnd_selection_alias_cell,
&drag_initiator_info);
x_dnd_motif_setup_p = true;
+ x_dnd_motif_atom = atom;
}
}
XM_DROP_ACTION_DROP_CANCEL);
dmsg.x = 0;
dmsg.y = 0;
- dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO (f));
+ dmsg.index_atom = x_dnd_motif_atom;
dmsg.source_window = FRAME_X_WINDOW (f);
x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
XM_DROP_ACTION_DROP_CANCEL);
dmsg.x = 0;
dmsg.y = 0;
- dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO (f));
+ dmsg.index_atom = x_dnd_motif_atom;
dmsg.source_window = FRAME_X_WINDOW (f);
x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
/* Delete the Motif drag initiator info if it was set up. */
if (x_dnd_motif_setup_p)
XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- xm_get_drag_atom (FRAME_DISPLAY_INFO (f)));
+ x_dnd_motif_atom);
/* Remove any type list set as well. */
XM_DROP_ACTION_DROP_CANCEL);
dmsg.x = 0;
dmsg.y = 0;
- dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO (f));
+ dmsg.index_atom = x_dnd_motif_atom;
dmsg.source_window = FRAME_X_WINDOW (f);
x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
/* Delete the Motif drag initiator info if it was set up. */
if (x_dnd_motif_setup_p)
XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- xm_get_drag_atom (FRAME_DISPLAY_INFO (f)));
+ x_dnd_motif_atom);
/* Remove any type list set as well. */
/* Delete the Motif drag initiator info if it was set up. */
if (x_dnd_motif_setup_p)
XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
- xm_get_drag_atom (FRAME_DISPLAY_INFO (f)));
+ x_dnd_motif_atom);
/* Remove any type list set as well. */
if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
emsg.zero = 0;
emsg.timestamp = timestamp;
emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
- emsg.index_atom = xm_get_drag_atom (dpyinfo);
+ emsg.index_atom = x_dnd_motif_atom;
if (x_dnd_motif_setup_p)
xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
XM_DROP_ACTION_DROP_CANCEL);
dsmsg.x = 0;
dsmsg.y = 0;
- dsmsg.index_atom = xm_get_drag_atom (dpyinfo);
+ dsmsg.index_atom = x_dnd_motif_atom;
dsmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
x_dnd_send_xm_leave_for_drop (dpyinfo, x_dnd_frame,
{
const XSelectionClearEvent *eventp = &event->xselectionclear;
+ if (eventp->selection == dpyinfo->motif_drag_atom
+ && dpyinfo->motif_drag_atom_time <= eventp->time)
+ dpyinfo->motif_drag_atom = None;
+
inev.sie.kind = SELECTION_CLEAR_EVENT;
SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo;
SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection;
if (x_dnd_waiting_for_finish
&& x_dnd_waiting_for_motif_finish == 2
&& dpyinfo == x_dnd_waiting_for_motif_finish_display
- && eventp->selection == xm_get_drag_atom (dpyinfo)
+ && eventp->selection == x_dnd_motif_atom
&& (eventp->target == dpyinfo->Xatom_XmTRANSFER_SUCCESS
|| eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE))
{
emsg.zero = 0;
emsg.timestamp = event->xbutton.time;
emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
- emsg.index_atom = xm_get_drag_atom (dpyinfo);
+ emsg.index_atom = x_dnd_motif_atom;
if (x_dnd_motif_setup_p)
xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
dmsg.timestamp = event->xbutton.time;
dmsg.x = event->xbutton.x_root;
dmsg.y = event->xbutton.y_root;
- dmsg.index_atom = xm_get_drag_atom (dpyinfo);
+ dmsg.index_atom = x_dnd_motif_atom;
dmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
if (!XM_DRAG_STYLE_IS_DROP_ONLY (drag_receiver_info.protocol_style))
emsg.zero = 0;
emsg.timestamp = xev->time;
emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
- emsg.index_atom = xm_get_drag_atom (dpyinfo);
+ emsg.index_atom = x_dnd_motif_atom;
if (x_dnd_motif_setup_p)
xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
instances of Emacs try to drag
into the same window at the same
time. */
- dmsg.index_atom = xm_get_drag_atom (dpyinfo);
+ dmsg.index_atom = x_dnd_motif_atom;
dmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
if (!XM_DRAG_STYLE_IS_DROP_ONLY (drag_receiver_info.protocol_style))
XM_DROP_ACTION_DROP_CANCEL);
dmsg.x = 0;
dmsg.y = 0;
- dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO (f));
+ dmsg.index_atom = x_dnd_motif_atom;
dmsg.source_window = FRAME_X_WINDOW (f);
x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,