diff options
author | Po Lu <luangruo@yahoo.com> | 2022-03-16 13:18:12 +0000 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-03-16 13:28:53 +0000 |
commit | 3de3f12b9402c731aca1a583a15fc6245efea136 (patch) | |
tree | dd0b83c98156cb6aecd01d40bdda7ef20df05844 | |
parent | 65f92837fa58c943f689fb847edcfd44c8a8a6c1 (diff) | |
download | emacs-3de3f12b9402c731aca1a583a15fc6245efea136.tar.gz |
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.
-rw-r--r-- | lisp/term/haiku-win.el | 11 | ||||
-rw-r--r-- | src/haiku_io.c | 4 | ||||
-rw-r--r-- | src/haiku_select.cc | 64 | ||||
-rw-r--r-- | src/haiku_support.cc | 59 | ||||
-rw-r--r-- | src/haiku_support.h | 10 | ||||
-rw-r--r-- | src/haikuselect.c | 140 | ||||
-rw-r--r-- | src/haikuselect.h | 14 | ||||
-rw-r--r-- | src/haikuterm.c | 12 | ||||
-rw-r--r-- | 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 c4810f116d2..322f1a18de6 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 f9fa4095f9f..89f0877eb67 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 011ad58036f..abb07b20028 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 4bd801242af..884e3583e25 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 41bd1e1c84f..78d51b83d8b 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 65dac0e02fa..f291fa70edd 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 566aae596f6..14b779c36dc 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 52846fc1450..9844a09a024 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 64fd0ec2b71..8d0af8dc679 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); |