]> git.eshelyaron.com Git - emacs.git/commitdiff
Redo Haiku DND support
authorPo Lu <luangruo@yahoo.com>
Wed, 16 Mar 2022 13:18:12 +0000 (13:18 +0000)
committerPo Lu <luangruo@yahoo.com>
Wed, 16 Mar 2022 13:28:53 +0000 (13:28 +0000)
* lisp/term/haiku-win.el (haiku-dnd-handle-drag-n-drop-event):
Update for new DND event format.
* src/haiku_io.c (haiku_len): Handle DRAG_AND_DROP_EVENTs.
* src/haiku_select.cc (be_enum_message, be_get_refs_data)
(be_get_message_data): New function.
* src/haiku_support.cc (class Emacs): Remove `RefsReceived'.
(MessageReceived): Generate new kind of drag-n-drop events.
* src/haiku_support.h (enum haiku_event_type): Rename
`REFS_EVENT' to `DRAG_AND_DROP_EVENT'.
(struct haiku_refs_event): Delete struct.
(struct haiku_drag_and_drop_event): New struct.
* src/haikuselect.c (haiku_message_to_lisp): New function.
(syms_of_haikuselect): New symbols.
* src/haikuselect.h: Update prototypes.
* src/haikuterm.c (haiku_read_socket): Handle new type of
drag-and-drop events by serializing drop message to Lisp and
letting Lisp code do the processing.
* src/haikuterm.h: Update prototypes.

lisp/term/haiku-win.el
src/haiku_io.c
src/haiku_select.cc
src/haiku_support.cc
src/haiku_support.h
src/haikuselect.c
src/haikuselect.h
src/haikuterm.c
src/haikuterm.h

index c4810f116d25c5c6f0dbd647886faf7c6761831b..322f1a18de66e89f34d2f249e3b67934391da078 100644 (file)
@@ -130,9 +130,14 @@ If TYPE is nil, return \"text/plain\"."
   (interactive "e")
   (let* ((string (caddr event))
         (window (posn-window (event-start event))))
-    (with-selected-window window
-      (raise-frame)
-      (dnd-handle-one-url window 'private (concat "file:" string)))))
+    (cond
+     ((assoc "refs" string)
+      (with-selected-window window
+        (raise-frame)
+        (dolist (filename (cddr (assoc "refs" string)))
+          (dnd-handle-one-url window 'private
+                              (concat "file:" filename)))))
+     (t (message "Don't know how to drop: %s" event)))))
 
 (define-key special-event-map [drag-n-drop]
             'haiku-dnd-handle-drag-n-drop-event)
index f9fa4095f9fe4b0a94f4c8c144795ee7b9f782ed..89f0877eb673253ec99aea01043c6c0ffc1f68b1 100644 (file)
@@ -90,8 +90,8 @@ haiku_len (enum haiku_event_type type)
       return sizeof (struct haiku_menu_bar_help_event);
     case ZOOM_EVENT:
       return sizeof (struct haiku_zoom_event);
-    case REFS_EVENT:
-      return sizeof (struct haiku_refs_event);
+    case DRAG_AND_DROP_EVENT:
+      return sizeof (struct haiku_drag_and_drop_event);
     case APP_QUIT_REQUESTED_EVENT:
       return sizeof (struct haiku_app_quit_requested_event);
     case DUMMY_EVENT:
index 011ad58036fcee8967cbc0ad661fbdca00fbd083..abb07b20028f33d223d00a831916e1b606081eda 100644 (file)
@@ -19,6 +19,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <config.h>
 
 #include <Clipboard.h>
+#include <Message.h>
+#include <Path.h>
+#include <Entry.h>
 
 #include <cstdlib>
 #include <cstring>
@@ -257,3 +260,64 @@ init_haiku_select (void)
   primary = new BClipboard ("primary");
   secondary = new BClipboard ("secondary");
 }
+
+int
+be_enum_message (void *message, int32 *tc, int32 index,
+                int32 *count, const char **name_return)
+{
+  BMessage *msg = (BMessage *) message;
+  type_code type;
+  char *name;
+  status_t rc;
+
+  rc = msg->GetInfo (B_ANY_TYPE, index, &name, &type, count);
+
+  if (rc != B_OK)
+    return 1;
+
+  *tc = type;
+  *name_return = name;
+  return 0;
+}
+
+int
+be_get_refs_data (void *message, const char *name,
+                 int32 index, char **path_buffer)
+{
+  status_t rc;
+  BEntry entry;
+  BPath path;
+  entry_ref ref;
+  BMessage *msg;
+
+  msg = (BMessage *) message;
+  rc = msg->FindRef (name, index, &ref);
+
+  if (rc != B_OK)
+    return 1;
+
+  rc = entry.SetTo (&ref, 0);
+
+  if (rc != B_OK)
+    return 1;
+
+  rc = entry.GetPath (&path);
+
+  if (rc != B_OK)
+    return 1;
+
+  *path_buffer = strdup (path.Path ());
+  return 0;
+}
+
+int
+be_get_message_data (void *message, const char *name,
+                    int32 type_code, int32 index,
+                    const void **buf_return,
+                    ssize_t *size_return)
+{
+  BMessage *msg = (BMessage *) message;
+
+  return msg->FindData (name, type_code,
+                       index, buf_return, size_return) != B_OK;
+}
index 4bd801242af0c85cd6b286e81da967cb3f587eb7..884e3583e25f80fcb69dcd30af183cad3cca8615 100644 (file)
@@ -381,37 +381,6 @@ public:
     haiku_write (APP_QUIT_REQUESTED_EVENT, &rq);
     return 0;
   }
