unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Drag and drop patch for X, please review.
@ 2004-01-17 16:35 Jan D.
  2004-01-17 20:20 ` David Kastrup
                   ` (3 more replies)
  0 siblings, 4 replies; 56+ messages in thread
From: Jan D. @ 2004-01-17 16:35 UTC (permalink / raw)


Hello.

The enclosed patch adds drag and drop support (well, actually only drop)
in X to Emacs.  The protocols supported are XDND (the most used nowdays,
by Mozilla, OpenOffice, Gnome, KDE etc.) and the old KDE 1.x protocol.
You can currently drop file names and text.  Files will be opened
and text inserted (at mouse position).  Http urls and such are just
ignored, probably there is something more intelligent one could do,
suggestions?

The reason to include the old KDE one is that it is very simple and
easy to test.
I plan to add Motif and OpenWindows as soon as I get Solaris 8 & 9 installed
(waiting for an ordered disc drive).

I previously did this in C, but it added so much code and the turnaround time
for modifications where long, so this implementation is mostly in elisp.
As elisp is not one of my better known languages, any comments and
improvements are welcome.

There are some issues with file names with non-ascii characters in them,
part of that is due to the fact that XDND is not very clear on how that
should be done, and KDE and Gnome does things differently.
Also, I am not sure if I got it right either.

Thanks,

	Jan D.

Index: lisp/term/x-win.el
===================================================================
RCS file: /cvsroot/emacs/emacs/lisp/term/x-win.el,v
retrieving revision 1.166
diff -c -c -r1.166 x-win.el
*** lisp/term/x-win.el	1 Sep 2003 15:45:36 -0000	1.166
--- lisp/term/x-win.el	17 Jan 2004 16:18:11 -0000
***************
*** 76,81 ****
--- 76,82 ----
  (require 'select)
  (require 'menu-bar)
  (require 'fontset)
+ (require 'x-dnd)
  
  (defvar x-invocation-args)
  
***************
*** 2455,2460 ****
--- 2456,2465 ----
  
  ;; Turn on support for mouse wheels.
  (mouse-wheel-mode 1)
+ 
+ ;; Initiate drag and drop
+ (add-hook 'after-make-frame-functions 'x-dnd-init-frame)
+ (global-set-key [drag-n-drop] 'x-dnd-handle-drag-n-drop-event)
  
  ;;; arch-tag: f1501302-db8b-4d95-88e3-116697d89f78
  ;;; x-win.el ends here
Index: src/xfns.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xfns.c,v
retrieving revision 1.601
diff -c -c -r1.601 xfns.c
*** src/xfns.c	28 Dec 2003 00:13:10 -0000	1.601
--- src/xfns.c	17 Jan 2004 16:18:19 -0000
***************
*** 4284,4408 ****
  
  \f
  /***********************************************************************
-                 General X functions exposed to Elisp.
-  ***********************************************************************/
- 
- DEFUN ("x-send-client-message", Fx_send_client_event,
-        Sx_send_client_message, 6, 6, 0,
-        doc: /* Send a client message of MESSAGE-TYPE to window DEST on DISPLAY.
- 
- For DISPLAY, specify either a frame or a display name (a string).
- If DISPLAY is nil, that stands for the selected frame's display.
- DEST may be an integer, in which case it is a Window id.  The value 0 may
- be used to send to the root window of the DISPLAY.
- If DEST is a frame the event is sent to the outer window of that frame.
- Nil means the currently selected frame.
- If DEST is the string "PointerWindow" the event is sent to the window that
- contains the pointer.  If DEST is the string "InputFocus" the event is
- sent to the window that has the input focus.
- FROM is the frame sending the event.  Use nil for currently selected frame.
- MESSAGE-TYPE is the name of an Atom as a string.
- FORMAT must be one of 8, 16 or 32 and determines the size of the values in
- bits.  VALUES is a list of integer and/or strings containing the values to
- send.  If a value is a string, it is converted to an Atom and the value of
- the Atom is sent.  If more values than fits into the event is given,
- the excessive values are ignored.  */)
-      (display, dest, from, message_type, format, values)
-      Lisp_Object display, dest, from, message_type, format, values;
- {
-   struct x_display_info *dpyinfo = check_x_display_info (display);
-   Window wdest;
-   XEvent event;
-   Lisp_Object cons;
-   int i;
-   int max_nr_values = (int) sizeof (event.xclient.data.b);
-   struct frame *f = check_x_frame (from);
-   
-   CHECK_STRING (message_type);
-   CHECK_NUMBER (format);
-   CHECK_CONS (values);
- 
-   for (cons = values; CONSP (cons); cons = XCDR (cons))
-     {
-       Lisp_Object o = XCAR (cons);
- 
-       if (! INTEGERP (o) && ! STRINGP (o))
-         error ("Bad data in VALUES, must be integer or string");
-     }
- 
-   event.xclient.type = ClientMessage;
-   event.xclient.format = XFASTINT (format);
- 
-   if (event.xclient.format != 8 && event.xclient.format != 16
-       && event.xclient.format != 32)
-     error ("FORMAT must be one of 8, 16 or 32");
-   if (event.xclient.format == 16) max_nr_values /= 2;
-   if (event.xclient.format == 32) max_nr_values /= 4;
-   
-   if (FRAMEP (dest) || NILP (dest))
-     {
-       struct frame *fdest = check_x_frame (dest);
-       wdest = FRAME_OUTER_WINDOW (fdest);
-     }
-   else if (STRINGP (dest))
-     {
-       if (strcmp (SDATA (dest), "PointerWindow") == 0)
-         wdest = PointerWindow;
-       else if (strcmp (SDATA (dest), "InputFocus") == 0)
-         wdest = InputFocus;
-       else
-         error ("DEST as a string must be one of PointerWindow or InputFocus");
-     }
-   else
-     {
-       CHECK_NUMBER (dest);
-       wdest = (Window) XFASTINT (dest);
-       if (wdest == 0) wdest = dpyinfo->root_window;
-     }
- 
-   BLOCK_INPUT;
-   for (cons = values, i = 0;
-        CONSP (cons) && i < max_nr_values;
-        cons = XCDR (cons), ++i)
-     {
-       Lisp_Object o = XCAR (cons);
-       long val;
- 
-       if (INTEGERP (o))
-         val = XINT (o);
-       else if (STRINGP (o))
-           val = XInternAtom (dpyinfo->display, SDATA (o), False);
- 
-       if (event.xclient.format == 8)
-         event.xclient.data.b[i] = (char) val;
-       else if (event.xclient.format == 16)
-         event.xclient.data.s[i] = (short) val;
-       else
-         event.xclient.data.l[i] = val;
-     }
- 
-   for ( ; i < max_nr_values; ++i)
-     if (event.xclient.format == 8)
-       event.xclient.data.b[i] = 0;
-     else if (event.xclient.format == 16)
-       event.xclient.data.s[i] = 0;
-     else
-       event.xclient.data.l[i] = 0;
- 
-   event.xclient.message_type
-     = XInternAtom (dpyinfo->display, SDATA (message_type), False);
-   event.xclient.display = dpyinfo->display;
-   event.xclient.window = FRAME_OUTER_WINDOW (f);
- 
-   XSendEvent (dpyinfo->display, wdest, False, 0xffff, &event);
- 
-   XFlush (dpyinfo->display);
-   UNBLOCK_INPUT;
- 
-   return Qnil;
- }
- \f
- /***********************************************************************
  			    Image types
   ***********************************************************************/
  
--- 4284,4289 ----
***************
*** 9593,9616 ****
   ***********************************************************************/
  
  DEFUN ("x-change-window-property", Fx_change_window_property,
!        Sx_change_window_property, 2, 3, 0,
         doc: /* Change window property PROP to VALUE on the X window of FRAME.
! PROP and VALUE must be strings.  FRAME nil or omitted means use the
! selected frame.  Value is VALUE.  */)
!      (prop, value, frame)
!      Lisp_Object frame, prop, value;
  {
    struct frame *f = check_x_frame (frame);
    Atom prop_atom;
  
    CHECK_STRING (prop);
!   CHECK_STRING (value);
  
    BLOCK_INPUT;
    prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
!   XChangeProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
! 		   prop_atom, XA_STRING, 8, PropModeReplace,
! 		   SDATA (value), SCHARS (value));
  
    /* Make sure the property is set when we return.  */
    XFlush (FRAME_X_DISPLAY (f));
--- 9474,9559 ----
   ***********************************************************************/
  
  DEFUN ("x-change-window-property", Fx_change_window_property,
!        Sx_change_window_property, 2, 6, 0,
         doc: /* Change window property PROP to VALUE on the X window of FRAME.
! PROP must be a string.
! VALUE may be a string or a list of conses, numbers and/or strings.
! If an element in the list is a string, it is converted to
! an Atom and the value of the Atom is used.  If an element is a cons,
! it is converted to a 32 bit number where the car is the 16 top bits and the
! cdr is the lower 16 bits.
! FRAME nil or omitted means use the selected frame.
! If TYPE is given and non-nil, it is the name of the type of VALUE.
! If TYPE is not given or nil, the type is STRING.
! FORMAT gives the size in bits of each element if VALUE is a list.
! It must be one of 8, 16 or 32.
! If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8.
! If OUTER_P is non-nil, the property is changed for the outer X window of
! FRAME.  Default is to change on the edit X window.
! 
! Value is VALUE.  */)
!      (prop, value, frame, type, format, outer_p)
!      Lisp_Object frame, prop, value, outer_p;
  {
    struct frame *f = check_x_frame (frame);
    Atom prop_atom;
+   Atom target_type = XA_STRING;
+   int element_format = 8;
+   unsigned char *data;
+   int nelements;
+   Lisp_Object cons;
+   Window w;
  
    CHECK_STRING (prop);
! 
!   if (! NILP (format))
!     {
!       CHECK_NUMBER (format);
!       element_format = XFASTINT (format);
! 
!       if (element_format != 8 && element_format != 16
!           && element_format != 32)
!         error ("FORMAT must be one of 8, 16 or 32");
!     }
! 
!   if (CONSP (value))
!     {
!       nelements = x_check_property_data (value);
!       if (nelements == -1)
!         error ("Bad data in VALUE, must be number, string or cons");
! 
!       if (element_format == 8)
!         data = (unsigned char *) xmalloc (nelements);
!       else if (element_format == 16)
!         data = (unsigned char *) xmalloc (nelements*2);
!       else
!         data = (unsigned char *) xmalloc (nelements*4);
! 
!       x_fill_property_data (FRAME_X_DISPLAY (f), value, data, element_format);
!     }
!   else
!     {
!       CHECK_STRING (value);
!       data = SDATA (value);
!       nelements = SCHARS (value);
!     }
  
    BLOCK_INPUT;
    prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
!   if (! NILP (type))
!     {
!       CHECK_STRING (type);
!       target_type = XInternAtom (FRAME_X_DISPLAY (f), SDATA (type), False);
!     }
! 
!   if (! NILP (outer_p)) w = FRAME_OUTER_WINDOW (f);
!   else w = FRAME_X_WINDOW (f);
!  
!   XChangeProperty (FRAME_X_DISPLAY (f), w,
! 		   prop_atom, target_type, element_format, PropModeReplace,
! 		   data, nelements);
! 
!   if (CONSP (value)) xfree (data);
  
    /* Make sure the property is set when we return.  */
    XFlush (FRAME_X_DISPLAY (f));
***************
*** 9644,9656 ****
  
  
  DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
!        1, 2, 0,
         doc: /* Value is the value of window property PROP on FRAME.
! If FRAME is nil or omitted, use the selected frame.  Value is nil
! if FRAME hasn't a property with name PROP or if PROP has no string
! value.  */)
!      (prop, frame)
!      Lisp_Object prop, frame;
  {
    struct frame *f = check_x_frame (frame);
    Atom prop_atom;
--- 9587,9606 ----
  
  
  DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
!        1, 6, 0,
         doc: /* Value is the value of window property PROP on FRAME.
! If FRAME is nil or omitted, use the selected frame.
! If TYPE is nil or omitted, get the property as a string.  Otherwise TYPE
! is the name of the Atom that denotes the type expected.
! If SOURCE is non-nil, get the property on that window instead of form
! FRAME.  The number 0 denotes the root window.
! If DELETE_P is non-nil, delete the property after retreiving it.
! If VECTOR_RET_P is non-nil, don't return a string but a vector of values.
! 
! Value is nil if FRAME hasn't a property with name PROP or if PROP has
! no value of TYPE.  */)
!      (prop, frame, type, source, delete_p, vector_ret_p)
!      Lisp_Object prop, frame, type, source, delete_p, vector_ret_p;
  {
    struct frame *f = check_x_frame (frame);
    Atom prop_atom;
***************
*** 9658,9671 ****
    Lisp_Object prop_value = Qnil;
    char *tmp_data = NULL;
    Atom actual_type;
    int actual_format;
    unsigned long actual_size, bytes_remaining;
  
    CHECK_STRING (prop);
    BLOCK_INPUT;
    prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
!   rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
! 			   prop_atom, 0, 0, False, XA_STRING,
  			   &actual_type, &actual_format, &actual_size,
  			   &bytes_remaining, (unsigned char **) &tmp_data);
    if (rc == Success)
--- 9608,9650 ----
    Lisp_Object prop_value = Qnil;
    char *tmp_data = NULL;
    Atom actual_type;
+   Atom target_type = XA_STRING;
    int actual_format;
    unsigned long actual_size, bytes_remaining;
+   Window target_window = FRAME_X_WINDOW (f);
+   struct gcpro gcpro1;
  
+   GCPRO1 (prop_value);
    CHECK_STRING (prop);
+ 
+   if (! NILP (source))
+     {
+       if (NUMBERP (source))
+         {
+           if (FLOATP (source))
+             target_window = (Window) XFLOAT (source);
+           else
+             target_window = XFASTINT (source);
+ 
+           if (target_window == 0)
+             target_window = FRAME_X_DISPLAY_INFO (f)->root_window;
+         }
+       else if (CONSP (source))
+         target_window = cons_to_long (source);
+     }
+ 
    BLOCK_INPUT;
+   if (STRINGP (type))
+     {
+       if (strcmp ("AnyPropertyType", SDATA (type)) == 0)
+         target_type = AnyPropertyType;
+       else
+         target_type = XInternAtom (FRAME_X_DISPLAY (f), SDATA (type), False);
+     }
+ 
    prop_atom = XInternAtom (FRAME_X_DISPLAY (f), SDATA (prop), False);
!   rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window,
! 			   prop_atom, 0, 0, False, target_type,
  			   &actual_type, &actual_format, &actual_size,
  			   &bytes_remaining, (unsigned char **) &tmp_data);
    if (rc == Success)
***************
*** 9675,9693 ****
        XFree (tmp_data);
        tmp_data = NULL;
  
!       rc = XGetWindowProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
  			       prop_atom, 0, bytes_remaining,
! 			       False, XA_STRING,
  			       &actual_type, &actual_format,
  			       &actual_size, &bytes_remaining,
  			       (unsigned char **) &tmp_data);
        if (rc == Success && tmp_data)
! 	prop_value = make_string (tmp_data, size);
  
!       XFree (tmp_data);
      }
  
    UNBLOCK_INPUT;
    return prop_value;
  }
  
--- 9654,9682 ----
        XFree (tmp_data);
        tmp_data = NULL;
  
!       rc = XGetWindowProperty (FRAME_X_DISPLAY (f), target_window,
  			       prop_atom, 0, bytes_remaining,
! 			       ! NILP (delete_p), target_type,
  			       &actual_type, &actual_format,
  			       &actual_size, &bytes_remaining,
  			       (unsigned char **) &tmp_data);
        if (rc == Success && tmp_data)
!         {
!           if (NILP (vector_ret_p))
!             prop_value = make_string (tmp_data, size);
!           else
!             prop_value = x_property_data_to_lisp (f,
!                                                   (unsigned char *) tmp_data,
!                                                   actual_type,
!                                                   actual_format,
!                                                   actual_size);
!         }
  
!       if (tmp_data) XFree (tmp_data);
      }
  
    UNBLOCK_INPUT;
