mouse pointer moves onto an Emacs frame, after first moving out of
FRAME.
+If ACTION is a list and not nil, its elements are assumed to be a cons
+of (ITEM . STRING), where ITEM is the name of an action, and STRING is
+a string describing ITEM to the user. The drop target is expected to
+prompt the user to choose between any of the actions in the list.
+
If ACTION is not specified or nil, `XdndActionCopy' is used
instead. */)
(Lisp_Object targets, Lisp_Object action, Lisp_Object frame,
Lisp_Object return_frame)
{
struct frame *f = decode_window_system_frame (frame);
- int ntargets = 0;
+ int ntargets = 0, nnames = 0;
+ ptrdiff_t len;
char *target_names[2048];
Atom *target_atoms;
- Lisp_Object lval, original;
+ Lisp_Object lval, original, tem, t1, t2;
Atom xaction;
+ Atom action_list[2048];
+ char *name_list[2048];
+ char *scratch;
+
+ USE_SAFE_ALLOCA;
CHECK_LIST (targets);
original = targets;
xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionMove;
else if (EQ (action, QXdndActionLink))
xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionLink;
- else if (EQ (action, QXdndActionAsk))
- xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionAsk;
else if (EQ (action, QXdndActionPrivate))
xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionPrivate;
+ else if (CONSP (action))
+ {
+ xaction = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionAsk;
+ original = action;
+
+ CHECK_LIST (action);
+ for (; CONSP (action); action = XCDR (action))
+ {
+ tem = XCAR (action);
+ CHECK_CONS (tem);
+ t1 = XCAR (tem);
+ t2 = XCDR (tem);
+ CHECK_SYMBOL (t1);
+ CHECK_STRING (t2);
+
+ if (nnames < 2048)
+ {
+ if (EQ (t1, QXdndActionCopy))
+ action_list[nnames] = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionCopy;
+ else if (EQ (t1, QXdndActionMove))
+ action_list[nnames] = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionMove;
+ else if (EQ (t1, QXdndActionLink))
+ action_list[nnames] = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionLink;
+ else if (EQ (t1, QXdndActionPrivate))
+ action_list[nnames] = FRAME_DISPLAY_INFO (f)->Xatom_XdndActionPrivate;
+ else
+ signal_error ("Invalid drag-and-drop action", tem);
+
+ scratch = SSDATA (ENCODE_UTF_8 (t2));
+ len = strlen (scratch);
+ name_list[nnames] = SAFE_ALLOCA (len + 1);
+ strncpy (name_list[nnames], scratch, len + 1);
+
+ nnames++;
+ }
+ else
+ error ("Too many actions");
+ }
+ CHECK_LIST_END (action, original);
+ }
else
signal_error ("Invalid drag-and-drop action", action);
x_set_dnd_targets (target_atoms, ntargets);
lval = x_dnd_begin_drag_and_drop (f, FRAME_DISPLAY_INFO (f)->last_user_time,
- xaction, !NILP (return_frame));
+ xaction, !NILP (return_frame), action_list,
+ (const char **) &name_list, nnames);
+ SAFE_FREE ();
return lval;
}
Lisp_Object
x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
- bool return_frame_p)
+ bool return_frame_p, Atom *ask_action_list,
+ const char **ask_action_names,
+ size_t n_ask_actions)
{
#ifndef USE_GTK
XEvent next_event;
XWindowAttributes root_window_attrs;
struct input_event hold_quit;
struct frame *any;
- char *atom_name;
+ char *atom_name, *ask_actions;
Lisp_Object action, ltimestamp;
specpdl_ref ref;
+ ptrdiff_t i, end, fill;
+ XTextProperty prop;
if (!FRAME_VISIBLE_P (f))
error ("Frame is invisible");
else
x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
+ if (n_ask_actions)
+ {
+ ask_actions = NULL;
+ end = 0;
+
+ for (i = 0; i < n_ask_actions; ++i)
+ {
+ fill = end;
+ end += strlen (ask_action_names[i]) + 1;
+
+ if (ask_actions)
+ ask_actions = xrealloc (ask_actions, end);
+ else
+ ask_actions = xmalloc (end);
+
+ strncpy (ask_actions + fill,
+ ask_action_names[i],
+ end - fill);
+ }
+
+ prop.value = (unsigned char *) ask_actions;
+ prop.encoding = XA_STRING;
+ prop.format = 8;
+ prop.nitems = end;
+
+ XSetTextProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ &prop, FRAME_DISPLAY_INFO (f)->Xatom_XdndActionDescription);
+ xfree (ask_actions);
+
+ XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->Xatom_XdndActionList, XA_ATOM, 32,
+ PropModeReplace, (unsigned char *) ask_action_list,
+ n_ask_actions);
+ }
+
x_dnd_in_progress = true;
x_dnd_frame = f;
x_dnd_last_seen_window = FRAME_X_WINDOW (f);