commit 7f6c9253838baba7cdd38573179bc0d3a724e25b (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Tue Apr 5 11:37:29 2022 +0800 Add support for dragging text onto windows that don't support any DND protocol * src/xselect.c (x_own_selection): Export function. (x_handle_selection_request): Handle selection requests to the pending DND time. (x_set_pending_dnd_time): New function. * src/xterm.c (x_dnd_send_unsupported_drop): New function. Implement according to the suggestions in the XDND protocol specification. (x_dnd_get_target_window): Return the toplevel window as well. (x_dnd_cleanup_drag_and_drop, x_dnd_begin_drag_and_drop) (x_dnd_update_state, handle_one_xevent): Send unsupported drops and use last seen toplevel instead of target for `return_frame'. * src/xterm.h: Update prototypes. diff --git a/src/xselect.c b/src/xselect.c index 7719876884..2969c816a3 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -39,6 +39,8 @@ along with GNU Emacs. If not, see . */ #include +static Time pending_dnd_time; + struct prop_location; struct selection_data; @@ -304,7 +306,7 @@ x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom) Update the Vselection_alist so that we can reply to later requests for our selection. */ -static void +void x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value, Lisp_Object frame) { @@ -771,6 +773,12 @@ x_handle_selection_request (struct selection_input_event *event) if (!dpyinfo) goto DONE; + /* This is how the XDND protocol recommends dropping text onto a + target that doesn't support XDND. */ + if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1 + || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2) + selection_symbol = QXdndSelection; + local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo); /* Decline if we don't own any selections. */ @@ -2671,6 +2679,12 @@ x_timestamp_for_selection (struct x_display_info *dpyinfo, return value; } +void +x_set_pending_dnd_time (Time time) +{ + pending_dnd_time = time; +} + static void syms_of_xselect_for_pdumper (void); void diff --git a/src/xterm.c b/src/xterm.c index d29a7a122a..77861c3fc0 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -899,9 +899,14 @@ static int x_dnd_return_frame; `x_dnd_begin_drag_and_drop'. */ static struct frame *x_dnd_return_frame_object; -/* The last toplevel window the mouse pointer moved over. */ +/* The last drop target window the mouse pointer moved over. This can + be different from `x_dnd_last_seen_toplevel' if that window had an + XdndProxy. */ static Window x_dnd_last_seen_window; +/* The last toplevel the mouse pointer moved over. */ +static Window x_dnd_last_seen_toplevel; + /* The window where the drop happened. Normally None, but it is set when something is actually dropped. */ static Window x_dnd_end_window; @@ -2747,10 +2752,104 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo, return rc; } +/* From the XDND protocol specification: + + Dropping on windows that do not support XDND + + Since middle clicking is the universal shortcut for pasting in X, + one can drop data into a window that does not support XDND by: + + 1. After the mouse has been released to trigger the drop, obtain + ownership of XA_PRIMARY. + + 2. Send a ButtonPress event and then a ButtonRelease event to the + deepest subwindow containing the mouse to simulate a middle click. + The times for these events should be the time of the actual button + release +1 and +2, respectively. These values will not be used by + anybody else, so one can unambiguously recognize the resulting + XConvertSelection() request. + + 3. If a request for XA_PRIMARY arrives bearing the timestamp of + either the ButtonPress or the ButtonRelease event, treat it as a + request for XdndSelection. Note that you must use the X data + types instead of the MIME types in this case. (e.g. XA_STRING + instead of text/plain). */ +static void +x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_window, + int root_x, int root_y, Time before) +{ + XEvent event; + int dest_x, dest_y; + Window child_return, child; + Lisp_Object frame; + int i; + + for (i = 0; i < x_dnd_n_targets; ++i) + { + if (x_dnd_targets[i] == XA_STRING + || x_dnd_targets[i] == dpyinfo->Xatom_COMPOUND_TEXT + || x_dnd_targets[i] == dpyinfo->Xatom_UTF8_STRING) + break; + } + + if (i == x_dnd_n_targets) + return; + + event.xbutton.type = ButtonPress; + event.xbutton.serial = 0; + event.xbutton.send_event = True; + event.xbutton.display = dpyinfo->display; + event.xbutton.root = dpyinfo->root_window; + event.xbutton.x_root = root_x; + event.xbutton.y_root = root_y; + + XSETFRAME (frame, x_dnd_frame); + + x_catch_errors (dpyinfo->display); + child = dpyinfo->root_window; + + while (XTranslateCoordinates (dpyinfo->display, child, + child, root_x, root_y, &dest_x, + &dest_y, &child_return) + && child_return != None + && XTranslateCoordinates (dpyinfo->display, child, + child_return, root_x, root_y, + &dest_x, &dest_y, &child)) + { + child = child_return; + root_x = dest_x; + root_y = dest_y; + } + + if (child != dpyinfo->root_window) + { + x_own_selection (QPRIMARY, Qnil, frame); + + event.xbutton.window = child; + event.xbutton.x = dest_x; + event.xbutton.y = dest_y; + event.xbutton.state = 0; + event.xbutton.button = 2; + event.xbutton.same_screen = True; + event.xbutton.time = before + 1; + event.xbutton.time = before + 2; + + x_set_pending_dnd_time (before); + + XSendEvent (dpyinfo->display, child, + True, ButtonPressMask, &event); + event.xbutton.type = ButtonRelease; + XSendEvent (dpyinfo->display, child, + True, ButtonReleaseMask, &event); + } + + x_uncatch_errors (); +} + static Window x_dnd_get_target_window (struct x_display_info *dpyinfo, int root_x, int root_y, int *proto_out, - int *motif_out) + int *motif_out, Window *toplevel_out) { Window child_return, child, dummy, proxy; int dest_x_return, dest_y_return, rc, proto, motif; @@ -2767,6 +2866,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, proto = -1; *motif_out = XM_DRAG_STYLE_NONE; + *toplevel_out = None; if (x_dnd_use_toplevels) { @@ -2779,6 +2879,8 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, && FRAME_X_WINDOW (x_dnd_frame) == child) *motif_out = XM_DRAG_STYLE_NONE; + *toplevel_out = child; + if (child != None) { #ifndef USE_XCB @@ -2808,6 +2910,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, { *proto_out = -1; *motif_out = XM_DRAG_STYLE_NONE; + *toplevel_out = None; return None; } @@ -2841,6 +2944,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, if (proto != -1) { *proto_out = proto; + *toplevel_out = overlay_window; x_uncatch_errors_after_check (); return proxy; @@ -2863,6 +2967,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, if (proto != -1) { + *toplevel_out = dpyinfo->root_window; *proto_out = proto; return proxy; } @@ -2871,6 +2976,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, /* No toplevel was found and the overlay and root windows were not proxies, so return None. */ *proto_out = -1; + *toplevel_out = dpyinfo->root_window; return None; } @@ -2894,21 +3000,6 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, break; } - proxy = x_dnd_get_window_proxy (dpyinfo, child_return); - - if (proxy != None) - { - proto = x_dnd_get_window_proto (dpyinfo, proxy); - - if (proto != -1) - { - *proto_out = proto; - - x_uncatch_errors (); - return proxy; - } - } - if (child_return) { if (x_dnd_get_wm_state_and_proto (dpyinfo, child_return, @@ -2919,11 +3010,28 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, { *proto_out = proto; *motif_out = motif; + *toplevel_out = child_return; x_uncatch_errors (); return child_return; } + proxy = x_dnd_get_window_proxy (dpyinfo, child_return); + + if (proxy != None) + { + proto = x_dnd_get_window_proto (dpyinfo, proxy); + + if (proto != -1) + { + *proto_out = proto; + *toplevel_out = child_return; + + x_uncatch_errors (); + return proxy; + } + } + rc = XTranslateCoordinates (dpyinfo->display, child, child_return, dest_x_return, dest_y_return, @@ -2934,6 +3042,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, { x_uncatch_errors_after_check (); *proto_out = -1; + *toplevel_out = dpyinfo->root_window; return None; } } @@ -2956,6 +3065,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, if (proto != -1) { *proto_out = proto; + *toplevel_out = child; return proxy; } } @@ -2993,6 +3103,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, if (proto != -1) { *proto_out = proto; + *toplevel_out = overlay_window; x_uncatch_errors_after_check (); return proxy; @@ -3014,6 +3125,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, if (proto != -1) { + *toplevel_out = child; *proto_out = proto; return proxy; } @@ -3021,6 +3133,7 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo, } *proto_out = x_dnd_get_window_proto (dpyinfo, child); + *toplevel_out = child; return child; #endif } @@ -3370,6 +3483,7 @@ x_dnd_cleanup_drag_and_drop (void *frame) x_dnd_end_window = x_dnd_last_seen_window; x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; x_dnd_in_progress = false; x_set_dnd_targets (NULL, 0); } @@ -9236,6 +9350,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, x_dnd_in_progress = true; x_dnd_frame = f; x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; x_dnd_last_protocol_version = -1; x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; x_dnd_mouse_rect_target = None; @@ -9402,6 +9517,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, x_dnd_end_window = x_dnd_last_seen_window; x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; x_dnd_in_progress = false; x_dnd_frame = NULL; x_set_dnd_targets (NULL, 0); @@ -13053,7 +13169,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp) { int root_x, root_y, dummy_x, dummy_y, target_proto, motif_style; unsigned int dummy_mask; - Window dummy, dummy_child, target; + Window dummy, dummy_child, target, toplevel; xm_top_level_leave_message lmsg; xm_top_level_enter_message emsg; xm_drag_motion_message dmsg; @@ -13068,14 +13184,33 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp) { target = x_dnd_get_target_window (dpyinfo, root_x, root_y, &target_proto, - &motif_style); + &motif_style, &toplevel); - if (target != x_dnd_last_seen_window) + if (toplevel != x_dnd_last_seen_toplevel) { - if (target != FRAME_OUTER_WINDOW (x_dnd_frame) + if (toplevel != FRAME_OUTER_WINDOW (x_dnd_frame) && x_dnd_return_frame == 1) x_dnd_return_frame = 2; + if (x_dnd_return_frame == 2 + && x_any_window_to_frame (dpyinfo, toplevel)) + { + x_dnd_end_window = x_dnd_last_seen_window; + x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; + x_dnd_in_progress = false; + x_dnd_return_frame_object + = x_any_window_to_frame (dpyinfo, toplevel); + x_dnd_return_frame = 3; + x_dnd_waiting_for_finish = false; + target = None; + } + + x_dnd_last_seen_toplevel = toplevel; + } + + if (target != x_dnd_last_seen_window) + { if (x_dnd_last_seen_window != None && x_dnd_last_protocol_version != -1 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) @@ -13099,19 +13234,6 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp) x_dnd_last_seen_window, &lmsg); } - if (x_dnd_return_frame == 2 - && x_any_window_to_frame (dpyinfo, target)) - { - x_dnd_end_window = x_dnd_last_seen_window; - x_dnd_last_seen_window = None; - x_dnd_in_progress = false; - x_dnd_return_frame_object - = x_any_window_to_frame (dpyinfo, target); - x_dnd_return_frame = 3; - x_dnd_waiting_for_finish = false; - target = None; - } - x_dnd_action = None; x_dnd_last_seen_window = target; x_dnd_last_protocol_version = target_proto; @@ -13208,6 +13330,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp) x_dnd_end_window = x_dnd_last_seen_window; x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; x_dnd_in_progress = false; x_dnd_waiting_for_finish = false; x_dnd_frame = NULL; @@ -14681,7 +14804,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (x_dnd_in_progress && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) { - Window target; + Window target, toplevel; int target_proto, motif_style; xm_top_level_leave_message lmsg; xm_top_level_enter_message emsg; @@ -14699,14 +14822,33 @@ handle_one_xevent (struct x_display_info *dpyinfo, event->xmotion.x_root, event->xmotion.y_root, &target_proto, - &motif_style); + &motif_style, &toplevel); - if (target != x_dnd_last_seen_window) + if (toplevel != x_dnd_last_seen_toplevel) { - if (target != FRAME_OUTER_WINDOW (x_dnd_frame) + if (toplevel != FRAME_OUTER_WINDOW (x_dnd_frame) && x_dnd_return_frame == 1) x_dnd_return_frame = 2; + if (x_dnd_return_frame == 2 + && x_any_window_to_frame (dpyinfo, toplevel)) + { + x_dnd_end_window = x_dnd_last_seen_window; + x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; + x_dnd_in_progress = false; + x_dnd_return_frame_object + = x_any_window_to_frame (dpyinfo, toplevel); + x_dnd_return_frame = 3; + x_dnd_waiting_for_finish = false; + target = None; + } + + x_dnd_last_seen_toplevel = toplevel; + } + + if (target != x_dnd_last_seen_window) + { if (x_dnd_last_seen_window != None && x_dnd_last_protocol_version != -1 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) @@ -14751,19 +14893,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } - if (x_dnd_return_frame == 2 - && x_any_window_to_frame (dpyinfo, target)) - { - x_dnd_end_window = x_dnd_last_seen_window; - x_dnd_last_seen_window = None; - x_dnd_in_progress = false; - x_dnd_return_frame_object - = x_any_window_to_frame (dpyinfo, target); - x_dnd_return_frame = 3; - x_dnd_waiting_for_finish = false; - target = None; - } - x_dnd_action = None; x_dnd_last_seen_window = target; x_dnd_last_protocol_version = target_proto; @@ -15311,11 +15440,19 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_waiting_for_motif_finish = 1; } } + else + { + x_set_pending_dnd_time (event->xbutton.time); + x_dnd_send_unsupported_drop (dpyinfo, x_dnd_last_seen_window, + event->xbutton.x_root, event->xbutton.y_root, + event->xbutton.time); + } } x_dnd_last_protocol_version = -1; x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; x_dnd_frame = NULL; x_set_dnd_targets (NULL, 0); } @@ -16136,7 +16273,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (x_dnd_in_progress && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame)) { - Window target; + Window target, toplevel; int target_proto, motif_style; /* Sometimes the drag-and-drop operation starts with the @@ -16151,14 +16288,34 @@ handle_one_xevent (struct x_display_info *dpyinfo, xev->root_x, xev->root_y, &target_proto, - &motif_style); + &motif_style, + &toplevel); - if (target != x_dnd_last_seen_window) + if (toplevel != x_dnd_last_seen_toplevel) { - if (target != FRAME_OUTER_WINDOW (x_dnd_frame) + if (toplevel != FRAME_OUTER_WINDOW (x_dnd_frame) && x_dnd_return_frame == 1) x_dnd_return_frame = 2; + if (x_dnd_return_frame == 2 + && x_any_window_to_frame (dpyinfo, toplevel)) + { + x_dnd_end_window = x_dnd_last_seen_window; + x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; + x_dnd_in_progress = false; + x_dnd_return_frame_object + = x_any_window_to_frame (dpyinfo, toplevel); + x_dnd_return_frame = 3; + x_dnd_waiting_for_finish = false; + target = None; + } + + x_dnd_last_seen_toplevel = toplevel; + } + + if (target != x_dnd_last_seen_window) + { if (x_dnd_last_seen_window != None && x_dnd_last_protocol_version != -1 && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) @@ -16205,19 +16362,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, } } - if (x_dnd_return_frame == 2 - && x_any_window_to_frame (dpyinfo, target)) - { - x_dnd_end_window = x_dnd_last_seen_window; - x_dnd_last_seen_window = None; - x_dnd_in_progress = false; - x_dnd_return_frame_object - = x_any_window_to_frame (dpyinfo, target); - x_dnd_return_frame = 3; - x_dnd_waiting_for_finish = false; - target = None; - } - x_dnd_action = None; x_dnd_last_seen_window = target; x_dnd_last_protocol_version = target_proto; @@ -16458,11 +16602,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_waiting_for_motif_finish = 1; } } + else + { + x_set_pending_dnd_time (xev->time); + x_dnd_send_unsupported_drop (dpyinfo, x_dnd_last_seen_window, + xev->root_x, xev->root_y, xev->time); + } } x_dnd_last_protocol_version = -1; x_dnd_last_motif_style = XM_DRAG_STYLE_NONE; x_dnd_last_seen_window = None; + x_dnd_last_seen_toplevel = None; x_dnd_frame = NULL; x_set_dnd_targets (NULL, 0); diff --git a/src/xterm.h b/src/xterm.h index 5627fd23c5..79dee6a569 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1489,6 +1489,8 @@ extern void x_clipboard_manager_save_all (void); extern Lisp_Object x_timestamp_for_selection (struct x_display_info *, Lisp_Object); +extern void x_set_pending_dnd_time (Time); +extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object); #ifdef USE_GTK extern bool xg_set_icon (struct frame *, Lisp_Object); commit c51d7c9e43f5bb0b030a992b291f31d31702437d Author: Po Lu Date: Tue Apr 5 09:07:36 2022 +0800 * configure.ac (HAVE_GIF): Respect --with-gif on PGTK. (bug#54633) diff --git a/configure.ac b/configure.ac index 254f15bef3..cda2a04be9 100644 --- a/configure.ac +++ b/configure.ac @@ -4292,7 +4292,8 @@ if test "${opsys}" = "mingw32"; then fi elif test "${HAVE_X11}" = "yes" && test "${with_gif}" != "no" \ || test "${HAVE_W32}" = "yes" || test "${HAVE_NS}" = "yes" \ - || test "${HAVE_BE_APP}" = "yes" || test "$window_system" = "pgtk"; then + || test "${HAVE_BE_APP}" = "yes" || test "$window_system" = "pgtk" \ + && test "${with_gif}" != "no"; then AC_CHECK_HEADER(gif_lib.h, # EGifPutExtensionLast only exists from version libungif-4.1.0b1. # Earlier versions can crash Emacs, but version 5.0 removes EGifPutExtensionLast. commit 1e1a66831bf1d8ca33b3ad37d23211fa98d92e63 Author: Po Lu Date: Tue Apr 5 00:54:03 2022 +0000 Respect new DND options when dragging to ourselves on Haiku * lisp/mouse.el (mouse-drag-and-drop-region): Allow dragging to the current frame if we know `return-frame' doesn't work. * lisp/term/haiku-win.el (haiku-dnd-drag-handler): New function. * src/haiku_support.cc (MouseMoved): Don't send drag motion events for the drag frame. * src/haikuselect.c (haiku_note_drag_motion_1) (haiku_note_drag_motion_2, haiku_note_drag_motion): New functions. (syms_of_haikuselect): New variable `haiku-drag-track-function'. * src/haikuterm.c (haiku_read_socket): Note mouse motion in that case.q * src/haikuterm.h: Update prototypes. diff --git a/lisp/mouse.el b/lisp/mouse.el index 26a17365da..b66cfad487 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -3190,7 +3190,12 @@ is copied instead of being cut." (if mouse-drag-and-drop-region-cut-when-buffers-differ 'XdndActionMove 'XdndActionCopy) - (posn-window (event-end event)) 'now) + (posn-window (event-end event)) 'now + ;; On platforms where we know + ;; `return-frame' doesn't + ;; work, allow dropping on + ;; the drop frame. + (eq window-system 'haiku)) (quit nil)))) (when (framep drag-action-or-frame) ;; With some window managers `x-begin-drag' diff --git a/lisp/term/haiku-win.el b/lisp/term/haiku-win.el index 5b4ef0aaef..fd0b68b5fc 100644 --- a/lisp/term/haiku-win.el +++ b/lisp/term/haiku-win.el @@ -277,6 +277,21 @@ This is necessary because on Haiku `use-system-tooltip' doesn't take effect on menu items until the menu bar is updated again." (force-mode-line-update t)) +;; Note that `mouse-position' can't return the actual frame the mouse +;; pointer is under, so this only works for the frame where the drop +;; started. +(defun haiku-dnd-drag-handler () + "Handle mouse movement during drag-and-drop." + (let ((track-mouse 'drag-source) + (mouse-position (mouse-pixel-position))) + (when (car mouse-position) + (dnd-handle-movement (posn-at-x-y (cadr mouse-position) + (cddr mouse-position) + (car mouse-position))) + (redisplay)))) + +(setq haiku-drag-track-function #'haiku-dnd-drag-handler) + (defun x-begin-drag (targets &optional action frame _return-frame allow-current-frame) "SKIP: real doc in xfns.c." (unless haiku-dnd-selection-value diff --git a/src/haiku_support.cc b/src/haiku_support.cc index 40112e2b71..830255d3f0 100644 --- a/src/haiku_support.cc +++ b/src/haiku_support.cc @@ -1524,13 +1524,23 @@ class EmacsView : public BView MouseMoved (BPoint point, uint32 transit, const BMessage *drag_msg) { struct haiku_mouse_motion_event rq; + int32 windowid; + EmacsWindow *window; + window = (EmacsWindow *) Window (); rq.just_exited_p = transit == B_EXITED_VIEW; rq.x = point.x; rq.y = point.y; - rq.window = this->Window (); + rq.window = window; rq.time = system_time (); - rq.dnd_message = drag_msg != NULL; + + if (drag_msg && (drag_msg->IsSourceRemote () + || drag_msg->FindInt32 ("emacs:window_id", + &windowid) != B_OK + || windowid != window->window_id)) + rq.dnd_message = true; + else + rq.dnd_message = false; if (ToolTip ()) ToolTip ()->SetMouseRelativeLocation (BPoint (-(point.x - tt_absl_pos.x), diff --git a/src/haikuselect.c b/src/haikuselect.c index f6199ccc1e..c3053688f5 100644 --- a/src/haikuselect.c +++ b/src/haikuselect.c @@ -791,6 +791,28 @@ ignored if it is dropped on top of FRAME. */) return unbind_to (idx, Qnil); } +static Lisp_Object +haiku_note_drag_motion_1 (void *data) +{ + if (!NILP (Vhaiku_drag_track_function)) + return call0 (Vhaiku_drag_track_function); + + return Qnil; +} + +static Lisp_Object +haiku_note_drag_motion_2 (enum nonlocal_exit exit, Lisp_Object error) +{ + return Qnil; +} + +void +haiku_note_drag_motion (void) +{ + internal_catch_all (haiku_note_drag_motion_1, NULL, + haiku_note_drag_motion_2); +} + void syms_of_haikuselect (void) { @@ -800,6 +822,12 @@ Otherwise, an error will be signalled if adding a file reference to a system message failed. */); haiku_signal_invalid_refs = true; + DEFVAR_LISP ("haiku-drag-track-function", Vhaiku_drag_track_function, + doc: /* If non-nil, a function to call upon mouse movement while dragging a message. +The function is called without any arguments. `mouse-position' can be +used to retrieve the current position of the mouse. */); + Vhaiku_drag_track_function = Qnil; + DEFSYM (QSECONDARY, "SECONDARY"); DEFSYM (QCLIPBOARD, "CLIPBOARD"); DEFSYM (QSTRING, "STRING"); diff --git a/src/haikuterm.c b/src/haikuterm.c index e2d6a9a467..1270fba410 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c @@ -3155,6 +3155,9 @@ haiku_read_socket (struct terminal *terminal, struct input_event *hold_quit) XSETINT (inev.y, b->y); XSETFRAME (inev.frame_or_window, f); } + else + haiku_note_drag_motion (); + break; } } diff --git a/src/haikuterm.h b/src/haikuterm.h index 5f8052f0f9..8f311b2ab1 100644 --- a/src/haikuterm.h +++ b/src/haikuterm.h @@ -293,6 +293,7 @@ extern void haiku_put_pixel (haiku bitmap, int x, int y, unsigned long pixel); extern Lisp_Object haiku_menu_show (struct frame *f, int x, int y, int menu_flags, Lisp_Object title, const char **error_name); extern Lisp_Object haiku_popup_dialog (struct frame *f, Lisp_Object header, Lisp_Object contents); +extern void haiku_note_drag_motion (void); extern void initialize_frame_menubar (struct frame *f);