with. */
static int x_dnd_movement_x, x_dnd_movement_y;
+/* The frame for which `x-dnd-wheel-function' should be called. */
+static struct frame *x_dnd_wheel_frame;
+
+/* The coordinates which the wheel function should be called with. */
+static int x_dnd_wheel_x, x_dnd_wheel_y;
+
+/* The button that was pressed. */
+static int x_dnd_wheel_button;
+
+/* The modifier state when the button was pressed. */
+static int x_dnd_wheel_state;
+
+/* When the button was pressed. */
+static Time x_dnd_wheel_time;
+
#ifdef HAVE_XKB
/* The keyboard state during the drag-and-drop operation. */
static unsigned int x_dnd_keyboard_state;
#endif
x_dnd_return_frame_object = NULL;
x_dnd_movement_frame = NULL;
+ x_dnd_wheel_frame = NULL;
x_dnd_frame = NULL;
x_restore_events_after_dnd (f, &x_dnd_old_window_attrs);
}
}
+static void
+x_dnd_note_self_wheel (struct x_display_info *dpyinfo, Window target,
+ unsigned short root_x, unsigned short root_y,
+ int button, unsigned int state, Time time)
+{
+ struct frame *f;
+ int dest_x, dest_y;
+ Window child_return;
+
+ if (button < 4 || button > 7)
+ return;
+
+ f = x_top_window_to_frame (dpyinfo, target);
+
+ if (f && XTranslateCoordinates (dpyinfo->display,
+ dpyinfo->root_window,
+ FRAME_X_WINDOW (f),
+ root_x, root_y, &dest_x,
+ &dest_y, &child_return))
+ {
+ x_dnd_wheel_frame = f;
+ x_dnd_wheel_x = dest_x;
+ x_dnd_wheel_y = dest_y;
+ x_dnd_wheel_button = button;
+ x_dnd_wheel_state = state;
+ x_dnd_wheel_time = time;
+
+ return;
+ }
+}
+
static void
x_dnd_note_self_drop (struct x_display_info *dpyinfo, Window target,
unsigned short root_x, unsigned short root_y,
x_dnd_waiting_for_finish = false;
x_dnd_return_frame_object = NULL;
x_dnd_movement_frame = NULL;
+ x_dnd_wheel_frame = NULL;
}
/* This function is defined far away from the rest of the XDND code so
x_dnd_toplevels = NULL;
x_dnd_allow_current_frame = allow_current_frame;
x_dnd_movement_frame = NULL;
+ x_dnd_wheel_frame = NULL;
x_dnd_init_type_lists = false;
x_dnd_need_send_drop = false;
#ifdef HAVE_XKB
}
}
+ if (x_dnd_wheel_frame
+ && (x_dnd_in_progress || x_dnd_waiting_for_finish))
+ {
+ XSETFRAME (frame_object, x_dnd_wheel_frame);
+ XSETINT (x, x_dnd_wheel_x);
+ XSETINT (y, x_dnd_wheel_y);
+ x_dnd_wheel_frame = NULL;
+
+ if (!NILP (Vx_dnd_wheel_function)
+ && FRAME_LIVE_P (XFRAME (frame_object))
+ && !FRAME_TOOLTIP_P (XFRAME (frame_object))
+ && x_dnd_movement_x >= 0
+ && x_dnd_movement_y >= 0
+ && x_dnd_frame
+ && (XFRAME (frame_object) != x_dnd_frame
+ || x_dnd_allow_current_frame))
+ {
+ x_dnd_old_window_attrs = root_window_attrs;
+ x_dnd_unwind_flag = true;
+
+ ref = SPECPDL_INDEX ();
+ record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+ call4 (Vx_dnd_wheel_function,
+ Fposn_at_x_y (x, y, frame_object, Qnil),
+ make_fixnum (x_dnd_wheel_button),
+ make_uint (x_dnd_wheel_state),
+ make_uint (x_dnd_wheel_time));
+ x_dnd_unwind_flag = false;
+ unbind_to (ref, Qnil);
+
+ /* Redisplay this way to preserve the echo area.
+ Otherwise, the contents will abruptly disappear
+ when the mouse moves over a frame. */
+ redisplay_preserve_echo_area (33);
+ }
+ }
+
if (hold_quit.kind != NO_EVENT)
{
x_dnd_process_quit (f, hold_quit.timestamp);
if (x_dnd_movement_frame)
x_dnd_movement_frame = NULL;
+ if (x_dnd_wheel_frame)
+ x_dnd_wheel_frame = NULL;
+
if (hold_quit.kind != NO_EVENT)
EVENT_INIT (hold_quit);
}
current_hold_quit = NULL;
#endif
x_dnd_movement_frame = NULL;
+ x_dnd_wheel_frame = NULL;
x_restore_events_after_dnd (f, &root_window_attrs);
if (x_dnd_return_frame == 3
dpyinfo->grabbed &= ~(1 << event->xbutton.button);
if (event->xbutton.type == ButtonPress
- && x_dnd_last_seen_window != None
- && x_dnd_last_protocol_version != -1)
+ && x_dnd_last_seen_window != None)
{
- x_dnd_send_position (x_dnd_frame,
- x_dnd_last_seen_window,
- x_dnd_last_protocol_version,
- event->xbutton.x_root,
- event->xbutton.y_root,
- x_dnd_selection_timestamp,
- x_dnd_wanted_action,
- event->xbutton.button,
- event->xbutton.state);
+ if (x_dnd_last_window_is_frame)
+ x_dnd_note_self_wheel (dpyinfo,
+ x_dnd_last_seen_window,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ event->xbutton.button,
+ event->xbutton.state,
+ event->xbutton.time);
+ else if (x_dnd_last_protocol_version != -1)
+ x_dnd_send_position (x_dnd_frame,
+ x_dnd_last_seen_window,
+ x_dnd_last_protocol_version,
+ event->xbutton.x_root,
+ event->xbutton.y_root,
+ x_dnd_selection_timestamp,
+ x_dnd_wanted_action,
+ event->xbutton.button,
+ event->xbutton.state);
goto OTHER;
}
#endif
if (xev->evtype == XI_ButtonPress
- && x_dnd_last_seen_window != None
- && x_dnd_last_protocol_version != -1)
+ && x_dnd_last_seen_window != None)
{
dnd_state = xi_convert_event_state (xev);
- x_dnd_send_position (x_dnd_frame, x_dnd_last_seen_window,
- x_dnd_last_protocol_version, xev->root_x,
- xev->root_y, x_dnd_selection_timestamp,
- x_dnd_wanted_action, xev->detail, dnd_state);
+ if (x_dnd_last_window_is_frame)
+ x_dnd_note_self_wheel (dpyinfo,
+ x_dnd_last_seen_window,
+ xev->root_x, xev->root_y,
+ xev->detail, dnd_state,
+ xev->time);
+ else
+ x_dnd_send_position (x_dnd_frame, x_dnd_last_seen_window,
+ x_dnd_last_protocol_version, xev->root_x,
+ xev->root_y, x_dnd_selection_timestamp,
+ x_dnd_wanted_action, xev->detail, dnd_state);
goto XI_OTHER;
}
x_dnd_return_frame_object = NULL;
x_dnd_movement_frame = NULL;
+ x_dnd_wheel_frame = NULL;
x_dnd_frame = NULL;
}
x_dnd_return_frame_object = NULL;
x_dnd_movement_frame = NULL;
+ x_dnd_wheel_frame = NULL;
x_dnd_frame = NULL;
}
mark_object (val);
}
+ if (x_dnd_wheel_frame)
+ {
+ XSETFRAME (val, x_dnd_wheel_frame);
+ mark_object (val);
+ }
+
#if defined HAVE_XINPUT2 || defined USE_TOOLKIT_SCROLL_BARS \
|| defined HAVE_XRANDR || defined USE_GTK
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
mouse position list. */);
Vx_dnd_movement_function = Qnil;
+ DEFVAR_LISP ("x-dnd-wheel-function", Vx_dnd_wheel_function,
+ doc: /* Function called upon wheel movement on a frame during drag-and-drop.
+It should either be nil, or accept four arguments POSITION, BUTTON,
+STATE and TIME, where POSITION is a mouse position list describing
+where the wheel moved, BUTTON is the wheel button that was pressed,
+STATE is the X modifier state at the time of the wheel movement, and
+TIME is the X server time at which the wheel moved. */);
+ Vx_dnd_wheel_function = Qnil;
+
DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function,
doc: /* Function called when trying to drop on an unsupported window.
This function is called whenever the user tries to drop something on a