emacs-diffs
[Top][All Lists]
Advanced

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

master 3de3f12b94 1/2: Redo Haiku DND support


From: Po Lu
Subject: master 3de3f12b94 1/2: Redo Haiku DND support
Date: Wed, 16 Mar 2022 09:30:08 -0400 (EDT)

branch: master
commit 3de3f12b9402c731aca1a583a15fc6245efea136
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Redo Haiku DND support
    
    * 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 |  11 ++--
 src/haiku_io.c         |   4 +-
 src/haiku_select.cc    |  64 ++++++++++++++++++++++
 src/haiku_support.cc   |  59 ++++++---------------
 src/haiku_support.h    |  10 ++--
 src/haikuselect.c      | 140 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/haikuselect.h      |  14 ++++-
 src/haikuterm.c        |  12 ++---
 src/haikuterm.h        |   1 +
 9 files changed, 254 insertions(+), 61 deletions(-)

diff --git a/lisp/term/haiku-win.el b/lisp/term/haiku-win.el
index c4810f116d..322f1a18de 100644
--- a/lisp/term/haiku-win.el
+++ b/lisp/term/haiku-win.el
@@ -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)
diff --git a/src/haiku_io.c b/src/haiku_io.c
index f9fa4095f9..89f0877eb6 100644
--- a/src/haiku_io.c
+++ b/src/haiku_io.c
@@ -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:
diff --git a/src/haiku_select.cc b/src/haiku_select.cc
index 011ad58036..abb07b2002 100644
--- a/src/haiku_select.cc
+++ b/src/haiku_select.cc
@@ -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;
+}
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index 4bd801242a..884e3583e2 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -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;
+}
diff --git a/src/haiku_support.h b/src/haiku_support.h
index 41bd1e1c84..78d51b83d8 100644
--- a/src/haiku_support.h
+++ b/src/haiku_support.h
@@ -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);
diff --git a/src/haikuselect.c b/src/haikuselect.c
index 65dac0e02f..f291fa70ed 100644
--- a/src/haikuselect.c
+++ b/src/haikuselect.c
@@ -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);
diff --git a/src/haikuselect.h b/src/haikuselect.h
index 566aae596f..14b779c36d 100644
--- a/src/haikuselect.h
+++ b/src/haikuselect.h
@@ -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
diff --git a/src/haikuterm.c b/src/haikuterm.c
index 52846fc145..9844a09a02 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -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:
diff --git a/src/haikuterm.h b/src/haikuterm.h
index 64fd0ec2b7..8d0af8dc67 100644
--- a/src/haikuterm.h
+++ b/src/haikuterm.h
@@ -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);
 



reply via email to

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