+   UNGCPRO;
    return prop_value;
  }
  
***************
*** 11097,11103 ****
    defsubr (&Sx_close_connection);
    defsubr (&Sx_display_list);
    defsubr (&Sx_synchronize);
-   defsubr (&Sx_send_client_message);
    defsubr (&Sx_focus_frame);
    defsubr (&Sx_backspace_delete_keys_p);
  
--- 11086,11091 ----
Index: src/xselect.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xselect.c,v
retrieving revision 1.130
diff -c -c -r1.130 xselect.c
*** src/xselect.c	1 Sep 2003 15:45:58 -0000	1.130
--- src/xselect.c	17 Jan 2004 16:18:21 -0000
***************
*** 30,35 ****
--- 30,38 ----
  #include "blockinput.h"
  #include "buffer.h"
  #include "process.h"
+ #include "termhooks.h"
+ 
+ #include <X11/Xproto.h>
  
  struct prop_location;
  
***************
*** 2278,2283 ****
--- 2281,2640 ----
  
  #endif
  \f
+ /***********************************************************************
+                       Drag and drop support
+ ***********************************************************************/
+ /* Check that lisp values are of correct type for x_fill_property_data.
+    That is, number, string or a cons with two numbers (low and high 16
+    bit parts of a 32 bit number).  */
+ int
+ x_check_property_data (data)
+      Lisp_Object data;
+ {
+   Lisp_Object iter;
+   int size = 0;
+ 
+   for (iter = data; CONSP (iter) && size != -1; iter = XCDR (iter), ++size)
+     {
+       Lisp_Object o = XCAR (iter);
+ 
+       if (! NUMBERP (o) && ! STRINGP (o) && ! CONSP (o))
+         size = -1;
+       else if (CONSP (o) &&
+                (! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o))))
+         size = -1;
+     }
+ 
+   return size;
+ }
+ 
+ /* Convert lisp values to a C array.  Values may be a number, a string
+    which is taken as an X atom name and converted to the atom value, or
+    a cons containing the two 16 bit parts of a 32 bit number.
+ 
+    DPY is the display use to look up X atoms.
+    DATA is a Lisp list of values to be converted.
+    RET is the C array that contains the converted values.  It is assumed
+    it is big enough to hol all values.
+    FORMAT is 8, 16 or 32 and gives the size in bits for each C value to
+    be stored in RET.  */
+ 
+ void
+ x_fill_property_data (dpy, data, ret, format)
+      Display *dpy;
+      Lisp_Object data;
+      void *ret;
+      int format;
+ {
+   CARD32 val;
+   CARD32 *d32 = (CARD32 *) ret;
+   CARD16 *d16 = (CARD16 *) ret;
+   CARD8  *d08 = (CARD8  *) ret;
+   Lisp_Object iter;
+ 
+   for (iter = data; CONSP (iter); iter = XCDR (iter))
+     {
+       Lisp_Object o = XCAR (iter);
+ 
+       if (INTEGERP (o))
+         val = (CARD32) XFASTINT (o);
+       else if (FLOATP (o))
+         val = (CARD32) XFLOAT (o);
+       else if (CONSP (o))
+         val = (CARD32) cons_to_long (o);
+       else if (STRINGP (o))
+         {
+           BLOCK_INPUT;
+           val = XInternAtom (dpy, (char *) SDATA (o), False);
+           UNBLOCK_INPUT;
+         }
+       else
+         error ("Wrong type, must be string, number or cons");
+ 
+       if (format == 8)
+         *d08++ = (CARD8) val;
+       else if (format == 16)
+         *d16++ = (CARD16) val;
+       else
+         *d32++ = val;
+     }
+ }
+ 
+ /* Convert an array of C values to a Lisp list.
+    F is the frame to be used to look up X atoms if the TYPE is XA_ATOM.
+    DATA is a C array of values to be converted.
+    TYPE is the type of the data.  Only XA_ATOM is special, it converts
+    each number in DATA to its corresponfing X atom as a symbol.
+    FORMAT is 8, 16 or 32 and gives the size in bits for each C value to
+    be stored in RET.
+    SIZE is the number of elements in DATA.
+ 
+    Also see comment for selection_data_to_lisp_data above.  */
+ 
+ Lisp_Object
+ x_property_data_to_lisp (f, data, type, format, size)
+      struct frame *f;
+      unsigned char *data;
+      Atom type;
+      int format;
+      unsigned long size;
+ {
+   return selection_data_to_lisp_data (FRAME_X_DISPLAY (f),
+                                       data, size*format/8, type, format);
+ }
+ 
+ /* Get the mouse position in frame relative coordinates.  */
+ static void
+ mouse_position_for_drop (f, x, y)
+      FRAME_PTR f;
+      int *x;
+      int *y;
+ {
+   Window root, dummy_window;
+   int dummy;
+ 
+   BLOCK_INPUT;
+ 
+   XQueryPointer (FRAME_X_DISPLAY (f),
+                  DefaultRootWindow (FRAME_X_DISPLAY (f)),
+ 
+                  /* The root window which contains the pointer.  */
+                  &root,
+ 
+                  /* Window pointer is on, not used  */
+                  &dummy_window,
+ 
+                  /* The position on that root window.  */
+                  x, y,
+ 
+                  /* x/y in dummy_window coordinates, not used.  */
+                  &dummy, &dummy,
+ 
+                  /* Modifier keys and pointer buttons, about which
+                     we don't care.  */
+                  (unsigned int *) &dummy);
+ 
+ 
+   /* Absolute to relative.  */
+   *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
+   *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
+ 
+   UNBLOCK_INPUT;
+ }
+ 
+ DEFUN ("x-get-atom-name", Fx_get_atom_name,
+        Sx_get_atom_name, 1, 2, 0,
+        doc: /* Return the X atom name as a string for VALUE.
+ VALUE may be a number or a cons where the car is the lower 16 bits and
+ the cdr is the upper 16 bits of a 32 bit value.
+ Use the display for FRAME or the current frame if FRAME is not given or nil.
+ 
+ If the value is 0 or the atom is not known, return the empty string.  */)
+   (value, frame)
+      Lisp_Object value, frame;
+ {
+   struct frame *f = check_x_frame (frame);
+   char *name = 0;
+   Lisp_Object ret = Qnil;
+   int count;
+   Display *dpy = FRAME_X_DISPLAY (f);
+   Atom atom;
+ 
+   if (INTEGERP (value))
+     atom = (Atom) XUINT (value);
+   else if (FLOATP (value))
+     atom = (Atom) XFLOAT (value);
+   else if (CONSP (value))
+     atom = (Atom) cons_to_long (value);
+   else
+     error ("Wrong type, value must be number or cons");
+ 
+   BLOCK_INPUT;
+   count = x_catch_errors (dpy);
+ 
+   name = atom ? XGetAtomName (dpy, atom) : "";
+ 
+   if (! x_had_errors_p (dpy))
+     ret = make_string (name, strlen (name));
+ 
+   x_uncatch_errors (dpy, count);
+ 
+   if (atom && name) XFree (name);
+   if (NILP (ret)) ret = make_string ("", 0);
+ 
+   UNBLOCK_INPUT;
+ 
+   return ret;
+ }
+ 
+ /* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT.
+    TODO: Check if this client event really is a DND event?  */
+ int
+ x_handle_dnd_message (f, event, dpyinfo, bufp)
+      struct frame *f;
+      XClientMessageEvent *event;
+      struct x_display_info *dpyinfo;
+      struct input_event *bufp;
+ {
+   Lisp_Object vec;
+   Lisp_Object frame;
+   unsigned long size = (8*sizeof (event->data))/event->format;
+   int x, y;
+ 
+   XSETFRAME (frame, f);
+ 
+   vec = Fmake_vector (4, Qnil);
+   AREF (vec, 0) = SYMBOL_NAME (x_atom_to_symbol (FRAME_X_DISPLAY (f),
+                                                  event->message_type));
+   AREF (vec, 1) = frame;
+   AREF (vec, 2) = XFASTINT (event->format);
+   AREF (vec, 3) = x_property_data_to_lisp (f,
+                                            event->data.b,
+                                            event->message_type,
+                                            event->format,
+                                            size);
+ 
+   mouse_position_for_drop (f, &x, &y);
+   bufp->kind = DRAG_N_DROP_EVENT;
+   bufp->frame_or_window = Fcons (frame, vec);
+   bufp->timestamp = CurrentTime;
+   bufp->x = make_number (x);
+   bufp->y = make_number (y);
+   bufp->arg = Qnil;
+   bufp->modifiers = 0;
+ 
+   return 1;
+ }
+ 
+ DEFUN ("x-send-client-message", Fx_send_client_event,
+        Sx_send_client_message, 6, 6, 0,
+        doc: /* Send a client message of MESSAGE-TYPE to window DEST on DISPLAY.
+ 
+ For DISPLAY, specify either a frame or a display name (a string).
+ If DISPLAY is nil, that stands for the selected frame's display.
+ DEST may be a number, in which case it is a Window id.  The value 0 may
+ be used to send to the root window of the DISPLAY.
+ If DEST is a cons, it is converted to a 32 bit number
+ with the high 16 bits from the car and the lower 16 bit from the cdr.  That
+ number is then used as a window id.
+ If DEST is a frame the event is sent to the outer window of that frame.
+ Nil means the currently selected frame.
+ If DEST is the string "PointerWindow" the event is sent to the window that
+ contains the pointer.  If DEST is the string "InputFocus" the event is
+ sent to the window that has the input focus.
+ FROM is the frame sending the event.  Use nil for currently selected frame.
+ MESSAGE-TYPE is the name of an Atom as a string.
+ FORMAT must be one of 8, 16 or 32 and determines the size of the values in
+ bits.  VALUES is a list of numbers, cons and/or strings containing the values
+ to send.  If a value is a string, it is converted to an Atom and the value of
+ the Atom is sent.  If a value is a cons, it is converted to a 32 bit number
+ with the high 16 bits from the car and the lower 16 bit from the cdr.
+ If more values than fits into the event is given, the excessive values
+ are ignored.  */)
+      (display, dest, from, message_type, format, values)
+      Lisp_Object display, dest, from, message_type, format, values;
+ {
+   struct x_display_info *dpyinfo = check_x_display_info (display);
+   Window wdest;
+   XEvent event;
+   Lisp_Object cons;
+   int size;
+   struct frame *f = check_x_frame (from);
+   int count;
+   int to_root;
+ 
+   CHECK_STRING (message_type);
+   CHECK_NUMBER (format);
+   CHECK_CONS (values);
+ 
+   if (x_check_property_data (values) == -1)
+     error ("Bad data in VALUES, must be number, cons or string");
+ 
+   event.xclient.type = ClientMessage;
+   event.xclient.format = XFASTINT (format);
+ 
+   if (event.xclient.format != 8 && event.xclient.format != 16
+       && event.xclient.format != 32)
+     error ("FORMAT must be one of 8, 16 or 32");
+   
+   if (FRAMEP (dest) || NILP (dest))
+     {
+       struct frame *fdest = check_x_frame (dest);
+       wdest = FRAME_OUTER_WINDOW (fdest);
+     }
+   else if (STRINGP (dest))
+     {
+       if (strcmp (SDATA (dest), "PointerWindow") == 0)
+         wdest = PointerWindow;
+       else if (strcmp (SDATA (dest), "InputFocus") == 0)
+         wdest = InputFocus;
+       else
+         error ("DEST as a string must be one of PointerWindow or InputFocus");
+     }
+   else if (INTEGERP (dest))
+     wdest = (Window) XFASTINT (dest);
+   else if (FLOATP (dest))
+     wdest =  (Window) XFLOAT (dest);
+   else if (CONSP (dest))
+     {
+       if (! NUMBERP (XCAR (dest)) || ! NUMBERP (XCDR (dest)))
+         error ("Both car and cdr for DEST must be numbers");
+       else
+         wdest = (Window) cons_to_long (dest);
+     }
+   else
+     error ("DEST must be a frame, nil, string, number or cons");
+ 
+   if (wdest == 0) wdest = dpyinfo->root_window;
+   to_root = wdest == dpyinfo->root_window;
+ 
+   for (cons = values, size = 0; CONSP (cons); cons = XCDR (cons), ++size)
+     ;
+ 
+   BLOCK_INPUT;
+ 
+   event.xclient.message_type
+     = XInternAtom (dpyinfo->display, SDATA (message_type), False);
+   event.xclient.display = dpyinfo->display;
+ 
+   /* Some clients (metacity for example) expects sending window to be here
+      when sending to the root window.  */
+   event.xclient.window = to_root ? FRAME_OUTER_WINDOW (f) : wdest;
+   memset (event.xclient.data.b, 0, sizeof (event.xclient.data.b));
+ 
+   x_fill_property_data (dpyinfo->display, values, event.xclient.data.b,
+                         event.xclient.format);
+ 
+   /* If event mask is 0 the event is sent to the client that created
+      the destination window.  But if we are sending to the root window,
+      there is no such client.  Then we set the event mask to 0xffff.  The
+      event then goes to clients selecting for events on the root window.  */
+   count = x_catch_errors (dpyinfo->display);
+   {
+     int propagate = to_root ? False : True;
+     unsigned mask = to_root ? 0xffff : 0;
+     XSendEvent (dpyinfo->display, wdest, propagate, mask, &event);
+   }
+ 
+   XFlush (dpyinfo->display);
+   x_uncatch_errors (dpyinfo->display, count);
+   UNBLOCK_INPUT;
+ 
+ #if 0
+   fprintf(stderr, "XSend: dest 0x%x, type %d format %d "
+           "[0x%x 0x%x 0x%x 0x%x 0x%x]\n",
+           wdest, event.xclient.message_type, event.xclient.format,
+           event.xclient.data.l[0],
+           event.xclient.data.l[1],
+           event.xclient.data.l[2],
+           event.xclient.data.l[3],
+           event.xclient.data.l[4]);
+ #endif
+ 
+   return Qnil;
+ }
+ 
+ \f
  void
  syms_of_xselect ()
  {
***************
*** 2292,2297 ****
--- 2649,2657 ----
    defsubr (&Sx_store_cut_buffer_internal);
    defsubr (&Sx_rotate_cut_buffers_internal);
  #endif
+ 
+   defsubr (&Sx_get_atom_name);
+   defsubr (&Sx_send_client_message);
  
    reading_selection_reply = Fcons (Qnil, Qnil);
    staticpro (&reading_selection_reply);
Index: src/xterm.c
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xterm.c,v
retrieving revision 1.825
diff -c -c -r1.825 xterm.c
*** src/xterm.c	16 Jan 2004 18:47:40 -0000	1.825
--- src/xterm.c	17 Jan 2004 16:18:31 -0000
***************
*** 5934,5940 ****
            }
  #endif /* USE_TOOLKIT_SCROLL_BARS */
          else
!           goto OTHER;
        }
        break;
  
--- 5934,5958 ----
            }
  #endif /* USE_TOOLKIT_SCROLL_BARS */
          else
!           {
!             struct frame *f
!               = x_any_window_to_frame (dpyinfo, event.xclient.window);
! 
!             if (f)
!               {
!                 int ret = x_handle_dnd_message (f, &event.xclient,
!                                                 dpyinfo, bufp);
!                 if (ret > 0)
!                   {
!                     ++bufp, ++count, --numchars;
!                   }
! 
!                 if (ret != 0)
!                   *finish = X_EVENT_DROP;
!               }
!             else
!               goto OTHER;
!           }
        }
        break;
  