-
-  void
-  RefsReceived (BMessage *msg)
-  {
-    struct haiku_refs_event rq;
-    entry_ref ref;
-    BEntry entry;
-    BPath path;
-    int32 cookie = 0;
-    int32 x, y;
-    void *window;
-
-    if ((msg->FindPointer ("window", 0, &window) != B_OK)
-       || (msg->FindInt32 ("x", 0, &x) != B_OK)
-       || (msg->FindInt32 ("y", 0, &y) != B_OK))
-      return;
-
-    rq.window = window;
-    rq.x = x;
-    rq.y = y;
-
-    while (msg->FindRef ("refs", cookie++, &ref) == B_OK)
-      {
-        if (entry.SetTo (&ref, 0) == B_OK
-            && entry.GetPath (&path) == B_OK)
-          {
-            rq.ref = strdup (path.Path ());
-            haiku_write (REFS_EVENT, &rq);
-          }
-      }
-  }
 };
 
 class EmacsWindow : public BWindow
@@ -665,21 +634,19 @@ public:
 
     if (msg->WasDropped ())
       {
-       entry_ref ref;
        BPoint whereto;
+       struct haiku_drag_and_drop_event rq;
 
-        if (msg->FindRef ("refs", &ref) == B_OK)
+       if (msg->FindPoint ("_drop_point_", &whereto) == B_OK)
          {
-           msg->what = B_REFS_RECEIVED;
-           msg->AddPointer ("window", this);
-           if (msg->FindPoint ("_drop_point_", &whereto) == B_OK)
-             {
-               this->ConvertFromScreen (&whereto);
-               msg->AddInt32 ("x", whereto.x);
-               msg->AddInt32 ("y", whereto.y);
-             }
-           be_app->PostMessage (msg);
-           msg->SendReply (B_OK);
+           this->ConvertFromScreen (&whereto);
+
+           rq.window = this;
+           rq.message = DetachCurrentMessage ();;
+           rq.x = whereto.x;
+           rq.y = whereto.y;
+
+           haiku_write (DRAG_AND_DROP_EVENT, &rq);
          }
       }
     else if (msg->GetPointer ("menuptr"))
@@ -3897,3 +3864,9 @@ EmacsWindow_signal_menu_update_complete (void *window)
   pthread_cond_signal (&w->menu_update_cv);
   pthread_mutex_unlock (&w->menu_update_mutex);
 }
+
+void
+BMessage_delete (void *message)
+{
+  delete (BMessage *) message;
+}
index 41bd1e1c84f1478486ef4c5b5ad5c7e8ff0fd937..78d51b83d8b1ab4cee8002e994d0934935de7736 100644 (file)
@@ -86,7 +86,7 @@ enum haiku_event_type
     FILE_PANEL_EVENT,
     MENU_BAR_HELP_EVENT,
     ZOOM_EVENT,
