Implement sending drag start message to client
This commit is contained in:
parent
cf52a8289c
commit
0584cbfadc
8 changed files with 60 additions and 15 deletions
|
|
@ -257,7 +257,7 @@ image by sending::
|
|||
|
||||
Where ``idx`` is now a zero based index with zero being the first image and so on.
|
||||
|
||||
Once the terminal program has present all data and images for the drag
|
||||
Once the terminal program has sent all data and images for the drag
|
||||
operation, it indicates the drag should be started by sending ``t=P:x=-1``. At
|
||||
this time if the user has already cancelled the drag or the terminal determines
|
||||
the drag operation is not allowed, it must respond with ``t=R ; EPERM``. If any
|
||||
|
|
|
|||
|
|
@ -854,3 +854,8 @@ drop_left_child(Window *w) {
|
|||
queue_payload_to_child(w->id, w->drop.client_id, &w->drop.pending, buf, header_size, NULL, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
drag_free_offer(Window *w) {
|
||||
(void)w;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,3 +21,6 @@ size_t drop_update_mimes(Window *w, const char **allowed_mimes, size_t allowed_m
|
|||
void drop_dispatch_data(Window *w, const char *mime_type, const char *data, ssize_t sz);
|
||||
void drop_finish(Window *w);
|
||||
void dnd_set_test_write_func(PyObject *func);
|
||||
|
||||
|
||||
void drag_free_offer(Window *w);
|
||||
|
|
|
|||
|
|
@ -1056,6 +1056,12 @@ free_drag_source(void) {
|
|||
zero_at_ptr(&ds);
|
||||
}
|
||||
|
||||
void
|
||||
cancel_current_drag_source(void) {
|
||||
if (!ds.from_os_window) return; OSWindow *w = os_window_for_id(ds.from_os_window); if (!w || !w->handle) return;
|
||||
glfwStartDrag(w->handle, NULL, 0, NULL, -3, false);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_source_callback(GLFWwindow *window UNUSED, GLFWDragEvent *ev) {
|
||||
#define finish \
|
||||
|
|
@ -3115,6 +3121,8 @@ change_drag_thumbnail(PyObject *self UNUSED, PyObject *args) {
|
|||
if (!get_thumbnail(global_state.drag_source.thumbnails, &thumbnail, idx)) return NULL;
|
||||
global_state.drag_source.thumbnail_idx = idx;
|
||||
} else global_state.drag_source.thumbnail_idx = -1;
|
||||
global_state.drag_source.from_os_window = w->id;
|
||||
global_state.drag_source.from_window = 0;
|
||||
errno = glfwStartDrag(w->handle, NULL, 0, thumbnail.pixels ? &thumbnail : NULL, -2, false);
|
||||
if (errno != 0) {
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
|
|
|
|||
|
|
@ -643,6 +643,10 @@ handle_scrollbar_mouse(Window *w, int button, MouseAction action, int modifiers
|
|||
}
|
||||
// }}}
|
||||
|
||||
static double
|
||||
distance(double x1, double y1, double x2, double y2) {
|
||||
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||
}
|
||||
|
||||
HANDLER(handle_move_event) {
|
||||
modifiers &= ~GLFW_LOCK_MASK;
|
||||
|
|
@ -672,11 +676,13 @@ HANDLER(handle_move_event) {
|
|||
int sz = encode_mouse_button(w, button, button >=0 ? DRAG : MOVE, modifiers);
|
||||
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, ESC_CSI, mouse_event_buf); }
|
||||
}
|
||||
}
|
||||
|
||||
static double
|
||||
distance(double x1, double y1, double x2, double y2) {
|
||||
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
||||
if (w->drag_source.can_offer && w->drag_source.initial_left_press.at && distance(w->mouse_pos.global_x, w->mouse_pos.global_y, w->drag_source.initial_left_press.x, w->drag_source.initial_left_press.y) > OPT(drag_threshold)) {
|
||||
zero_at_ptr(&w->drag_source.initial_left_press);
|
||||
snprintf(mouse_event_buf, sizeof(mouse_event_buf), "%d;t=o:x=%d:y=%d:X=%d:Y=%d",
|
||||
DND_CODE, w->mouse_pos.cell_x, w->mouse_pos.cell_y, (int)w->mouse_pos.global_x, (int)w->mouse_pos.global_y);
|
||||
write_escape_code_to_child(screen, ESC_OSC, mouse_event_buf);
|
||||
debug("Sent drag start event to child\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -870,6 +876,15 @@ HANDLER(handle_button_event) {
|
|||
|
||||
bool a, b;
|
||||
if (!set_mouse_position(w, &a, &b)) return;
|
||||
if (button == GLFW_MOUSE_BUTTON_LEFT) {
|
||||
if (is_release) {
|
||||
zero_at_ptr(&w->drag_source.initial_left_press);
|
||||
} else if (w->drag_source.can_offer) {
|
||||
w->drag_source.initial_left_press.x = w->mouse_pos.global_x;
|
||||
w->drag_source.initial_left_press.y = w->mouse_pos.global_x;
|
||||
w->drag_source.initial_left_press.at = monotonic();
|
||||
}
|
||||
}
|
||||
id_type wid = w->id;
|
||||
if (!dispatch_mouse_event(w, button, is_release ? -1 : 1, modifiers, screen->modes.mouse_tracking_mode != 0)) {
|
||||
if (!suppress_child_forwarding && screen->modes.mouse_tracking_mode != 0) {
|
||||
|
|
|
|||
|
|
@ -884,7 +884,7 @@
|
|||
'''
|
||||
)
|
||||
|
||||
opt('drag_threshold', '5', option_type='positive_int', long_text='''
|
||||
opt('drag_threshold', '5', option_type='positive_int', ctype='int', long_text='''
|
||||
The threshold distance the mouse must move to start a drag and drop. Dragging
|
||||
works for tabs and windows. You can drag tabs to re-order them, detach
|
||||
them into new OS Windows or move them to another OS Window. Similarly,
|
||||
|
|
|
|||
|
|
@ -1530,16 +1530,23 @@ screen_handle_dnd_command(Screen *self, const DnDCommand *cmd, const uint8_t *pa
|
|||
}
|
||||
} break;
|
||||
case 's': {
|
||||
if (cmd->payload_sz)
|
||||
drop_request_uri_data(w, (const char*)payload, cmd->payload_sz);
|
||||
else
|
||||
drop_send_einval(w);
|
||||
if (cmd->payload_sz) drop_request_uri_data(w, (const char*)payload, cmd->payload_sz);
|
||||
else drop_send_einval(w);
|
||||
} break;
|
||||
case 'd': {
|
||||
if (cmd->cell_x > 0)
|
||||
drop_handle_dir_request(w, (uint32_t)cmd->cell_x, cmd->cell_y);
|
||||
else
|
||||
drop_send_einval(w);
|
||||
if (cmd->cell_x > 0) drop_handle_dir_request(w, (uint32_t)cmd->cell_x, cmd->cell_y);
|
||||
else drop_send_einval(w);
|
||||
} break;
|
||||
case 'o': {
|
||||
if (cmd->payload_sz > 0) ;
|
||||
else w->drag_source.can_offer = true;
|
||||
} break;
|
||||
case 'O': {
|
||||
drag_free_offer(w);
|
||||
w->drag_source.can_offer = false;
|
||||
if (global_state.drag_source.is_active && global_state.drag_source.from_window == w->id) {
|
||||
cancel_current_drag_source();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,6 +153,7 @@ typedef struct Options {
|
|||
double momentum_scroll;
|
||||
double window_drag_tolerance;
|
||||
bool generate_256_palette;
|
||||
int drag_threshold;
|
||||
} Options;
|
||||
|
||||
typedef struct WindowLogoRenderData {
|
||||
|
|
@ -284,6 +285,10 @@ typedef struct Window {
|
|||
monotonic_t last_file_send_at; /* time of last successful file chunk write */
|
||||
id_type file_send_timer; /* pending file-send retry timer, 0 = none */
|
||||
} drop;
|
||||
struct {
|
||||
bool can_offer;
|
||||
struct { double x, y; monotonic_t at; } initial_left_press;
|
||||
} drag_source;
|
||||
} Window;
|
||||
|
||||
typedef struct BorderRect {
|
||||
|
|
@ -441,6 +446,7 @@ typedef struct GlobalState {
|
|||
|
||||
struct {
|
||||
bool is_active, was_dropped, was_canceled, needs_toplevel_on_wayland;
|
||||
id_type from_window, from_os_window;
|
||||
char *accepted_mime_type;
|
||||
int action, thumbnail_idx;
|
||||
PyObject *drag_data, *thumbnails;
|
||||
|
|
@ -571,3 +577,4 @@ bool current_framebuffer_is_ok(void);
|
|||
void request_drop_status_update(OSWindow *osw);
|
||||
void register_mimes_for_drop(OSWindow *w, const char **mimes, size_t sz);
|
||||
void request_drop_data(OSWindow *w, id_type wid, const char* mime);
|
||||
void cancel_current_drag_source(void);
|
||||
|
|
|
|||
Loading…
Reference in a new issue