Index: src/xterm.h
===================================================================
RCS file: /cvsroot/emacs/emacs/src/xterm.h,v
retrieving revision 1.156
diff -c -c -r1.156 xterm.h
*** src/xterm.h	16 Nov 2003 16:05:21 -0000	1.156
--- src/xterm.h	17 Jan 2004 16:18:31 -0000
***************
*** 1006,1013 ****
--- 1006,1029 ----
  extern void x_handle_selection_clear P_ ((struct input_event *));
  extern void x_clear_frame_selections P_ ((struct frame *));
  
+ extern int x_handle_dnd_message P_ ((struct frame *,
+                                      XClientMessageEvent *,
+                                      struct x_display_info *,
+                                      struct input_event *bufp));
+ extern int x_check_property_data P_ ((Lisp_Object));
+ extern void x_fill_property_data P_ ((Display *,
+                                       Lisp_Object,
+                                       void *,
+                                       int));
+ extern Lisp_Object x_property_data_to_lisp P_ ((struct frame *,
+                                                 unsigned char *,
+                                                 Atom,
+                                                 int,
+                                                 unsigned long));
+ 
  /* Defined in xfns.c */
  
+ extern struct x_display_info * check_x_display_info P_ ((Lisp_Object frame));
  extern int have_menus_p P_ ((void));
  extern int x_bitmap_height P_ ((struct frame *, int));
  extern int x_bitmap_width P_ ((struct frame *, int));