-    REFS_EVENT,
+    DRAG_AND_DROP_EVENT,
     APP_QUIT_REQUESTED_EVENT,
     DUMMY_EVENT,
     MENU_BAR_LEFT
@@ -113,12 +113,11 @@ struct haiku_expose_event
   int height;
 };
 
-struct haiku_refs_event
+struct haiku_drag_and_drop_event
 {
   void *window;
   int x, y;
-  /* Free this with free! */
-  char *ref;
+  void *message;
 };
 
 struct haiku_app_quit_requested_event
@@ -943,6 +942,9 @@ extern "C"
   extern void
   BWindow_dimensions (void *window, int *width, int *height);
 
+  extern void
+  BMessage_delete (void *message);
+
 #ifdef __cplusplus
   extern void *
   find_appropriate_view_for_draw (void *vw);
index 65dac0e02fa4e079814d99fa2394d27bf0443331..f291fa70edd27db28c44c74f7b0f12fb57c22e55 100644 (file)
@@ -179,6 +179,138 @@ same as `SECONDARY'.  */)
   return value ? Qt : Qnil;
 }
 
+/* Return the Lisp representation of MESSAGE.
+
+   It is an alist of strings, denoting message parameter names, to a
+   list the form (TYPE . (DATA ...)), where TYPE is an integer
+   denoting the system data type of DATA, and DATA is in the general
+   case a unibyte string.
+
+   If TYPE is a symbol instead of an integer, then DATA was specially
+   decoded.  If TYPE is `ref', then DATA is the absolute file name of
+   a file, or nil if decoding the file name failed.  If TYPE is
+   `string', then DATA is a unibyte string.  If TYPE is `short', then
+   DATA is a 16-bit signed integer.  If TYPE is `long', then DATA is a
+   32-bit signed integer.  If TYPE is `llong', then DATA is a 64-bit
+   signed integer. If TYPE is `byte' or `char', then DATA is an 8-bit
+   signed integer.  If TYPE is `bool', then DATA is a boolean.  */
+Lisp_Object
+haiku_message_to_lisp (void *message)
+{
+  Lisp_Object list = Qnil, tem, t1, t2;
+  const char *name;
+  char *pbuf;
+  const void *buf;
+  ssize_t buf_size;
+  int32 i, j, count, type_code;
+  int rc;
+
+  for (i = 0; !be_enum_message (message, &type_code, i,
+                               &count, &name); ++i)
+    {
+      tem = Qnil;
+
+      for (j = 0; j < count; ++j)
+       {
+         rc = be_get_message_data (message, name,
+                                   type_code, j,
+                                   &buf, &buf_size);
+         if (rc)
+           emacs_abort ();
+
+         switch (type_code)
+           {
+           case 'BOOL':
+             t1 = (*(bool *) buf) ? Qt : Qnil;
+             break;
+
+           case 'RREF':
+             rc = be_get_refs_data (message, name,
+                                    j, &pbuf);
+
+             if (rc)
+               {
+                 t1 = Qnil;
+                 break;
+               }
+
+             if (!pbuf)
+               memory_full (SIZE_MAX);
+
+             t1 = build_string (pbuf);
+             free (pbuf);
+             break;
+
+           case 'SHRT':
+             t1 = make_fixnum (*(int16 *) buf);
+             break;
+
+           case 'LONG':
+             t1 = make_int (*(int32 *) buf);
+             break;
+
+           case 'LLNG':
+             t1 = make_int ((intmax_t) *(int64 *) buf);
+             break;
+
+           case 'BYTE':
+           case 'CHAR':
+             t1 = make_fixnum (*(int8 *) buf);
+             break;
+
+           default:
+             t1 = make_uninit_string (buf_size);
+             memcpy (SDATA (t1), buf, buf_size);
+           }
+
+         tem = Fcons (t1, tem);
+       }
+
+      switch (type_code)
+       {
+       case 'CSTR':
+         t2 = Qstring;
+         break;
+
+       case 'SHRT':
+         t2 = Qshort;
+         break;
+
+       case 'LONG':
+         t2 = Qlong;
+         break;
+
+       case 'LLNG':
+         t2 = Qllong;
+         break;
+
+       case 'BYTE':
+         t2 = Qbyte;
+         break;
+
+       case 'RREF':
+         t2 = Qref;
+         break;
+
+       case 'CHAR':
+         t2 = Qchar;
+         break;
+
+       case 'BOOL':
+         t2 = Qbool;
+         break;
+
+       default:
+         t2 = make_int (type_code);
+       }
+
+      tem = Fcons (t2, tem);
+      list = Fcons (Fcons (build_string_from_utf8 (name), tem), list);
+    }
+
+  return list;
+}
+
 void
 syms_of_haikuselect (void)
 {
@@ -188,6 +320,14 @@ syms_of_haikuselect (void)
   DEFSYM (QUTF8_STRING, "UTF8_STRING");
   DEFSYM (Qforeign_selection, "foreign-selection");
   DEFSYM (QTARGETS, "TARGETS");
+  DEFSYM (Qstring, "string");
+  DEFSYM (Qref, "ref");
+  DEFSYM (Qshort, "short");
+  DEFSYM (Qlong, "long");
+  DEFSYM (Qllong, "llong");
+  DEFSYM (Qbyte, "byte");
+  DEFSYM (Qchar, "char");
+  DEFSYM (Qbool, "bool");
 
   defsubr (&Shaiku_selection_data);
   defsubr (&Shaiku_selection_put);
index 566aae596f641d338fc54d41106b2733b4603e17..14b779c36dcb443513ccdc141c6059bb4023758a 100644 (file)
@@ -23,6 +23,8 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <cstdio>
 #endif
 
+#include <SupportDefs.h>
+
 #ifdef __cplusplus
 #include <stdio.h>
 extern "C"
@@ -72,11 +74,19 @@ extern "C"
   extern bool
   BClipboard_owns_primary (void);
 
-  extern bool
-  BClipboard_owns_secondary (void);
+  extern bool BClipboard_owns_secondary (void);
 
   /* Free the returned data.  */
   extern void BClipboard_free_data (void *ptr);
+
+  extern int be_enum_message (void *message, int32 *tc, int index,
+                             int32 *count, const char **name_return);
+  extern int be_get_message_data (void *message, const char *name,
+                                 int32 type_code, int32 index,
+                                 const void **buf_return,
+                                 ssize_t *size_return);
+  extern int be_get_refs_data (void *message, const char *name,
+                              int32 index, char **path_buffer);
 #ifdef __cplusplus
 };
 #endif
index 52846fc14507ff0196df00a528321f0cda93a5a7..9844a09a0244dc9375b9cc543fcb25116f6c30e9 100644 (file)
@@ -3545,27 +3545,25 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit)
            haiku_make_fullscreen_consistent (f);
            break;
          }
-       case REFS_EVENT:
+       case DRAG_AND_DROP_EVENT:
          {
-           struct haiku_refs_event *b = buf;
+           struct haiku_drag_and_drop_event *b = buf;
            struct frame *f = haiku_window_to_frame (b->window);
 
            if (!f)
              {
-               free (b->ref);
+               BMessage_delete (b->message);
                continue;
              }
 
            inev.kind = DRAG_N_DROP_EVENT;
-           inev.arg = build_string_from_utf8 (b->ref);
+           inev.arg = haiku_message_to_lisp (b->message);
 
            XSETINT (inev.x, b->x);
            XSETINT (inev.y, b->y);
            XSETFRAME (inev.frame_or_window, f);
 
-           /* There should be no problem with calling free here.
-              free on Haiku is thread-safe.  */
-           free (b->ref);
+           BMessage_delete (b->message);
            break;
          }
        case APP_QUIT_REQUESTED_EVENT:
index 64fd0ec2b71854aed87fec02c13ebc56ad7a9e59..8d0af8dc67942842c88d025dc41f8554099d6c10 100644 (file)
@@ -255,6 +255,7 @@ extern void haiku_free_frame_resources (struct frame *f);
 extern void haiku_scroll_bar_remove (struct scroll_bar *bar);
 extern void haiku_clear_under_internal_border (struct frame *f);
 extern void haiku_set_name (struct frame *f, Lisp_Object name, bool explicit_p);
+extern Lisp_Object haiku_message_to_lisp (void *);
 
 extern struct haiku_display_info *haiku_term_init (void);