emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 17393c0db0: Allow dragging and dropping multiple actions


From: Po Lu
Subject: master 17393c0db0: Allow dragging and dropping multiple actions
Date: Wed, 23 Mar 2022 21:43:09 -0400 (EDT)

branch: master
commit 17393c0db0fbd4ba9b7ddcdc668974ef8a65107d
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Allow dragging and dropping multiple actions
    
    * doc/lispref/frames.texi (Drag and Drop): Document new meaning
    of `action'.
    * lisp/term/haiku-win.el (x-begin-drag): Correct for new meaning
    of `action'.
    * src/xfns.c (Fx_begin_drag): Handle new alist meaning of
    `action'.
    * src/xterm.c (x_dnd_begin_drag_and_drop): New parameters
    `ask_action_list', `ask_action_names' and `n_ask_actions'.
    * src/xterm.h: Update prototypes.
---
 doc/lispref/frames.texi |  5 ++++
 lisp/term/haiku-win.el  |  4 +++-
 src/xfns.c              | 61 +++++++++++++++++++++++++++++++++++++++++++++----
 src/xterm.c             | 43 ++++++++++++++++++++++++++++++++--
 src/xterm.h             |  3 ++-
 5 files changed, 107 insertions(+), 9 deletions(-)

diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index 9717fa2978..a031b25e47 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -4061,6 +4061,11 @@ the drop target; or @code{XdndActionMove}, which means 
copy as with
 @code{XdndActionCopy}, and in addition the caller should delete
 whatever was stored in that selection after copying it.
 
+@var{action} may also be an alist which associates between symbols
+describing the available actions, and strings that the drop target is
+expected to present to the user to choose between the available
+actions.
+
 If @var{return-frame} is non-nil and the mouse moves over an Emacs
 frame after first moving out of @var{frame}, then the frame to which
 the mouse moves will be returned immediately.  This is useful when you
diff --git a/lisp/term/haiku-win.el b/lisp/term/haiku-win.el
index 8ec959a758..1433620875 100644
--- a/lisp/term/haiku-win.el
+++ b/lisp/term/haiku-win.el
@@ -224,7 +224,9 @@ take effect on menu items until the menu bar is updated 
again."
               (push (cadr selection-result)
                     (cdr (alist-get (car selection-result) message
                                     nil nil #'equal))))))))
-    (prog1 (or action 'XdndActionCopy)
+    (prog1 (or (and (symbolp action)
+                    action)
+               'XdndActionCopy)
       (haiku-drag-message (or frame (selected-frame))
                           message))))
 
diff --git a/src/xfns.c b/src/xfns.c
index eae409eed2..c4b924e007 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -6614,17 +6614,28 @@ If RETURN-FRAME is non-nil, this function will return 
the frame if the
 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;
@@ -6650,10 +6661,48 @@ instead.  */)
     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);
 
@@ -6666,8 +6715,10 @@ instead.  */)
 
   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;
 }
 
diff --git a/src/xterm.c b/src/xterm.c
index e4c17644e4..0543f152ed 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -6942,7 +6942,9 @@ x_top_window_to_frame (struct x_display_info *dpyinfo, 
int wdesc)
 
 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;
@@ -6951,9 +6953,11 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   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");
@@ -6972,6 +6976,41 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   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);
diff --git a/src/xterm.h b/src/xterm.h
index 2a11f87e16..4a71968b04 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1373,7 +1373,8 @@ extern void x_scroll_bar_configure (GdkEvent *);
 #endif
 
 extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,
-                                             bool);
+                                             bool, Atom *, const char **,
+                                             size_t);
 extern void x_set_dnd_targets (Atom *, int);
 
 INLINE int



reply via email to

[Prev in Thread] Current Thread [Next in Thread]