*** /dev/null	1970-01-01 01:00:00.000000000 +0100
--- lisp/x-dnd.el	2004-01-17 16:38:43.000000000 +0100
***************
*** 0 ****
--- 1,310 ----
+ 
+ (defvar x-dnd-debug nil
+   "Set to non-nil to get debugging messages from X drag and drop code.")
+ 
+ (defvar x-dnd-current-type nil
+   "The type (Atom name) we want the DND data to be in for the current drop.
+ TODO: There should be one of these per display.  How to do that?")
+ 
+ (defun x-dnd-debug (string &rest args)
+   "If x-dnd-debug is non-nil, call message with STRING and ARGS."
+   (if x-dnd-debug (message "%s" (apply 'format string args))))
+ 
+ 
+ (defun x-dnd-init-frame (&optional frame)
+   "Setup drag and drop for FRAME (i.e. create appropriate properties)."
+   (x-dnd-init-xdnd-for-frame frame))
+ 
+ (defun x-dnd-handle-one-drop (arg &optional split_p)
+   "Opens ARG if it is a file.  If not a file, do nothing.
+ If SPLIT_P is non-nil, split the window before opening the file."
+   (x-dnd-debug "DND: %s" arg)
+   (let* ((uri (replace-regexp-in-string
+ 	       "%[A-Z0-9][A-Z0-9]"
+ 	       (lambda (arg)
+ 		 (format "%c" (string-to-number (substring arg 1) 16)))
+ 	       arg))
+ 	 (f (cond ((string-match "^file:///" uri)	;; XDND format.
+ 		   (substring uri (1- (match-end 0))))
+ 		  ((string-match "^file://" uri)	;; URI with host
+ 		   nil)					;; Skip for now.
+ 		  ((string-match "^file:" uri)		;; Old KDE, Motif, Sun
+ 		   (substring uri (match-end 0)))
+ 		  ((string-match "^[a-z]+://" uri)	;; http:// and such.
+ 		   (progn ;; Ignore other URI:s for now.
+ 		     (message "DND: ignoring '%s'" uri)
+ 		     nil))
+ 
+ 		  (t (error "Bad URI ignored: %s" uri)))))
+     (if f
+ 	(let* ((decoded-f (decode-coding-string 
+ 			  f
+ 			  (or file-name-coding-system
+ 			      default-file-name-coding-system)))
+ 	       (try-f (if (file-readable-p decoded-f) decoded-f f)))
+ 	  (if (file-readable-p try-f)
+ 	      (progn
+ 		(if split_p (split-window))
+ 		(find-file try-f))
+ 	    (error "Can not read %s (%s)" try-f f))))))
+ 
+ (defvar x-dnd-known-types
+   '(("text/uri-list" 6)
+     ("text/x-moz-url" 5 nil xdnd-handle-moz-url)
+     ("FILE_NAME" 4)
+     ("_NETSCAPE_URL" 3)
+     ("UTF8_STRING" 2 t xdnd-decode-utf8)
+     ("text/plain;charset=UTF-8" 2 t xdnd-decode-utf8)
+     ("text/plain;charset=utf-8" 2 t xdnd-decode-utf8)
+     ("STRING" 1 t)
+     ("TEXT"   1 t)
+     ("text/plain" 1 t)
+     )
+   "The types accepted for dropped data.
+ The list elements are: type order is-text special-handling-function")
+ 
+ (defun xdnd-decode-utf8 (data type)
+   "Decode DATA that is in utf-8 format."
+   (x-dnd-debug "decode-utf8: '%s' %s'" data type)
+   (decode-coding-string data 'utf-8))
+ 
+ (defun xdnd-handle-moz-url (data type)
+   "Handle one item of type text/x-moz-url, returning just the URL.
+ DATA is the moz-url, which is formatted as two strings separated by \r\n.
+ The first string is the URL, the second string is the title of that URL.
+ DATA is encoded in utf-16."
+   (let* ((string (decode-coding-string data 'utf-16le))  ;; ALWAYS LE???
+ 	 (strings (split-string string "[\r\n]" t))
+ 	 ;; Can one drop more than one moz-url ??  Assume not.
+ 	 (url (car strings))
+ 	 (title (car (cdr strings))))
+     (setq last-moz data)
+     (set-text-properties 0 (length url)
+ 			 (list 'original-url string 'title title)
+ 			 url)
+     url))
+ 
+ (defun x-dnd-type-is-text (type)
+   "Return t if TYPE is defined as a text type in `x-dnd-known-types'."
+   (let ((type-info (assoc type x-dnd-known-types)))
+     (and type-info (nth 2 type-info))))
+ 
+ (defun x-dnd-choose-type (types)
+   "Choose which type we want to receive for the drop.
+ TYPES are the types the source of the drop offers.  Select among these
+ according to `x-dnd-known-types' and return that type name.  If no suitable
+ type is found, return nil."
+   (x-dnd-debug "DND types: %s" types)
+   (let ((w -1)
+ 	(pref nil))
+     (dotimes (i (length types))
+       (let* ((type (aref types i))
+ 	     (typename (if (stringp type) type 
+ 			 (symbol-name type)))
+ 	     (typeinfo (assoc typename x-dnd-known-types))
+ 	     (weight (if typeinfo (nth 1 typeinfo)
+ 		       -1)))
+ 	(if (and (> weight 0) (> weight w))
+ 	    (setq w weight pref typename))))
+     pref))
+ 
+ (defun x-dnd-drop-data (event frame data type)
+   "Drop one data item onto a frame.
+ EVENT is the client message for the drop, FRAME is the frame the drop occurred
+ on.  DATA is the data received from the source, and type is the type
+ for DATA (see `x-dnd-known-types').
+ 
+ Return t if drop was successful, nil if not."
+   (let* ((type-info (assoc type x-dnd-known-types))
+ 	 (preprocess (nth 3 type-info))
+ 	 (dropvalue (if preprocess
+ 			(funcall preprocess data type)
+ 		      data))
+ 	 (w (posn-window (event-start event))))
+     (if (x-dnd-type-is-text type)
+ 	(let* ((buffer (window-buffer w)))
+ 	  (progn
+ 	    (select-window w)
+ 	    (set-buffer buffer)
+ 	    (barf-if-buffer-read-only)
+ 	    (goto-char (posn-point (event-start event)))
+ 	    (insert (replace-regexp-in-string "\0$" "" dropvalue))
+ 	    t)
+ 	  nil)
+       (progn  ;; Dropping URL:s
+ 	(select-frame frame)
+ 	(when (windowp w) (select-window w))
+ 	(x-dnd-handle-uri-list dropvalue)
+ 	t))))
+ 
+ (defun x-dnd-handle-uri-list (string)
+   "Split an uri-list into separate URIs and call `x-dnd-handle-one-drop'.
+ STRING is the uri-list as a string.  The URIs are separated by \r\n."
+   (let ((uri-list (split-string string "[\0\r\n]" t)))
+     (mapcar 'x-dnd-handle-one-drop uri-list)))
+ 
+ (defun x-dnd-handle-drag-n-drop-event (event)
+   "Receive drag and drop events (X client messages).
+ Currently XDND and old KDE 1.x protocols are recognized.
+ TODO: Add Motif and OpenWindows."
+   (interactive "e")
+   (let* ((client-message (car (cdr (cdr event))))
+ 	 (window (posn-window (event-start event)))
+ 	 (message-atom (aref client-message 0))
+ 	 (frame (aref client-message 1))
+ 	 (format (aref client-message 2))
+ 	 (data (aref client-message 3)))
+ 
+     (cond ((equal "DndProtocol" message-atom)	;; Old KDE 1.x.
+ 	   (x-dnd-handle-old-kde event frame message-atom format data))
+ 
+ 	  ((and (> (length message-atom) 4)	;; XDND protocol.
+ 		(equal "Xdnd" (substring message-atom 0 4)))
+ 	   (x-dnd-handle-xdnd event frame message-atom format data))
+ 
+ 	  (t (error "Unknown DND atom: %s" message-atom)))))
+ 
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;;  Old KDE protocol.  Only dropping of files.
+ 
+ (defun x-dnd-handle-old-kde (event frame message format data)
+   "Open the files in a KDE 1.x drop."
+   (let ((values (x-window-property "DndSelection" frame nil 0 t)))
+     (x-dnd-handle-uri-list (replace-regexp-in-string "\0$" "" values))))
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 
+ 
+ 
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ ;;  XDND protocol.
+ 
+ (defun x-dnd-init-xdnd-for-frame (frame)
+   "Set the XdndAware for FRAME to indicate that we do XDND."
+   (x-change-window-property "XdndAware"
+ 			    '(5)	;; The version of XDND we support.
+ 			    frame "ATOM" 32 t))
+ 
+ (defun x-dnd-get-drop-width-height (frame w accept)
+   "Return the widht/height to be sent in a XDndStatus message.
+ FRAME is the frame and W is the window where the drop happened.
+ If ACCEPT is nil return 0 (empty rectangle),
+ otherwise if W is a window, return its widht/height,
+ otherwise return the frame width/height."
+   (if accept
+       (if (windowp w)   ;; w is not a window if dropping on the menu bar,
+ 			;; scroll bar or tool bar.
+ 	  (let ((edges (window-inside-pixel-edges w)))
+ 	    (cons
+ 	     (- (nth 2 edges) (nth 0 edges))	;; right - left
+ 	     (- (nth 3 edges) (nth 1 edges))))	;; bottom - top
+ 	(cons (frame-pixel-width frame)
+ 	      (frame-pixel-height frame)))
+     0))
+ 
+ (defun x-dnd-get-drop-x-y (frame w)
+   "Return the x/y coordinates to be sent in a XDndStatus message.
+ Coordinates are required to be absolute.
+ FRAME is the frame and W is the window where the drop happened.
+ If W is a window, return its absolute corrdinates,
+ otherwise return the frame coordinates."
+   (let* ((frame-left (frame-parameter frame 'left))
+ 	 ;; If the frame is outside the display, frame-left looks like
+ 	 ;; '(0 -16).  Extract the -16.
+ 	 (frame-real-left (if (consp frame-left) (car (cdr frame-left))
+ 			    frame-left))
+ 	 (frame-top (frame-parameter frame 'top))
+ 	 (frame-real-top (if (consp frame-top) (car (cdr frame-top))
+ 			   frame-top)))
+     (if (windowp w)
+ 	(let ((edges (window-inside-pixel-edges w)))
+ 	  (cons
+ 	   (+ frame-real-left (nth 0 edges))
+ 	   (+ frame-real-top (nth 1 edges))))
+     (cons frame-real-left frame-real-top))))
+ 
+ (defun x-dnd-handle-xdnd (event frame message format data)
+   "Receive one XDND event (client message) and send the appropriate reply.
+ EVENT is the client message.  FRAME is where the mouse is now.
+ FORMAT is 32 (not used).  MESSAGE is the data part of an XClientMessageEvent."
+   (x-dnd-debug "Xdnd: %s %s %s" message format data)
+   (cond ((equal "XdndEnter" message)
+ 	 (let ((version (ash (car (aref data 1)) -8))
+ 	       (more-than-3 (cdr (aref data 1)))
+ 	       (dnd-source (aref data 0)))
+ 	   (setq x-dnd-current-type
+ 		 (x-dnd-choose-type
+ 		  (if (> more-than-3 0)
+ 		      (x-window-property "XdndTypeList"
+ 					 frame "AnyPropertyType"
+ 					 dnd-source nil t)
+ 		    (vector (x-get-atom-name (aref data 2))
+ 			    (x-get-atom-name (aref data 3))
+ 			    (x-get-atom-name (aref data 4))))))
+ 	   (x-dnd-debug "Version %s, more-than-3 %s, dnd-source %s pref %s"
+ 			version more-than-3 dnd-source x-dnd-current-type)))
+ 
+ 	((equal "XdndPosition" message)
+ 	 (let* ((x (car (aref data 2)))
+ 		(y (cdr (aref data 2)))
+ 		(action (x-get-atom-name (aref data 4)))
+ 		(dnd-source (aref data 0))
+ 		(dnd-time (aref data 3))
+ 		(w (posn-window (event-start event)))
+ 		(accept ;; 1 = accept, 0 = reject
+ 			;; Reject if dropping text and the mouse is not over
+ 			;; a window (i.e. menu bar or scroll bar) or
+ 			;; mouse is over a read only buffer.
+ 		 (if (x-dnd-type-is-text x-dnd-current-type)
+ 		     (if (and (windowp w)
+ 			      (window-live-p w)
+ 			      (not (buffer-local-value 
+ 				    'buffer-read-only
+ 				    (window-buffer w))))
+ 			 1
+ 		       0)
+ 		     1))
+ 		(list-to-send
+ 		 (list (string-to-number
+ 			(frame-parameter frame 'outer-window-id))
+ 		       accept ;; 1 = Accept, 0 = reject.
+ 		       (x-dnd-get-drop-x-y frame w)
+ 		       (x-dnd-get-drop-width-height frame w (eq accept 1))
+ 		       "XdndActionPrivate"		;; Always use private.
+ 		       )))
+ 	   (x-send-client-message
+ 	    frame dnd-source frame "XdndStatus" 32 list-to-send)
+ 	   (x-dnd-debug "Status %s" list-to-send)
+ 	 ))
+ 
+ 	((equal "XdndLeave" message)
+ 	 (setq x-dnd-current-type nil)
+ 	 (x-dnd-debug "Leave %s" data))
+ 
+ 	((equal "XdndDrop" message)
+ 	 (let* ((dnd-source (aref data 0))
+ 		(value (and x-dnd-current-type
+ 			    (x-get-selection-internal
+ 			     'XdndSelection
+ 			     (intern x-dnd-current-type))))
+ 		(success 
+ 		 (if (and value
+ 			  (condition-case nil
+ 			      (x-dnd-drop-data event frame value 
+ 					       x-dnd-current-type)
+ 			    (error nil)))
+ 		     1
+ 		   0)))
+ 	   (x-dnd-debug "Drop success %s" success)
+ 	   (x-send-client-message
+ 	    frame dnd-source frame "XdndFinished" 32
+ 	    (list (string-to-number (frame-parameter frame 'outer-window-id))
+ 		  success	;; 1 = Success, 0 = Error
+ 		  (if success "XdndActionPrivate" 0)
+ 		  ))
+ 	   (setq x-dnd-current-type nil)))
+ 
+ 	(t (error "Unknown XDND message %s %s" message data))))
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ 
+ 
+ (provide 'x-dnd)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-17 16:35 Drag and drop patch for X, please review Jan D.
@ 2004-01-17 20:20 ` David Kastrup
  2004-01-18 20:22   ` Jan D.
  2004-01-18  0:40 ` Miles Bader
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 56+ messages in thread
From: David Kastrup @ 2004-01-17 20:20 UTC (permalink / raw)
  Cc: emacs-devel

"Jan D." <jan.h.d@swipnet.se> writes:

> The enclosed patch adds drag and drop support (well, actually only
> drop) in X to Emacs.  The protocols supported are XDND (the most
> used nowdays, by Mozilla, OpenOffice, Gnome, KDE etc.) and the old
> KDE 1.x protocol.  You can currently drop file names and text.
> Files will be opened and text inserted (at mouse position).  Http
> urls and such are just ignored, probably there is something more
> intelligent one could do, suggestions?

You could call browse-url on them.  My browse-url handles the mailto:
protocol within Emacs.

One could also call the handlers of browse-url for all treated URL
types, and for the rest insert <URL:http://the.link.address> into the
buffer.

-- 
David Kastrup, Kriemhildstr. 15, 44793 Bochum

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-17 16:35 Drag and drop patch for X, please review Jan D.
  2004-01-17 20:20 ` David Kastrup
@ 2004-01-18  0:40 ` Miles Bader
  2004-01-18 20:44   ` Jan D.
  2004-01-18 19:14 ` Richard Stallman
  2004-01-18 19:16 ` Richard Stallman
  3 siblings, 1 reply; 56+ messages in thread
From: Miles Bader @ 2004-01-18  0:40 UTC (permalink / raw)
  Cc: emacs-devel

On Sat, Jan 17, 2004 at 05:35:19PM +0100, Jan D. wrote:
> You can currently drop file names and text.  Files will be opened
> and text inserted (at mouse position).  Http urls and such are just
> ignored, probably there is something more intelligent one could do,
> suggestions?

It should just use an alist of (DND-TYPE . FUNCTION) pairs so the user can
define his own preferences (in the case where there's some subtyping, e.g., I
see you checking if the data is `some text type', you could look for more
specific type in the alist first, and if not found, look for a more generic
supertype like`text').

Personally, I'd like URLs to be just inserted, as I _very_ often want to copy
a url from mozilla into a mail message or something, and having such an
alist would make it simple for me to implement this.

-Miles
-- 
Yo mama's so fat when she gets on an elevator it HAS to go down.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-17 16:35 Drag and drop patch for X, please review Jan D.
  2004-01-17 20:20 ` David Kastrup
  2004-01-18  0:40 ` Miles Bader
@ 2004-01-18 19:14 ` Richard Stallman
  2004-01-18 21:02   ` Jan D.
  2004-01-18 19:16 ` Richard Stallman
  3 siblings, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-18 19:14 UTC (permalink / raw)
  Cc: emacs-devel

It is good that you could implement this mostly in Lisp;
that makes it easier to customize and adapt.
Thanks for improving the doc strings.

Could you put a blank line between a function definition
and the preceding comment?

If the user drops an icon representing a file into a Dired buffer,
I think it should rename or copy the file into that directory.
That is what drag-and-drop was used for originally on
the Mac: to move files between directories.  But I don't
see any code here to do rename or copy.

Does the current protocol handle dragging and dropping of files in any
way?  I don't see anything in x-dnd-known-types for files.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-17 16:35 Drag and drop patch for X, please review Jan D.
                   ` (2 preceding siblings ...)
  2004-01-18 19:14 ` Richard Stallman
@ 2004-01-18 19:16 ` Richard Stallman
  3 siblings, 0 replies; 56+ messages in thread
From: Richard Stallman @ 2004-01-18 19:16 UTC (permalink / raw)
  Cc: emacs-devel

It is good that you could implement this mostly in Lisp;
that makes it much easier to customize.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-17 20:20 ` David Kastrup
@ 2004-01-18 20:22   ` Jan D.
  2004-01-18 21:50     ` Kim F. Storm
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-18 20:22 UTC (permalink / raw)
  Cc: emacs-devel

>
>> The enclosed patch adds drag and drop support (well, actually only
>> drop) in X to Emacs.  The protocols supported are XDND (the most
>> used nowdays, by Mozilla, OpenOffice, Gnome, KDE etc.) and the old
>> KDE 1.x protocol.  You can currently drop file names and text.
>> Files will be opened and text inserted (at mouse position).  Http
>> urls and such are just ignored, probably there is something more
>> intelligent one could do, suggestions?
>
> You could call browse-url on them.  My browse-url handles the mailto:
> protocol within Emacs.

I will do that, it is probably the best thing to do.

> One could also call the handlers of browse-url for all treated URL
> types, and for the rest insert <URL:http://the.link.address> into the
> buffer.

It would be nice if I could give it to browse-url first and then catch
the error if there is no handler, but that doesn't seem to work since
by default it seems that browse-url justs hands off the url to a
browser (if I am reading it correctly).

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18  0:40 ` Miles Bader
@ 2004-01-18 20:44   ` Jan D.
  2004-01-18 21:34     ` Kai Grossjohann
                       ` (2 more replies)
  0 siblings, 3 replies; 56+ messages in thread
From: Jan D. @ 2004-01-18 20:44 UTC (permalink / raw)
  Cc: emacs-devel

> On Sat, Jan 17, 2004 at 05:35:19PM +0100, Jan D. wrote:
>> You can currently drop file names and text.  Files will be opened
>> and text inserted (at mouse position).  Http urls and such are just
>> ignored, probably there is something more intelligent one could do,
>> suggestions?
>
> It should just use an alist of (DND-TYPE . FUNCTION) pairs so the user 
> can
> define his own preferences (in the case where there's some subtyping, 
> e.g., I
> see you checking if the data is `some text type', you could look for 
> more
> specific type in the alist first, and if not found, look for a more 
> generic
> supertype like`text').

There is one problem with this, I need to know beforehand what Emacs
is going to to with the URL to tell the drop source if Emacs is 
accepting
the URL or not.  Consider dropping text that will be inserted in a 
buffer.
It is not useful (or easy to make it work correctly) to drop that on the
tool bar, menu bar or scroll bar.  If you have multiple windows in the
frame, it is hard to select the one the user intended.  Also, if the
buffer is read only, we don't want to accept a drop there.  So currently
these kind of drops are not accepted.  But dropping a file on the menu
bar or on a read only buffer window is useful, it justs open the file 
in a
new window.

So if the user redefines say the uri-list type to insert the text 
instead,
how can the drop code then know that it is supposed to accept the drop
only in writable buffer windows?

> Personally, I'd like URLs to be just inserted, as I _very_ often want 
> to copy
> a url from mozilla into a mail message or something, and having such an
> alist would make it simple for me to implement this.

I agree that the customizing aspect is important, but I just don't
know how to handle the accept/reject thing.  Maybe we can let the user
put different priorities on types, so for example plain/text is
preferred before plan/uri-list?  That way the text of an URL will
be inserted.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 19:14 ` Richard Stallman
@ 2004-01-18 21:02   ` Jan D.
  2004-01-19 20:12     ` Richard Stallman
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-18 21:02 UTC (permalink / raw)
  Cc: emacs-devel

> It is good that you could implement this mostly in Lisp;
> that makes it easier to customize and adapt.
> Thanks for improving the doc strings.
>
> Could you put a blank line between a function definition
> and the preceding comment?

Yes.

> If the user drops an icon representing a file into a Dired buffer,
> I think it should rename or copy the file into that directory.
> That is what drag-and-drop was used for originally on
> the Mac: to move files between directories.  But I don't
> see any code here to do rename or copy.

If we know the target is a dired buffer, we can then accept the
action that the source sends us (XdndActionCopy or XdndActionMove)
instead of always using XdndActionPrivate and to the right thing
for each action.

> Does the current protocol handle dragging and dropping of files in any
> way?  I don't see anything in x-dnd-known-types for files.

The types text/uri-list, text/x-moz-url, FILE_NAME and _NETSCAPE_URL all
can have file:// URLs.  text/uri-list is the one XDND and the 
freedesktop
organization wants everybody to use.  text/x-moz-url is used by mozilla
and newer netscape.  FILE_NAME is used by the OpenWindows protocol (and
maybe older programs that don't do XDND, but Motif or OpenWindows),
_NETSCAPE_URL are older netscape (4.x and older).

So the file code is just handling the file:/// URLs.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 21:50     ` Kim F. Storm
@ 2004-01-18 21:09       ` Jan D.
  0 siblings, 0 replies; 56+ messages in thread
From: Jan D. @ 2004-01-18 21:09 UTC (permalink / raw)
  Cc: David Kastrup, emacs-devel

> "Jan D." <jan.h.d@swipnet.se> writes:
>
>>> You could call browse-url on them.  My browse-url handles the mailto:
>>> protocol within Emacs.
>>
>> I will do that, it is probably the best thing to do.
>
> I don't think so.
>
> If I want to open the URL in a browser, I will drag it into my browser.
>
> For emacs, I would prefer if it just inserts the URL in the buffer.
>
> Or at least that I can choose that behaviour over browse-url with a
> user option.

The idea was to automatically get any customizations that may have been
done on protocols such as news: and mail:.  I realize that dropping
something on Emacs and then get Mozilla to open up may be a bit
confusing :-).
But I guess we can do as David suggested, try all the handlers manually
first.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 22:10     ` Kim F. Storm
@ 2004-01-18 21:14       ` Jan D.
  0 siblings, 0 replies; 56+ messages in thread
From: Jan D. @ 2004-01-18 21:14 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader

>> There is one problem with this, I need to know beforehand what Emacs
>> is going to to with the URL to tell the drop source if Emacs is
>> accepting
>> the URL or not.  Consider dropping text that will be inserted in a
>> buffer.
>> It is not useful (or easy to make it work correctly) to drop that on 
>> the
>> tool bar, menu bar or scroll bar.  If you have multiple windows in the
>> frame, it is hard to select the one the user intended.  Also, if the
>> buffer is read only, we don't want to accept a drop there.  So 
>> currently
>> these kind of drops are not accepted.
>
> In those cases, it could just copy the url to the kill-ring and print a
> suitable message in the echo area, e.g. Use C-y to insert the dropped 
> URL.

That is a very good suggestion, I'll try it.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 20:44   ` Jan D.
@ 2004-01-18 21:34     ` Kai Grossjohann
  2004-01-18 21:55       ` Jan D.
  2004-01-18 22:10     ` Kim F. Storm
  2004-01-19 18:24     ` Stefan Monnier
  2 siblings, 1 reply; 56+ messages in thread
From: Kai Grossjohann @ 2004-01-18 21:34 UTC (permalink / raw)


"Jan D." <jan.h.d@swipnet.se> writes:

>> It should just use an alist of (DND-TYPE . FUNCTION) pairs so the
>> user can define his own preferences (in the case where there's some
>> subtyping, e.g., I see you checking if the data is `some text
>> type', you could look for more specific type in the alist first,
>> and if not found, look for a more generic supertype like`text').
>
> [...]
>
> I agree that the customizing aspect is important, but I just don't
> know how to handle the accept/reject thing.

Well, err, the obvious idea is to have (DND-TYPE TEST FUNCTION)
triples instead of pairs, where the TEST has an arg specifying where
the drag is going to happen.

But since it is so obvious, you have surely thought about it and
rejected it.  What was the reason for rejecting this idea?

Kai

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 20:22   ` Jan D.
@ 2004-01-18 21:50     ` Kim F. Storm
  2004-01-18 21:09       ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Kim F. Storm @ 2004-01-18 21:50 UTC (permalink / raw)
  Cc: David Kastrup, emacs-devel

"Jan D." <jan.h.d@swipnet.se> writes:

> > You could call browse-url on them.  My browse-url handles the mailto:
> > protocol within Emacs.
> 
> I will do that, it is probably the best thing to do.

I don't think so.

If I want to open the URL in a browser, I will drag it into my browser.

For emacs, I would prefer if it just inserts the URL in the buffer.

Or at least that I can choose that behaviour over browse-url with a
user option.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 21:34     ` Kai Grossjohann
@ 2004-01-18 21:55       ` Jan D.
  2004-01-18 23:08         ` Miles Bader
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-18 21:55 UTC (permalink / raw)
  Cc: emacs-devel


>>
>> I agree that the customizing aspect is important, but I just don't
>> know how to handle the accept/reject thing.
>
> Well, err, the obvious idea is to have (DND-TYPE TEST FUNCTION)
> triples instead of pairs, where the TEST has an arg specifying where
> the drag is going to happen.
>
> But since it is so obvious, you have surely thought about it and
> rejected it.  What was the reason for rejecting this idea?

I thought that would be too complex for a user to customize.  For 
example,
going by the discussion, we want different behaviour if dropping to
a menu bar, dired buffer, read only buffer, or writable buffer.   It may
be that I think this is more complex than it actually is, though.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 20:44   ` Jan D.
  2004-01-18 21:34     ` Kai Grossjohann
@ 2004-01-18 22:10     ` Kim F. Storm
  2004-01-18 21:14       ` Jan D.
  2004-01-19 18:24     ` Stefan Monnier
  2 siblings, 1 reply; 56+ messages in thread
From: Kim F. Storm @ 2004-01-18 22:10 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader

"Jan D." <jan.h.d@swipnet.se> writes:

> There is one problem with this, I need to know beforehand what Emacs
> is going to to with the URL to tell the drop source if Emacs is
> accepting
> the URL or not.  Consider dropping text that will be inserted in a
> buffer.
> It is not useful (or easy to make it work correctly) to drop that on the
> tool bar, menu bar or scroll bar.  If you have multiple windows in the
> frame, it is hard to select the one the user intended.  Also, if the
> buffer is read only, we don't want to accept a drop there.  So currently
> these kind of drops are not accepted.  

In those cases, it could just copy the url to the kill-ring and print a
suitable message in the echo area, e.g. Use C-y to insert the dropped URL.

>                                        But dropping a file on the menu
> bar or on a read only buffer window is useful, it justs open the file
> in a
> new window.

That's fine.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 21:55       ` Jan D.
@ 2004-01-18 23:08         ` Miles Bader
  2004-01-19 20:12           ` Richard Stallman
                             ` (2 more replies)
  0 siblings, 3 replies; 56+ messages in thread
From: Miles Bader @ 2004-01-18 23:08 UTC (permalink / raw)
  Cc: Kai Grossjohann, emacs-devel

On Sun, Jan 18, 2004 at 10:55:23PM +0100, Jan D. wrote:
> >Well, err, the obvious idea is to have (DND-TYPE TEST FUNCTION)
> >triples instead of pairs, where the TEST has an arg specifying where
> >the drag is going to happen.
> 
> I thought that would be too complex for a user to customize.  For 
> example,

However complex it is, it's certainly simpler than modifying a built-in
hardwired function though!  Anyway, I think the above sort of interface is
easy enough for the customize package to manipulate, and it can offer a more
user friendly interface.

I'd suggest:

  (1) Make the alist entry be one of (DND-TYPE DROP-FUN TEST-FUN) or
      (DND-TYPE . DROP-FUN) with TEST-FUN being a test function that accepts
      the same args as DROP-FUN.  Putting the TEST-FUN last makes it easier
      to omit.

  (2) If TEST-FUN is omitted/nil, default to some common formula like `in a
      writable text area'
  
  (3) Export the default test-function as a real function, so the user can
      call it from his code too (or use it explicitly in the alist, though of
      course that would be redundant).

-Miles
-- 
I'm beginning to think that life is just one long Yoko Ono album; no rhyme
or reason, just a lot of incoherent shrieks and then it's over.  --Ian Wolff

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 20:44   ` Jan D.
  2004-01-18 21:34     ` Kai Grossjohann
  2004-01-18 22:10     ` Kim F. Storm
@ 2004-01-19 18:24     ` Stefan Monnier
  2004-01-19 20:47       ` Jan D.
  2 siblings, 1 reply; 56+ messages in thread
From: Stefan Monnier @ 2004-01-19 18:24 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader

> frame, it is hard to select the one the user intended.  Also, if the
> buffer is read only, we don't want to accept a drop there.  So currently

I'd argue that we want to accept the drop (and then signal an error).
Just like C-y is accepted (i.e. the yank function is invoked) but then
signals an error.

Now that I think about it, rather than an alist, we might just want to make
the drop into an event that we look up in the keymaps.  If the drop is in
the tool-bar or the menu-bar, the event generated should be different so
that we can bind it to a different command (just like [mouse-1] turns into
[mode-line mouse-1] when clicking on the mode-line).


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 21:02   ` Jan D.
@ 2004-01-19 20:12     ` Richard Stallman
  2004-01-19 21:14       ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-19 20:12 UTC (permalink / raw)
  Cc: emacs-devel


    > If the user drops an icon representing a file into a Dired buffer,
    > I think it should rename or copy the file into that directory.
    > That is what drag-and-drop was used for originally on
    > the Mac: to move files between directories.  But I don't
    > see any code here to do rename or copy.

    If we know the target is a dired buffer, we can then accept the
    action that the source sends us (XdndActionCopy or XdndActionMove)
    instead of always using XdndActionPrivate and to the right thing
    for each action.

It should be easy to tell whether the buffer it was dropped into
is a Dired buffer.  But that is not the most elegant solution.

Is there a way that Dired mode could make a local variable binding,
or a local key binding, so as to control this?

    The types text/uri-list, text/x-moz-url, FILE_NAME and _NETSCAPE_URL all
    can have file:// URLs.  text/uri-list is the one XDND and the 
    freedesktop
    organization wants everybody to use.  text/x-moz-url is used by mozilla
    and newer netscape.

In modern systems, do the directory browsers use text/uri-list?
If so, it is vital that Dired handle it right.

      If you have multiple windows in the
    >> frame, it is hard to select the one the user intended.

What is the difficulty?  Can you tell the position at which the drop
occurred?  If so, is it hard to find the window containing that position?

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 23:08         ` Miles Bader
@ 2004-01-19 20:12           ` Richard Stallman
  2004-01-19 20:43           ` Jan D.
  2004-01-19 20:49           ` Jan D.
  2 siblings, 0 replies; 56+ messages in thread
From: Richard Stallman @ 2004-01-19 20:12 UTC (permalink / raw)
  Cc: jan.h.d, kai, emacs-devel

      (1) Make the alist entry be one of (DND-TYPE DROP-FUN TEST-FUN) or
	  (DND-TYPE . DROP-FUN)

I'd prefer to make it (DND-TYPE DROP-FUN TEST-FUN) or (DND-TYPE DROP-FUN).
In other words, you can omit the TEST-FUN.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 23:08         ` Miles Bader
  2004-01-19 20:12           ` Richard Stallman
@ 2004-01-19 20:43           ` Jan D.
  2004-01-20  2:34             ` Miles Bader
  2004-01-19 20:49           ` Jan D.
  2 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-19 20:43 UTC (permalink / raw)
  Cc: Kai Grossjohann, emacs-devel

>
> I'd suggest:
>
>   (1) Make the alist entry be one of (DND-TYPE DROP-FUN TEST-FUN) or
>       (DND-TYPE . DROP-FUN) with TEST-FUN being a test function that 
> accepts
>       the same args as DROP-FUN.  Putting the TEST-FUN last makes it 
> easier
>       to omit.
>
>   (2) If TEST-FUN is omitted/nil, default to some common formula like 
> `in a
>       writable text area'
>
>   (3) Export the default test-function as a real function, so the user 
> can
>       call it from his code too (or use it explicitly in the alist, 
> though of
>       course that would be redundant).

I see just one problem with this approach.  The DND-TYPE is not unique.
That is, when I drop a file from say the Gnome file manager, I have
several types to choose from, for example, text/uri-list, text/plain,
UTF8_STRING, and some more.  If a user is going to be able to make
an intelligent choice, I'd assume he wants to look at all acceptable
types as a group.  Also, there are several types out there that a user
can add to the alist that the current suggestion just ignores (say
application/xml or just about any unknown type).  How do we determine
which of these are more specific?

Am I missing something here?

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 18:24     ` Stefan Monnier
@ 2004-01-19 20:47       ` Jan D.
  2004-01-19 23:35         ` Jason Rumney
  2004-01-20 15:52         ` Stefan Monnier
  0 siblings, 2 replies; 56+ messages in thread
From: Jan D. @ 2004-01-19 20:47 UTC (permalink / raw)
  Cc: Miles Bader, emacs-devel

>> frame, it is hard to select the one the user intended.  Also, if the
>> buffer is read only, we don't want to accept a drop there.  So 
>> currently
>
> I'd argue that we want to accept the drop (and then signal an error).
> Just like C-y is accepted (i.e. the yank function is invoked) but then
> signals an error.
>
> Now that I think about it, rather than an alist, we might just want to 
> make
> the drop into an event that we look up in the keymaps.  If the drop is 
> in
> the tool-bar or the menu-bar, the event generated should be different 
> so
> that we can bind it to a different command (just like [mouse-1] turns 
> into
> [mode-line mouse-1] when clicking on the mode-line).

This is not compatible with the current drop code for W32.  Also, I 
don't
think it is worth doing, it is too complex for very little user benefit.
Better then to accept the drop and put it in the kill ring if we can't
insert it into a buffer.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-18 23:08         ` Miles Bader
  2004-01-19 20:12           ` Richard Stallman
  2004-01-19 20:43           ` Jan D.
@ 2004-01-19 20:49           ` Jan D.
  2 siblings, 0 replies; 56+ messages in thread
From: Jan D. @ 2004-01-19 20:49 UTC (permalink / raw)
  Cc: Kai Grossjohann, emacs-devel

> I'd suggest:
>
>   (1) Make the alist entry be one of (DND-TYPE DROP-FUN TEST-FUN) or
>       (DND-TYPE . DROP-FUN) with TEST-FUN being a test function that 
> accepts
>       the same args as DROP-FUN.  Putting the TEST-FUN last makes it 
> easier
>       to omit.

I forgot to mention, it is not possible to use the same arguments.  We
can not read the data to be dropped before we have determined which type
to use, so the data is not available to a TEST-FUN.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 20:12     ` Richard Stallman
@ 2004-01-19 21:14       ` Jan D.
  2004-01-20 15:31         ` Richard Stallman
  2004-01-20 16:02         ` Stefan Monnier
  0 siblings, 2 replies; 56+ messages in thread
From: Jan D. @ 2004-01-19 21:14 UTC (permalink / raw)
  Cc: emacs-devel

>
>     If we know the target is a dired buffer, we can then accept the
>     action that the source sends us (XdndActionCopy or XdndActionMove)
>     instead of always using XdndActionPrivate and to the right thing
>     for each action.
>
> It should be easy to tell whether the buffer it was dropped into
> is a Dired buffer.  But that is not the most elegant solution.
>
> Is there a way that Dired mode could make a local variable binding,
> or a local key binding, so as to control this?

I could add some more events or hooks at various points in the DND
protocol, but most DND protocols behave differently, so we would
probably get different behaviour when dropping with the XDND protocol
and when dropping with the Motif protocol.

Also, I don't want the protocols internals to be exposed too much, just
to be able to handle different protocols and future protocol changes 
better.

The way XDND works is basically it sends a XdndPosition to the target
(Emacs).  The XdndPosition contains the suggested action for the drop
(Move, Copy or Ask).  The target then reads available types for the drop
data, and determines if it wants to accept the suggested action, or
change it (Emacs always uses Private, which means, I'm doing something
that is special and don't affect the original data).  The target 
answers with
a XdndStatus message which tells the source if the drop is accepted and
if accepted, the action the target will take.

Later on, the source sends a XdndDrop message.  Then the target can read
the drop data and replies with a XdndFinished message that tells the 
source
if the drop was successful or not.

Now, if the mouse moves from a ordinary buffer to a dired buffer,
we need to change the action in the XdndStatus message.  And if it moves
out of the dired buffer, the action must be changed again.

Probably some buffer local variable could be used to influence the
actions chosen, but that would mean that dired would have to have
knowledge on the DND protocol.  The TEST-FUN suggested could be extended
to take the proposed action and return the preferred action.  So then
the alist could be made buffer local for dired buffers.

>
>     The types text/uri-list, text/x-moz-url, FILE_NAME and 
> _NETSCAPE_URL all
>     can have file:// URLs.  text/uri-list is the one XDND and the
>     freedesktop
>     organization wants everybody to use.  text/x-moz-url is used by 
> mozilla
>     and newer netscape.
>
> In modern systems, do the directory browsers use text/uri-list?
> If so, it is vital that Dired handle it right.

Yes, it is used by Gnome and KDE file browsers.

>
>       If you have multiple windows in the
>>> frame, it is hard to select the one the user intended.
>
> What is the difficulty?  Can you tell the position at which the drop
> occurred?  If so, is it hard to find the window containing that 
> position?

If the frame is split vertically and text is dropped on the menu bar, 
there
is a bit coordinate calculations to be made to determine which window
to use.  Not impossible, but quite elaborate for just a small benefit.
I kind of like the suggestion to push it in the kill buffer and display
a message about it.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 20:47       ` Jan D.
@ 2004-01-19 23:35         ` Jason Rumney
  2004-01-19 23:50           ` Jan D.
  2004-01-20 15:52         ` Stefan Monnier
  1 sibling, 1 reply; 56+ messages in thread
From: Jason Rumney @ 2004-01-19 23:35 UTC (permalink / raw)
  Cc: emacs-devel, Stefan Monnier, Miles Bader

"Jan D." <jan.h.d@swipnet.se> writes:

> This is not compatible with the current drop code for W32.

If we come up with good ideas from this discussion, there is no reason
why the w32 code should not change to accomodate them.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 23:35         ` Jason Rumney
@ 2004-01-19 23:50           ` Jan D.
  0 siblings, 0 replies; 56+ messages in thread
From: Jan D. @ 2004-01-19 23:50 UTC (permalink / raw)
  Cc: Miles Bader, Stefan Monnier, emacs-devel

> "Jan D." <jan.h.d@swipnet.se> writes:
>
>> This is not compatible with the current drop code for W32.
>
> If we come up with good ideas from this discussion, there is no reason
> why the w32 code should not change to accomodate them.

I meant that I didn't feel comfortable forcing a change that affected
ports that I can not update myself (I have no W32 development 
resourses).

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 20:43           ` Jan D.
@ 2004-01-20  2:34             ` Miles Bader
  0 siblings, 0 replies; 56+ messages in thread
From: Miles Bader @ 2004-01-20  2:34 UTC (permalink / raw)
  Cc: Kai Grossjohann, emacs-devel

"Jan D." <jan.h.d@swipnet.se> writes:
> The DND-TYPE is not unique.  That is, when I drop a file from say the
> Gnome file manager, I have several types to choose from, for example,
> text/uri-list, text/plain, UTF8_STRING, and some more.  If a user is
> going to be able to make an intelligent choice, I'd assume he wants to
> look at all acceptable types as a group.

Well why not do so then?  I.e., pass a list of all the acceptable types
as a list to the TEST-FUN.

> Also, there are several types out there that a user can add to the
> alist that the current suggestion just ignores (say application/xml or
> just about any unknown type).  How do we determine which of these are
> more specific?

If it's hard for the calling code to order the possible types, you could
use a simple ordered list instead of an alist, e.g., with entries like
(TEST-FUN . DROP-FUN), TEST-FUN being called with a _list_ of the
available types (+ other info), and the first test returning non-nil
causing the corresponding DROP-FUN to be called.

As a convenience, you could also allow TEST-FUN to be a string, and
consider it to match if the list of types contains it (or whatever).

-Miles
-- 
Come now, if we were really planning to harm you, would we be waiting here, 
 beside the path, in the very darkest part of the forest?

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 21:14       ` Jan D.
@ 2004-01-20 15:31         ` Richard Stallman
  2004-01-20 15:49           ` Jan D.
  2004-01-20 16:02         ` Stefan Monnier
  1 sibling, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-20 15:31 UTC (permalink / raw)
  Cc: emacs-devel

    > Is there a way that Dired mode could make a local variable binding,
    > or a local key binding, so as to control this?

    I could add some more events or hooks at various points in the DND
    protocol, but most DND protocols behave differently, so we would
    probably get different behaviour when dropping with the XDND protocol
    and when dropping with the Motif protocol.

I am surprised you think it is difficult, because it looks
trivial to me.

+ (global-set-key [drag-n-drop] 'x-dnd-handle-drag-n-drop-event)

If Dired mode makes a local binding for drag-n-drop, won't that
do the job?

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 15:31         ` Richard Stallman
@ 2004-01-20 15:49           ` Jan D.
  2004-01-21 21:09             ` Richard Stallman
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-20 15:49 UTC (permalink / raw)
  Cc: emacs-devel


>> Is there a way that Dired mode could make a local variable binding,
>> or a local key binding, so as to control this?
>
>     I could add some more events or hooks at various points in the DND
>     protocol, but most DND protocols behave differently, so we would
>     probably get different behaviour when dropping with the XDND 
> protocol
>     and when dropping with the Motif protocol.
>
> I am surprised you think it is difficult, because it looks
> trivial to me.
>
> + (global-set-key [drag-n-drop] 'x-dnd-handle-drag-n-drop-event)
>
> If Dired mode makes a local binding for drag-n-drop, won't that
> do the job?

Maybe, but then dired would have to have code to handle all the details
of all drag and drop protocols, basically all the code that is in
the new file x-dnd.el and more since I haven't added Motif and 
OpenWindows
yet.  A drop in XDND involves at least 5 different messages with
different context, i.e. dired would need to handle all of them.  Also,
a Motif drop involves another 3-5 messages, of different contents and
different replies.  Ditto for OpenWindows.
I'd rather have the details of the protocols in one place and the pass
on the result of the drop to other parts of Emacs.  The TEST-FUN 
suggestion
is a way forward, I don't think dired needs to do more than that to be
able to handle move and copy correctly.

Thinking about it, it would actually not do the job.  Because if the 
drag
enters Emacs in a non-dired buffer, dired would not see the XdndEnter
message.  Later on when the mouse travels to a dired buffer, dired would
just see a XdndPosition message, and that is not enough.  Also, we are 
not
selecting the buffers that the mouse travels over when doing a drop,
so a local binding would have no effect if another buffer
is selected when the drag starts.

The reason for not selecting the buffer the mouse is over is that a drag
can be aborted, and if the drag enters the selected buffer and leaves 
from
another buffer it would be confusing to have changed the selected buffer
just because the mouse happend to travel over it.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 20:47       ` Jan D.
  2004-01-19 23:35         ` Jason Rumney
@ 2004-01-20 15:52         ` Stefan Monnier
  2004-01-20 16:05           ` Jan D.
  1 sibling, 1 reply; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 15:52 UTC (permalink / raw)
  Cc: Miles Bader, emacs-devel

>> Now that I think about it, rather than an alist, we might just want to
>> make the drop into an event that we look up in the keymaps.  If the drop
>> is in the tool-bar or the menu-bar, the event generated should be
>> different so that we can bind it to a different command (just like
>> [mouse-1] turns into [mode-line mouse-1] when clicking on the mode-line).

The more I think about it, the more it feels like The Right Thing.
Admittedly, the issue with having to choose between various types might
make it impractical: I don't know enough to be able to tell.

> This is not compatible with the current drop code for W32.

It's a non-issue unless the current w32 behavior is better or cannot be
changed to use such keymap bindings.

> Also, I don't think it is worth doing, it is too complex for very little
> user benefit.

Looking at it from my armchair, it doesn't look that complex ;-)
You basically need to do a bunch of keymap lookups rather than a bunch of
alist lookups.  And you need to create an event, which might indeed be more
work, I don't know.

> Better then to accept the drop and put it in the kill ring
> if we can't insert it into a buffer.

That's up to the command bound to the event.  All that I wanted to point out
by my original remark is that it's OK to accept the drop even if the buffer
is read-only: we can then signal an error (and/or do whatever else we feel
like).  Or in more general terms, it's OK to accept a drop before knowing
whether the action can be carried through.  All we need to figure out really
is *which* type of drop to use.


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-19 21:14       ` Jan D.
  2004-01-20 15:31         ` Richard Stallman
@ 2004-01-20 16:02         ` Stefan Monnier
  2004-01-20 16:24           ` Jan D.
  1 sibling, 1 reply; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 16:02 UTC (permalink / raw)
  Cc: rms, emacs-devel

> If the frame is split vertically and text is dropped on the menu bar, there
> is a bit coordinate calculations to be made to determine which window
> to use.

I don't know enough to understand I guess.  I assume you'd use the same
kind of code that Kim recently changed to report the full position info in
mouse-click events: this code turns a scren pixel position into a bunch of
"logical position" info: window, buffer-pos, ...

Now, when dropping on the menu-bar, I don't know what DND should do (I
can't think of any meaningful operation that you could carry this way,
unless you could drop not just on the menu-bar but on a menu-entry), but
a menu-bar is always linked to a particular window, so getting the relevant
window is a small matter of finding the active window of the frame.

Obviously, I'm much too unfamiliar with the code to understand the problems
you're referring to.


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 15:52         ` Stefan Monnier
@ 2004-01-20 16:05           ` Jan D.
  2004-01-20 18:41             ` Stefan Monnier
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-20 16:05 UTC (permalink / raw)
  Cc: Miles Bader, emacs-devel

>> Also, I don't think it is worth doing, it is too complex for very 
>> little
>> user benefit.
>
> Looking at it from my armchair, it doesn't look that complex ;-)
> You basically need to do a bunch of keymap lookups rather than a bunch 
> of
> alist lookups.  And you need to create an event, which might indeed be 
> more
> work, I don't know.

The problem is more figuring out where the mouse is, i.e. menu bar, 
scroll
bar or tool bar.  Right now, I just see if the position corresponds to
a window and if not, it is somewhere in those three, the details does 
not
matter.  It may not be a complex thing, but all these events must 
interract
so that if a drop starts with [menu-bar dnd], then enters a window,
i.e. [dnd], and then exits via a [scroll-bar dnd], the global data
needed for the drop must be synchronized so that it is correctly 
updated.

>
>> Better then to accept the drop and put it in the kill ring
>> if we can't insert it into a buffer.
>
> That's up to the command bound to the event.  All that I wanted to 
> point out
> by my original remark is that it's OK to accept the drop even if the 
> buffer
> is read-only: we can then signal an error (and/or do whatever else we 
> feel
> like).  Or in more general terms, it's OK to accept a drop before 
> knowing
> whether the action can be carried through.  All we need to figure out 
> really
> is *which* type of drop to use.

I don't feel comfortable with accepting a drop and then signal an error.
I think this goes a bit against the "spirit" of drag and drop in a small
way.  The reason why the source of the drop gives a list of types and
a suggested action (copy, move etc.) at the start of the drop is just
so that the target can decide if to accept the drop or not.

Also, many programs (all GTK for example) have a visual indicator to
show if the drop can be made or not where the mouse is.  If Emacs just
accepts everything and then signals an error would be bad user interface
IMHO.  Better then to show the user that he can't drop here, or that he
can, but the results have to be manually extracted from the kill ring.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 16:02         ` Stefan Monnier
@ 2004-01-20 16:24           ` Jan D.
  2004-01-20 18:43             ` Stefan Monnier
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-20 16:24 UTC (permalink / raw)
  Cc: rms, emacs-devel

>> If the frame is split vertically and text is dropped on the menu bar, 
>> there
>> is a bit coordinate calculations to be made to determine which window
>> to use.
>
> I don't know enough to understand I guess.  I assume you'd use the same
> kind of code that Kim recently changed to report the full position 
> info in
> mouse-click events: this code turns a scren pixel position into a 
> bunch of
> "logical position" info: window, buffer-pos, ...
>
> Now, when dropping on the menu-bar, I don't know what DND should do (I
> can't think of any meaningful operation that you could carry this way,
> unless you could drop not just on the menu-bar but on a menu-entry), 
> but
> a menu-bar is always linked to a particular window, so getting the 
> relevant
> window is a small matter of finding the active window of the frame.

Dropping a file name on the menu bar currently opens the file in a new
window.  I think that is useful (i.e. I use it all the time :-)

But the active window is probably not where the drop should go.  
Consider
this setup with vertically split windows:

--------------------------------------------
| File  Edit  Options  Buffers  Tools Help |
--------------------------------------------
| window 1  |x|  window 2 |x|  window 3  |x|
--------------------------------------------

|x| represents a scroll bar.

If dropping text onto File, the user might reasonable expect the text
to be pasted into window 1, because it is closest.  Dropping on Tools
can be expected to paste the text into window 3.

But the selected window may be window 1, but I think it would be
strange to paste into window 1 when the drop is clearly made closer to
window 3.  And what about dropping on the 'e' in Buffers?  It is
the same distance to window 2 and window 3.  Remember that drag and
drop is very visual, and where the drop does occur is where the action
should happen.  To say that the menu bar is associated with window 1
and do all drops there would be confusing for a user.

So while dropping just about anywhere makes sense when used to open a
file, it is more problematic for pasting in text.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 16:05           ` Jan D.
@ 2004-01-20 18:41             ` Stefan Monnier
  2004-01-20 20:50               ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 18:41 UTC (permalink / raw)
  Cc: Miles Bader, emacs-devel

> The problem is more figuring out where the mouse is, i.e. menu bar, scroll
> bar or tool bar.

Wait.... you're doing it in elisp, right?  That's the problem.
You first need to export the C code that does it.

> matter.  It may not be a complex thing, but all these events must
> interract so that if a drop starts with [menu-bar dnd], then enters
> a window, i.e. [dnd], and then exits via a [scroll-bar dnd], the global
> data needed for the drop must be synchronized so that it is
> correctly updated.

I must admit that I don't understand what you mean by a drop "starting"
somewhere and "exiting" somewhere else.  My understand of a drop is "release
the mouse button" which is instantaneous.

Or are you talking about the drag part and saying that Emacs should somehow
highlight the object to which the drop is going to apply ?

> I don't feel comfortable with accepting a drop and then signal an error.
> I think this goes a bit against the "spirit" of drag and drop in a small
> way.  The reason why the source of the drop gives a list of types and
> a suggested action (copy, move etc.) at the start of the drop is just
> so that the target can decide if to accept the drop or not.

Obviously, if there's no binding for the drop event at the drop location,
you should not accept the drop action.  So view-mode could explicily unbind
the drop event, for example.

Or the keymap bindings could be to commands that have to first call
a `dnd-accept' function to get the actual text to insert.  This accept
function could take arguments to indicate which kind of drop is being
accepted, ...

> Also, many programs (all GTK for example) have a visual indicator to
> show if the drop can be made or not where the mouse is.

With the generality of elisp you indeed can't do it 100%, but you can
approximate it using things like "is there a binding for dnd-drop here?".


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 16:24           ` Jan D.
@ 2004-01-20 18:43             ` Stefan Monnier
  2004-01-20 20:33               ` Jan D.
  2004-01-21 21:08               ` Richard Stallman
  0 siblings, 2 replies; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 18:43 UTC (permalink / raw)
  Cc: rms, emacs-devel

> Dropping a file name on the menu bar currently opens the file in a new
> window.  I think that is useful (i.e. I use it all the time :-)

It might be useful, but I'd find it confusing.

> If dropping text onto File, the user might reasonable expect the text
> to be pasted into window 1, because it is closest.  Dropping on Tools
> can be expected to paste the text into window 3.

For me that would spell more confusion.
I'd much rather drop directly into the window or maybe the modeline (in
case you want the "drop into window" to insert the file's path instead).


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 18:43             ` Stefan Monnier
@ 2004-01-20 20:33               ` Jan D.
  2004-01-20 20:43                 ` Stefan Monnier
  2004-01-21 21:08               ` Richard Stallman
  1 sibling, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-20 20:33 UTC (permalink / raw)
  Cc: rms, emacs-devel


2004-01-20 kl. 19.43 skrev Stefan Monnier:

>> Dropping a file name on the menu bar currently opens the file in a new
>> window.  I think that is useful (i.e. I use it all the time :-)
>
> It might be useful, but I'd find it confusing.

It is how it works on most applications, and indeed in Emacs when 
running
on W32 (at least it did a couple of years ago, when I ran Emacs on W32).
For most people, the biggest benefit of supporting DND is to be able to
open a file by dragging it from a file manager to the appropriate
application (Emacs in this case).  Inserting the file name in a buffer 
is a
very non-standard behaviour.  For example, all Gnome and KDE text 
editors
behave this way.  Since Emacs is relative new in the DND game, I'd like
Emacs to behave like other applications in this regard (but not in any
other function obviously :-).  I find it harder to explain to a user why
a drop on the tool bar and the menu bar is not acceptable to open a 
file.
If we do that, I think we will get bug reports on it.


>> If dropping text onto File, the user might reasonable expect the text
>> to be pasted into window 1, because it is closest.  Dropping on Tools
>> can be expected to paste the text into window 3.
>
> For me that would spell more confusion.
> I'd much rather drop directly into the window or maybe the modeline (in
> case you want the "drop into window" to insert the file's path 
> instead).

Yes of course.  But then we are back to the question, shall we reject
the drop in this case, or accept it.  It sounds like you want to reject
it in this case, which is what I tried to do initially.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 20:33               ` Jan D.
@ 2004-01-20 20:43                 ` Stefan Monnier
  0 siblings, 0 replies; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 20:43 UTC (permalink / raw)
  Cc: rms, emacs-devel

>>> Dropping a file name on the menu bar currently opens the file in a new
>>> window.  I think that is useful (i.e. I use it all the time :-)
>> It might be useful, but I'd find it confusing.
> It is how it works on most applications, and indeed in Emacs when running
> on W32 (at least it did a couple of years ago, when I ran Emacs on W32).

It's not the "open the file" that I find confusing.  It's the "on the menu
bar".  I'd rather reject the drop in that case.

> other function obviously :-).  I find it harder to explain to a user why
> a drop on the tool bar and the menu bar is not acceptable to open a file.
> If we do that, I think we will get bug reports on it.

That's possible: I don't claim to be representative.

>>> If dropping text onto File, the user might reasonable expect the text
>>> to be pasted into window 1, because it is closest.  Dropping on Tools
>>> can be expected to paste the text into window 3.
>> 
>> For me that would spell more confusion.
>> I'd much rather drop directly into the window or maybe the modeline (in
>> case you want the "drop into window" to insert the file's path instead).

> Yes of course.  But then we are back to the question, shall we reject
> the drop in this case, or accept it.  It sounds like you want to reject
> it in this case, which is what I tried to do initially.

I don't understand what you're referring to.  From my point of view, we
could just look up [menu-bar dnd-drop] and/or [mode-line dnd-drop] to see
whether to accept (and how to process) the drop event.


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 18:41             ` Stefan Monnier
@ 2004-01-20 20:50               ` Jan D.
  2004-01-20 21:12                 ` Stefan Monnier
  2004-01-21 21:08                 ` Richard Stallman
  0 siblings, 2 replies; 56+ messages in thread
From: Jan D. @ 2004-01-20 20:50 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader

>> The problem is more figuring out where the mouse is, i.e. menu bar, 
>> scroll
>> bar or tool bar.
>
> Wait.... you're doing it in elisp, right?  That's the problem.
> You first need to export the C code that does it.

Yes, I kind of suspected that.

>> matter.  It may not be a complex thing, but all these events must
>> interract so that if a drop starts with [menu-bar dnd], then enters
>> a window, i.e. [dnd], and then exits via a [scroll-bar dnd], the 
>> global
>> data needed for the drop must be synchronized so that it is
>> correctly updated.
>
> I must admit that I don't understand what you mean by a drop "starting"
> somewhere and "exiting" somewhere else.  My understand of a drop is 
> "release
> the mouse button" which is instantaneous.
>
> Or are you talking about the drag part and saying that Emacs should 
> somehow
> highlight the object to which the drop is going to apply ?

Drag and drop is no where near instantaneous as for example copy-paste 
is.
I'll outline it here, restricted to XDND, but other protocols are 
similar.
The way it works is the the target (Emacs) puts a property on the window
that tells other apps that it can do drag and drop, XDND style.
When a user drags something from a file manager for example (the 
source),
the source keeps track on which application that is under the mouse.

When the mouse enters an application that can do XDND, it sends an
XdndEnter message (i.e. drop starting).  The target does not reply to 
this,
but when it gets this message, it can see what types the source offers
for the drop data.

Later when the mouse moves, the source sends XdndPosition messages,
which among other things, contains the suggested action the source
wants to do. The target replies with XdndStatus messages.  The answer
contains among other things, the action the target wants to perform 
(copy, move, private) and if it is acceptable to drop where the mouse 
is currently.

If the mouse is the moved out of the target, the source sends
a XdndLeave message, and the target forgets the whole thing.

If the mouse button is released, the target sends XdndDrop, and this
is the "release button" you talk about.  At this point, the target
can retreive the data, and do with it what it wants.  The target
sends XdndFinish to the source, and the drop ends.

So if the mouse travels from the menu bar, to the tool bar, to a read
only buffer, to an ordinary buffer, and then to a dired buffer, and then
we do the drop, Emacs must send XdndStatus messages back to the source
with different actions in them.  Possibly we want to do private on
the menu bar and tool bar, not accept the drop in the read only buffer,
then send private again when entering the ordinary buffer, and then
send the action the target suggests (move, copy) when entering the
dired buffer so that dired acts like a file manager.

So there is a lot of talk going on, and Emacs needs to determine what
to send in the XdndStatus messages, based on where the pointer is,
what kind of buffer we are over, and take into account the user
preferences (i.e. insert the file name in abuffer instead of opening 
it).

And remember, XDND is said to be a simple dnd protocol :-).

>> I don't feel comfortable with accepting a drop and then signal an 
>> error.
>> I think this goes a bit against the "spirit" of drag and drop in a 
>> small
>> way.  The reason why the source of the drop gives a list of types and
>> a suggested action (copy, move etc.) at the start of the drop is just
>> so that the target can decide if to accept the drop or not.
>
> Obviously, if there's no binding for the drop event at the drop 
> location,
> you should not accept the drop action.  So view-mode could explicily 
> unbind
> the drop event, for example.

As can be seen above, we need to know this before the drop occurs.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 20:50               ` Jan D.
@ 2004-01-20 21:12                 ` Stefan Monnier
  2004-01-20 21:27                   ` Jan D.
  2004-01-21 21:08                 ` Richard Stallman
  1 sibling, 1 reply; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 21:12 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader

> Later when the mouse moves, the source sends XdndPosition messages,
> which among other things, contains the suggested action the source
> wants to do. The target replies with XdndStatus messages.  The answer
> contains among other things, the action the target wants to perform (copy,
> move, private) and if it is acceptable to drop where the mouse is currently.

Why does the source app send XdndPosition (rather than the target app
keeping track of mouse movements) ?  Is suh an XdndPosition message sent
every time the mouse moves within the target's window ?
What is the purpose of the XdndStatus message?  I.e. how does the source
use this information?  I can see its usefulness once the drop actually
takes place, but during dragging I can't think of anything useful the
source could do with it.

> So if the mouse travels from the menu bar, to the tool bar, to a read
> only buffer, to an ordinary buffer, and then to a dired buffer, and then
> we do the drop, Emacs must send XdndStatus messages back to the source
> with different actions in them.

What happens if it just always sends some dummy XdndStatus message instead?
What happens if it waits for the button-release before sending any XdndStatus?

>> Obviously, if there's no binding for the drop event at the drop location,
>> you should not accept the drop action.  So view-mode could explicily
>> unbind the drop event, for example.

> As can be seen above, we need to know this before the drop occurs.

That's OK: we can lookup keymaps during the drag to figure out whether
dnd-drop is bound at the location under the mouse.


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 21:12                 ` Stefan Monnier
@ 2004-01-20 21:27                   ` Jan D.
  2004-01-20 22:09                     ` Stefan Monnier
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-20 21:27 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader


2004-01-20 kl. 22.12 skrev Stefan Monnier:

>> Later when the mouse moves, the source sends XdndPosition messages,
>> which among other things, contains the suggested action the source
>> wants to do. The target replies with XdndStatus messages.  The answer
>> contains among other things, the action the target wants to perform 
>> (copy,
>> move, private) and if it is acceptable to drop where the mouse is 
>> currently.
>
> Why does the source app send XdndPosition (rather than the target app
> keeping track of mouse movements) ?  Is suh an XdndPosition message 
> sent
> every time the mouse moves within the target's window ?
> What is the purpose of the XdndStatus message?  I.e. how does the 
> source
> use this information?  I can see its usefulness once the drop actually
> takes place, but during dragging I can't think of anything useful the
> source could do with it.

To simplify for the target.  It may also be that there are several
pointer devices (indeed, on my laptop, I can use three mice at the same
time), and the target can not know which one is used.
Also if for example, a press on a shift key while dragging means move,
and unshifted means copy, the source must inform
the target that the action has changed.  There is an optimization
where the target in the XdndStatus message tells the source not to
send XdndPosition when the mouse is inside a given rectangle.  But
the target must be prepared to accept XdndPositions anyway, the source
is free to ignore the given rectangle (which indeed GTK does,  Qt honors
the rectangle).

XdndStatus tells the source if the drop is accepted, and the above 
mentioned
rectangle.  The source uses the accept/reject status to change the
icon that is being dragged so the user can visually see if drop is
accepted or rejected where the mouse is now.  Also, if the mouse button 
is
released and the last XdndStatus said reject, the source usually does a 
bit
of animation so the dragged icon is "snapped back" to where the drag
started.

>
>> So if the mouse travels from the menu bar, to the tool bar, to a read
>> only buffer, to an ordinary buffer, and then to a dired buffer, and 
>> then
>> we do the drop, Emacs must send XdndStatus messages back to the source
>> with different actions in them.
>
> What happens if it just always sends some dummy XdndStatus message 
> instead?
> What happens if it waits for the button-release before sending any 
> XdndStatus?

If we don't send any XdndStatus, the source will conclude that the
target can not accept any drop whatsoever, and never send the XdndDrop
message.  A dummy is no good, we at least needs to set accept/reject
correctly.  The target does not get any button release info, the mouse
is grabbed by the source.  The only indication the target gets about
button release is the XdndDrop message, or an XdndLeave message if the
drop was rejected by the last XdndStatus message.

>
>>> Obviously, if there's no binding for the drop event at the drop 
>>> location,
>>> you should not accept the drop action.  So view-mode could explicily
>>> unbind the drop event, for example.
>
>> As can be seen above, we need to know this before the drop occurs.
>
> That's OK: we can lookup keymaps during the drag to figure out whether
> dnd-drop is bound at the location under the mouse.

That is true.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 21:27                   ` Jan D.
@ 2004-01-20 22:09                     ` Stefan Monnier
  2004-01-20 22:28                       ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 22:09 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader

> To simplify for the target.  It may also be that there are several
> pointer devices (indeed, on my laptop, I can use three mice at the same
> time), and the target can not know which one is used.

I've seen and used multiple mice, but they always all applied to the one and
only on-screen-cursor.  So from an Xclient point of view, there's really only
one input device (which is composed of several mice).
But that's irrelevant to the discussion.

> XdndStatus tells the source if the drop is accepted, and the above mentioned
> rectangle.  The source uses the accept/reject status to change the
> icon that is being dragged so the user can visually see if drop is
> accepted or rejected where the mouse is now.

Talk about stupid design: the user is obviously looking at the target while
dragging, so any indication should happen there rather than at the source.
It would also eliminate this need for constant XdndStatus communication.
I'm obviously missing something.

> Also, if the mouse button is released and the last XdndStatus said reject,
> the source usually does a bit of animation so the dragged icon is "snapped
> back" to where the drag started.

But that could be triggered by a XdndReject response to XdndDrop, so it
does not justify XdndStatus.
[ Don't take my comments too seriously: I understand you can't change any
  of it, I'm just trying to figure out how/why it was designed this way,
  so as to better understand how to use it.  If you get tired, just tell me
  to go read the docs.  Thanks already for your careful explanations. ]

> If we don't send any XdndStatus, the source will conclude that the
> target can not accept any drop whatsoever, and never send the XdndDrop
> message.  A dummy is no good, we at least needs to set accept/reject
> correctly.

Seems like `accept' would be a good dummy, if needed.

> The target does not get any button release info, the mouse
> is grabbed by the source.  The only indication the target gets about
> button release is the XdndDrop message, or an XdndLeave message if the
> drop was rejected by the last XdndStatus message.

OK, that part makes sense now, thank you.


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 22:09                     ` Stefan Monnier
@ 2004-01-20 22:28                       ` Jan D.
  2004-01-20 23:38                         ` Stefan Monnier
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-20 22:28 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader


>> To simplify for the target.  It may also be that there are several
>> pointer devices (indeed, on my laptop, I can use three mice at the 
>> same
>> time), and the target can not know which one is used.
>
> I've seen and used multiple mice, but they always all applied to the 
> one and
> only on-screen-cursor.  So from an Xclient point of view, there's 
> really only
> one input device (which is composed of several mice).

It is not a strict requirement.  There can be multiple pointer devices.
In some accessibility functions you can simulate the mouse actions
with arrow keys.

>> XdndStatus tells the source if the drop is accepted, and the above 
>> mentioned
>> rectangle.  The source uses the accept/reject status to change the
>> icon that is being dragged so the user can visually see if drop is
>> accepted or rejected where the mouse is now.
>
> Talk about stupid design: the user is obviously looking at the target 
> while
> dragging, so any indication should happen there rather than at the 
> source.

The icon I am talking about is the one the user drags, i.e. it is
where the pointer is.
It is actually recommended that the target does some visible indication
also, such as highlight the window border.  Most apps doesn't do that.  
The
target can not have control over any visible indication at the pointer,
first the source has grabbed the pointer, secondly the drop starts
at the source, so what the dragged icon looks like is not known by
the target.

> It would also eliminate this need for constant XdndStatus 
> communication.
> I'm obviously missing something.

The status messages are mostly a way for the target to change the state,
i.e. change reject/accept and/or change the rectangle where it does not
want more position messages.

>
>> Also, if the mouse button is released and the last XdndStatus said 
>> reject,
>> the source usually does a bit of animation so the dragged icon is 
>> "snapped
>> back" to where the drag started.
>
> But that could be triggered by a XdndReject response to XdndDrop, so it
> does not justify XdndStatus.

In the XdndFinished message the target tells the source if the drop
was successful or not.  But the XdndStatus messages are needed anyway
to inform the source if it should send a XdndDrop at all.  The
XdndFinished is only to be sent after a XdndDrop message.

>> If we don't send any XdndStatus, the source will conclude that the
>> target can not accept any drop whatsoever, and never send the XdndDrop
>> message.  A dummy is no good, we at least needs to set accept/reject
>> correctly.
>
> Seems like `accept' would be a good dummy, if needed.

Then we are back to saying accept and then later perhaps signal
an error.  I do not like that.  If we know we are going to raise an
error, we should not accept the drop in the first place.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 22:28                       ` Jan D.
@ 2004-01-20 23:38                         ` Stefan Monnier
  0 siblings, 0 replies; 56+ messages in thread
From: Stefan Monnier @ 2004-01-20 23:38 UTC (permalink / raw)
  Cc: emacs-devel, Miles Bader

> It is not a strict requirement.  There can be multiple pointer devices.
> In some accessibility functions you can simulate the mouse actions
> with arrow keys.

But if the source grabs the mouse, it is grabbed for all mice as well as for
those special arrow keys: i.e. there's still really only one pointer device
(which is a logical entity), just controlled from a bunch of different
hardware pieces (the mice and the keys).

>From the users point of view, there are several input devices that control
the cursor, but from the X clients, there's just only only cursor and they
don't care how the X server handles the hardware input devices to allow the
user to control the one and only cursor.

But it's still completely irrelevant to this discussion.

> The icon I am talking about is the one the user drags, i.e. it is
> where the pointer is.

Duh!  I finally understand, thank you.

> Then we are back to saying accept and then later perhaps signal
> an error.  I do not like that.  If we know we are going to raise an
> error, we should not accept the drop in the first place.

Well, we should still send a `reject' in the case where we know it will be
rejected (i.e. when there's no binding in the keymap), but if there's
a binding it's OK to say `accept' and later on signal an error.


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 18:43             ` Stefan Monnier
  2004-01-20 20:33               ` Jan D.
@ 2004-01-21 21:08               ` Richard Stallman
  2004-01-21 21:14                 ` Stefan Monnier
  1 sibling, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-21 21:08 UTC (permalink / raw)
  Cc: jan.h.d, emacs-devel

    > Dropping a file name on the menu bar currently opens the file in a new
    > window.  I think that is useful (i.e. I use it all the time :-)

    It might be useful, but I'd find it confusing.

Here's a bizarre idea.  If you bring up a menu and drop a file on a
menu item, the chosen command operates on that file name as argument.

    I'd much rather drop directly into the window or maybe the modeline (in
    case you want the "drop into window" to insert the file's [name] instead).

Dropping the file onto the window would mean something else, at least
in the case of a dired buffer.  It would mean to move or copy the file
into that directory.  So we can't use that action as the command for
opening the file in Emacs.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 20:50               ` Jan D.
  2004-01-20 21:12                 ` Stefan Monnier
@ 2004-01-21 21:08                 ` Richard Stallman
  2004-01-21 22:30                   ` Jan D.
  1 sibling, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-21 21:08 UTC (permalink / raw)
  Cc: miles, monnier, emacs-devel

    So if the mouse travels from the menu bar, to the tool bar, to a read
    only buffer, to an ordinary buffer, and then to a dired buffer, and then
    we do the drop, Emacs must send XdndStatus messages back to the source
    with different actions in them.  Possibly we want to do private on
    the menu bar and tool bar, not accept the drop in the read only buffer,
    then send private again when entering the ordinary buffer, and then
    send the action the target suggests (move, copy) when entering the
    dired buffer so that dired acts like a file manager.

I think it is better not to try to say yes and no in different Emacs
buffers.  We should treat all of the buffer text areas in a uniform way
as regards accepting drops there.

However, the menu bars could be treated differently, since the C code
can tell whether the pointer is in a menu bar.  Likewise, maybe Emacs
could always reject drops in scroll bars, or in the echo area when the
minibuffer is inactive (or maybe always in the echo area).  The C code
can tell if a window is a minibuffer window and whether it is active.

Mode lines also would have to be treated uniformly, I guess.
Is there a useful meaning for a drop in the mode line?

Different buffers can still handle the same kind of drop in different
ways, based on local key bindings.  There's no need to look thus up
except at the end, in response to the event.

If we want dropping a file into the menu bar to open the file, then I
suggest it open the file using find-file-other-window.  While no
method is always best, that's the way users most often prefer.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-20 15:49           ` Jan D.
@ 2004-01-21 21:09             ` Richard Stallman
  2004-01-21 22:22               ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-21 21:09 UTC (permalink / raw)
  Cc: emacs-devel

    Maybe, but then dired would have to have code to handle all the details
    of all drag and drop protocols, basically all the code that is in
    the new file x-dnd.el and more since I haven't added Motif and 
    OpenWindows

It could perhaps call a subroutine that does most of the work,
but with a different argument from the one used globally.

Or the global command could generate and unread a modified
event, which would then be looked up in turn.

    Thinking about it, it would actually not do the job.  Because if the 
    drag
    enters Emacs in a non-dired buffer, dired would not see the XdndEnter
    message.  Later on when the mouse travels to a dired buffer, dired would
    just see a XdndPosition message, and that is not enough.

Which of these messages causes the Lisp-level drag-n-drop event?
I would guess it is the last message that does so.

      Also, we are 
    not
    selecting the buffers that the mouse travels over when doing a drop,
    so a local binding would have no effect if another buffer
    is selected when the drag starts.

The time to look up the proper key binding is when the drop *ends*,
and only then.  It is not hard to get the key bindings for a given
place on the Emacs frame.  We do that for mouse clicks, we could do it
here too.

    The reason for not selecting the buffer the mouse is over is that a drag
    can be aborted,

It certainly should not select the buffer.  There is no need for that.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-21 21:08               ` Richard Stallman
@ 2004-01-21 21:14                 ` Stefan Monnier
  2004-01-21 22:02                   ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Stefan Monnier @ 2004-01-21 21:14 UTC (permalink / raw)
  Cc: jan.h.d, emacs-devel

>> Dropping a file name on the menu bar currently opens the file in a new
>> window.  I think that is useful (i.e. I use it all the time :-)

>     It might be useful, but I'd find it confusing.

> Here's a bizarre idea.  If you bring up a menu and drop a file on a
> menu item, the chosen command operates on that file name as argument.

Yes, that would make sense, but it seems difficult to do: when the menu
item is displayed, the mouse is typically grabbed by Emacs, and similarly
when drag&dropping, the mouse is grabbed the other application, so there's
a problem.


        Stefan

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-21 21:14                 ` Stefan Monnier
@ 2004-01-21 22:02                   ` Jan D.
  0 siblings, 0 replies; 56+ messages in thread
From: Jan D. @ 2004-01-21 22:02 UTC (permalink / raw)
  Cc: rms, emacs-devel

>>> Dropping a file name on the menu bar currently opens the file in a 
>>> new
>>> window.  I think that is useful (i.e. I use it all the time :-)
>
>>     It might be useful, but I'd find it confusing.
>
>> Here's a bizarre idea.  If you bring up a menu and drop a file on a
>> menu item, the chosen command operates on that file name as argument.
>
> Yes, that would make sense, but it seems difficult to do: when the menu
> item is displayed, the mouse is typically grabbed by Emacs, and 
> similarly
> when drag&dropping, the mouse is grabbed the other application, so 
> there's
> a problem.

Yes you are right, a drop from one application on to a menu item in
another application can never occur in X.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-21 21:09             ` Richard Stallman
@ 2004-01-21 22:22               ` Jan D.
  2004-01-22 19:00                 ` Richard Stallman
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-21 22:22 UTC (permalink / raw)
  Cc: emacs-devel

>
> Which of these messages causes the Lisp-level drag-n-drop event?
> I would guess it is the last message that does so.

No, they all do.  That is, the messages the source sends: XdndEnter,
XdndPosition, XdndPosition and XdndLeave (mouse moved away from Emacs
or drop aborted).  The replies are sent from lisp with 
x-send-client-message.

All drag and drop protocols operate with XClientMessageEvent:s, so by
converting XClientMessageEvent to one Emacs event the protocol can be
totally implemented in lisp.  When adding Motif and others only lisp
code needs to be added (I hope :-).

>       Also, we are
>     not
>     selecting the buffers that the mouse travels over when doing a 
> drop,
>     so a local binding would have no effect if another buffer
>     is selected when the drag starts.
>
> The time to look up the proper key binding is when the drop *ends*,
> and only then.  It is not hard to get the key bindings for a given
> place on the Emacs frame.  We do that for mouse clicks, we could do it
> here too.

That is too late.  We must know if we are going to accept the drop 
before
it ends.  Otherwise we can not reply to the source that we are accepting
the drop, and if we are not accepting the drop, there will be no end
(i.e. XdndDrop) message, just an XdndLeave message.  The alternative is
to accept anything, but that is bad user interaction IMHO.  If we say
we accept the drop of a totally unknown type (application/funky-app for
example), we have no choice then but to signal an error when the 
XdndDrop
message occurs because we have no idea what funky-app is.
So basically we lied.  We said we could accept the data, but we really
couldn't, and we could have figured this out in advance just by looking
at the type.

I am currently using just one test function, that gets called when
a XdndPosition message arrives and something has changed (buffer, window
suggested action).  This function is called via a variable so it can be
changed.  The function returns the action and the type it wants to do
or nil to reject the drop.

In addition to that, there is an alist that maps types to
actions.  For example, text/uri-list defaults to open file for files
and calling the various browse-url handlers for non-file URLs.
text/plain defauls to insert.  But if someone wants to insert the file 
names
instead, they can change the alist entry for that type.  Or they can
make their own test function to always return text/plain if that is
available.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-21 21:08                 ` Richard Stallman
@ 2004-01-21 22:30                   ` Jan D.
  2004-01-22 10:19                     ` Kim F. Storm
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-21 22:30 UTC (permalink / raw)
  Cc: emacs-devel, monnier, miles

>
> I think it is better not to try to say yes and no in different Emacs
> buffers.  We should treat all of the buffer text areas in a uniform way
> as regards accepting drops there.

Okay, then we can put the data in the kill ring if it can't be inserted.

> However, the menu bars could be treated differently, since the C code
> can tell whether the pointer is in a menu bar.  Likewise, maybe Emacs
> could always reject drops in scroll bars, or in the echo area when the
> minibuffer is inactive (or maybe always in the echo area).  The C code
> can tell if a window is a minibuffer window and whether it is active.
>
> Mode lines also would have to be treated uniformly, I guess.
> Is there a useful meaning for a drop in the mode line?

Well, if a drop of a file opens the file, it should do it for the
mode line also I think.

> Different buffers can still handle the same kind of drop in different
> ways, based on local key bindings.  There's no need to look thus up
> except at the end, in response to the event.

The current drag and drop event from C to Lisp is not intended to be
anything but internal, i.e. to be able to implement the protocol in 
lisp.
I guess I could create an additional event for the final drop, but
information must be extraced before the final event (see other mails).

>
> If we want dropping a file into the menu bar to open the file, then I
> suggest it open the file using find-file-other-window.  While no
> method is always best, that's the way users most often prefer.

That is easy to do.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-22 10:19                     ` Kim F. Storm
@ 2004-01-22  9:46                       ` Jan D.
  2004-01-22 11:32                         ` Kim F. Storm
  2004-01-23 18:25                         ` Richard Stallman
  0 siblings, 2 replies; 56+ messages in thread
From: Jan D. @ 2004-01-22  9:46 UTC (permalink / raw)
  Cc: emacs-devel, rms, monnier, miles

>>> However, the menu bars could be treated differently, since the C code
>>> can tell whether the pointer is in a menu bar.  Likewise, maybe Emacs
>>> could always reject drops in scroll bars, or in the echo area when 
>>> the
>>> minibuffer is inactive (or maybe always in the echo area).
>
> IMO, dropping it in the echo area/mini buffer should mean to copy the
> file-name/whatever to the kill-ring unconditionally.

Hmm, I think it is likely that someone might want to drop say a file
name (i.e. mark a file name in some other application and drag it to
Emacs) to the mini buffer, and really have the text inserted there.
I am talking about dragging text here, not a uri-list, which currently
opens the file instead (for example, dragging from a file manager).
I think this operation is the same as doing copy/past with the mouse
from another application to Emacs mini buffer.  Wouldn't it be strange
if drag-drop and copy-paste behaved differently for the mini buffer?

>>>
>>> Mode lines also would have to be treated uniformly, I guess.
>>> Is there a useful meaning for a drop in the mode line?
>>
>> Well, if a drop of a file opens the file, it should do it for the
>> mode line also I think.
>
> But contrary to dropping it on the menu-bar (which does
> find-file-other-window), I think that dropping it on the mode line of
> a window should open the file in that window.

That is what I am doing now, so if you have several windows in a frame,
the one where a file is dropped is used.  This happens anywhere in the
buffer, not just the mode line.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-21 22:30                   ` Jan D.
@ 2004-01-22 10:19                     ` Kim F. Storm
  2004-01-22  9:46                       ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Kim F. Storm @ 2004-01-22 10:19 UTC (permalink / raw)
  Cc: miles, rms, monnier, emacs-devel

"Jan D." <jan.h.d@swipnet.se> writes:

> >
> > I think it is better not to try to say yes and no in different Emacs
> > buffers.  We should treat all of the buffer text areas in a uniform way
> > as regards accepting drops there.
> 
> Okay, then we can put the data in the kill ring if it can't be inserted.
> 
> > However, the menu bars could be treated differently, since the C code
> > can tell whether the pointer is in a menu bar.  Likewise, maybe Emacs
> > could always reject drops in scroll bars, or in the echo area when the
> > minibuffer is inactive (or maybe always in the echo area).

IMO, dropping it in the echo area/mini buffer should mean to copy the
file-name/whatever to the kill-ring unconditionally.

> >
> > Mode lines also would have to be treated uniformly, I guess.
> > Is there a useful meaning for a drop in the mode line?
> 
> Well, if a drop of a file opens the file, it should do it for the
> mode line also I think.

But contrary to dropping it on the menu-bar (which does
find-file-other-window), I think that dropping it on the mode line of
a window should open the file in that window.


-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-22  9:46                       ` Jan D.
@ 2004-01-22 11:32                         ` Kim F. Storm
  2004-01-23 18:25                         ` Richard Stallman
  1 sibling, 0 replies; 56+ messages in thread
From: Kim F. Storm @ 2004-01-22 11:32 UTC (permalink / raw)
  Cc: emacs-devel, rms, monnier, miles

"Jan D." <jan.h.d@swipnet.se> writes:

> > IMO, dropping it in the echo area/mini buffer should mean to copy the
> > file-name/whatever to the kill-ring unconditionally.
> 
> Hmm, I think it is likely that someone might want to drop say a file
> name (i.e. mark a file name in some other application and drag it to
> Emacs) to the mini buffer, and really have the text inserted there.
> I am talking about dragging text here, not a uri-list, which currently
> opens the file instead (for example, dragging from a file manager).
> I think this operation is the same as doing copy/past with the mouse
> from another application to Emacs mini buffer.  Wouldn't it be strange
> if drag-drop and copy-paste behaved differently for the mini buffer?

Yes, you are right.

> That is what I am doing now, so if you have several windows in a frame,
> the one where a file is dropped is used.  This happens anywhere in the
> buffer, not just the mode line.

So if you drag a file name, the file opens in that window,
if you drag text, text is inserted in that window.

Sounds good.

-- 
Kim F. Storm <storm@cua.dk> http://www.cua.dk

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-21 22:22               ` Jan D.
@ 2004-01-22 19:00                 ` Richard Stallman
  2004-01-22 19:27                   ` Jan D.
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-22 19:00 UTC (permalink / raw)
  Cc: emacs-devel

    > Which of these messages causes the Lisp-level drag-n-drop event?
    > I would guess it is the last message that does so.

    No, they all do.  That is, the messages the source sends: XdndEnter,
    XdndPosition, XdndPosition and XdndLeave (mouse moved away from Emacs
    or drop aborted).  The replies are sent from lisp with 
    x-send-client-message.

If all of them turn into Lisp events, then all of them could be customized
to depend on any aspect of the environment.  But why bother to make
a Lisp event for anything except the actual drop?  I can see that is
more flexible, but it could be much slower.

    > The time to look up the proper key binding is when the drop *ends*,
    > and only then.  It is not hard to get the key bindings for a given
    > place on the Emacs frame.  We do that for mouse clicks, we could do it
    > here too.

    That is too late.  We must know if we are going to accept the drop 
    before
    it ends.

I think it is acceptable to always accept the drop, when the pointer
is on a buffer text area.

However, since you've implemented Lisp events for all the messages
in the drag-n-drop protocol, I guess it ought to be easy enough
to make the Lisp code that handles the event run some function
provided by the major mode in order to decide whether a drop
is acceptable at a given point.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-22 19:00                 ` Richard Stallman
@ 2004-01-22 19:27                   ` Jan D.
  0 siblings, 0 replies; 56+ messages in thread
From: Jan D. @ 2004-01-22 19:27 UTC (permalink / raw)
  Cc: emacs-devel

>> Which of these messages causes the Lisp-level drag-n-drop event?
>> I would guess it is the last message that does so.
>
>     No, they all do.  That is, the messages the source sends: 
> XdndEnter,
>     XdndPosition, XdndPosition and XdndLeave (mouse moved away from 
> Emacs
>     or drop aborted).  The replies are sent from lisp with
>     x-send-client-message.
>
> If all of them turn into Lisp events, then all of them could be 
> customized
> to depend on any aspect of the environment.  But why bother to make
> a Lisp event for anything except the actual drop?  I can see that is
> more flexible, but it could be much slower.

Yes, it is much more flexible.  There have never been a stable common
drag and drop protocol for X, so I fully expect them to change.
Some things, such as what types of drop data to accept, are much easier
to customize and handle in lisp than in C.  It is not nice to
say that we accept anything and then either raise an error because
the data could not be handeled, or just ignore the data because nothing
took care of the final drop event.

The slowness is mostly the sending of events through the X server
anyway.

>
>> The time to look up the proper key binding is when the drop *ends*,
>> and only then.  It is not hard to get the key bindings for a given
>> place on the Emacs frame.  We do that for mouse clicks, we could do it
>> here too.
>
>     That is too late.  We must know if we are going to accept the drop
>     before
>     it ends.
>
> I think it is acceptable to always accept the drop, when the pointer
> is on a buffer text area.

I disagree, it goes against the whole point of having a protocol in the
first place.  Applications should accept drops they know they can 
handle,
anything else is to confuse the user.

>
> However, since you've implemented Lisp events for all the messages
> in the drag-n-drop protocol, I guess it ought to be easy enough
> to make the Lisp code that handles the event run some function
> provided by the major mode in order to decide whether a drop
> is acceptable at a given point.

This is my current approach, but the function is called through a
variable that can be made buffer local if so needed.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-22  9:46                       ` Jan D.
  2004-01-22 11:32                         ` Kim F. Storm
@ 2004-01-23 18:25                         ` Richard Stallman
  2004-01-23 20:05                           ` Jan D.
  1 sibling, 1 reply; 56+ messages in thread
From: Richard Stallman @ 2004-01-23 18:25 UTC (permalink / raw)
  Cc: miles, emacs-devel, monnier, storm

Earlier I thought you were saying it was too difficult
to decide based on specific details whether to allow a certain
drop in a certain buffer.  But now that you've explained that
every message leads to a LIsp-level event, I can see this is
not difficult at all.

    That is what I am doing now, so if you have several windows in a frame,
    the one where a file is dropped is used.  This happens anywhere in the
    buffer, not just the mode line.

That might make sense in most cases.  But Dired buffers should treat
it differently, and that means it can't be a general Emacs convention.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-23 18:25                         ` Richard Stallman
@ 2004-01-23 20:05                           ` Jan D.
  2004-01-24 21:39                             ` Richard Stallman
  0 siblings, 1 reply; 56+ messages in thread
From: Jan D. @ 2004-01-23 20:05 UTC (permalink / raw)
  Cc: emacs-devel, monnier, storm, miles

> Earlier I thought you were saying it was too difficult
> to decide based on specific details whether to allow a certain
> drop in a certain buffer.  But now that you've explained that
> every message leads to a LIsp-level event, I can see this is
> not difficult at all.

I probably didn't explain it very well.  I was thinking of text versus
file names.  Dropping a file name on the menu bar, or a read only buffer
is OK, it justs open the file in that window.  But dropping text on the
same place should not insert the text.  So the question was, how can
the code know if somebody has reconfigured the dropping of file names
to actually insert the file name as text instead of opening it?  We can
not know that the drop should be rejected.  But the suggestion made here
was to in that case not reject it, but rather put it in the kill ring
and display a message about it.

>     That is what I am doing now, so if you have several windows in a 
> frame,
>     the one where a file is dropped is used.  This happens anywhere in 
> the
>     buffer, not just the mode line.
>
> That might make sense in most cases.  But Dired buffers should treat
> it differently, and that means it can't be a general Emacs convention.

I'm working on dired so it will handle drop of files as a file manager,
i.e. move, copy or link them to the directory.

	Jan D.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: Drag and drop patch for X, please review.
  2004-01-23 20:05                           ` Jan D.
@ 2004-01-24 21:39                             ` Richard Stallman
  0 siblings, 0 replies; 56+ messages in thread
From: Richard Stallman @ 2004-01-24 21:39 UTC (permalink / raw)
  Cc: emacs-devel, monnier, storm, miles

      So the question was, how can
    the code know if somebody has reconfigured the dropping of file names
    to actually insert the file name as text instead of opening it?

I don't see why it is difficult to give the user a way to specify the
answers.

    > That might make sense in most cases.  But Dired buffers should treat
    > it differently, and that means it can't be a general Emacs convention.

    I'm working on dired so it will handle drop of files as a file manager,
    i.e. move, copy or link them to the directory.

Thanks.  The point I am making now is that we want to teach people
something else--such as dropping on a mode line--as the way
to visit a file.  That would work regardless of what kind of buffer
is currently displayed in the window.

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2004-01-24 21:39 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-01-17 16:35 Drag and drop patch for X, please review Jan D.
2004-01-17 20:20 ` David Kastrup
2004-01-18 20:22   ` Jan D.
2004-01-18 21:50     ` Kim F. Storm
2004-01-18 21:09       ` Jan D.
2004-01-18  0:40 ` Miles Bader
2004-01-18 20:44   ` Jan D.
2004-01-18 21:34     ` Kai Grossjohann
2004-01-18 21:55       ` Jan D.
2004-01-18 23:08         ` Miles Bader
2004-01-19 20:12           ` Richard Stallman
2004-01-19 20:43           ` Jan D.
2004-01-20  2:34             ` Miles Bader
2004-01-19 20:49           ` Jan D.
2004-01-18 22:10     ` Kim F. Storm
2004-01-18 21:14       ` Jan D.
2004-01-19 18:24     ` Stefan Monnier
2004-01-19 20:47       ` Jan D.
2004-01-19 23:35         ` Jason Rumney
2004-01-19 23:50           ` Jan D.
2004-01-20 15:52         ` Stefan Monnier
2004-01-20 16:05           ` Jan D.
2004-01-20 18:41             ` Stefan Monnier
2004-01-20 20:50               ` Jan D.
2004-01-20 21:12                 ` Stefan Monnier
2004-01-20 21:27                   ` Jan D.
2004-01-20 22:09                     ` Stefan Monnier
2004-01-20 22:28                       ` Jan D.
2004-01-20 23:38                         ` Stefan Monnier
2004-01-21 21:08                 ` Richard Stallman
2004-01-21 22:30                   ` Jan D.
2004-01-22 10:19                     ` Kim F. Storm
2004-01-22  9:46                       ` Jan D.
2004-01-22 11:32                         ` Kim F. Storm
2004-01-23 18:25                         ` Richard Stallman
2004-01-23 20:05                           ` Jan D.
2004-01-24 21:39                             ` Richard Stallman
2004-01-18 19:14 ` Richard Stallman
2004-01-18 21:02   ` Jan D.
2004-01-19 20:12     ` Richard Stallman
2004-01-19 21:14       ` Jan D.
2004-01-20 15:31         ` Richard Stallman
2004-01-20 15:49           ` Jan D.
2004-01-21 21:09             ` Richard Stallman
2004-01-21 22:22               ` Jan D.
2004-01-22 19:00                 ` Richard Stallman
2004-01-22 19:27                   ` Jan D.
2004-01-20 16:02         ` Stefan Monnier
2004-01-20 16:24           ` Jan D.
2004-01-20 18:43             ` Stefan Monnier
2004-01-20 20:33               ` Jan D.
2004-01-20 20:43                 ` Stefan Monnier
2004-01-21 21:08               ` Richard Stallman
2004-01-21 21:14                 ` Stefan Monnier
2004-01-21 22:02                   ` Jan D.
2004-01-18 19:16 ` Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).