committed by
Kovid Goyal
parent
6744183027
commit
9b35c1b535
@@ -1343,6 +1343,13 @@ is_modifier_pressed(NSUInteger flags, NSUInteger target_mask, NSUInteger other_m
|
||||
_glfwInputScroll(window, &ev);
|
||||
}
|
||||
|
||||
// Return YES to receive periodic dragging updates even when the mouse hasn't moved.
|
||||
// This allows the application to update acceptance status asynchronously.
|
||||
- (BOOL)wantsPeriodicDraggingUpdates
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
const NSRect contentRect = [window->ns.view frame];
|
||||
@@ -1414,9 +1421,12 @@ is_modifier_pressed(NSUInteger flags, NSUInteger target_mask, NSUInteger other_m
|
||||
double xpos = pos.x;
|
||||
double ypos = contentRect.size.height - pos.y;
|
||||
|
||||
// Call drag move callback
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
return NSDragOperationGeneric;
|
||||
// Call drag move callback and return acceptance status
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
|
||||
if (accepted)
|
||||
return NSDragOperationGeneric;
|
||||
return NSDragOperationNone;
|
||||
}
|
||||
|
||||
- (void)draggingExited:(id <NSDraggingInfo>)sender
|
||||
@@ -3797,3 +3807,9 @@ int _glfwPlatformStartDrag(_GLFWwindow* window,
|
||||
}
|
||||
}
|
||||
|
||||
void _glfwPlatformSetDragAcceptance(_GLFWwindow* window UNUSED, bool accepted UNUSED) {
|
||||
// No-op on macOS: The system uses periodic dragging updates via
|
||||
// wantsPeriodicDraggingUpdates returning YES. The application should
|
||||
// return the updated acceptance status from the drag callback instead.
|
||||
}
|
||||
|
||||
|
||||
41
glfw/glfw3.h
vendored
41
glfw/glfw3.h
vendored
@@ -1852,11 +1852,14 @@ typedef struct GLFWdragitem {
|
||||
* duration of the callback; if you need to store them, make copies.
|
||||
* @param[in] mime_count Number of MIME types in the array. Zero if no MIME types
|
||||
* are available or for non-enter events.
|
||||
* @return For @ref GLFW_DRAG_ENTER events, return non-zero to accept the drag
|
||||
* or zero to reject it. Return value is ignored for other event types.
|
||||
* @return For @ref GLFW_DRAG_ENTER and @ref GLFW_DRAG_MOVE events, return non-zero
|
||||
* to accept the drag or zero to reject it. This allows the application to
|
||||
* dynamically accept or reject the drag based on the current position.
|
||||
* Return value is ignored for @ref GLFW_DRAG_LEAVE events.
|
||||
*
|
||||
* @sa @ref drag_events
|
||||
* @sa @ref glfwSetDragCallback
|
||||
* @sa @ref glfwSetDragAcceptance
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
*
|
||||
@@ -5067,6 +5070,40 @@ GLFWAPI GLFWdragfun glfwSetDragCallback(GLFWwindow* window, GLFWdragfun callback
|
||||
*/
|
||||
GLFWAPI int glfwStartDrag(GLFWwindow* window, const GLFWdragitem* items, int item_count, const GLFWimage* thumbnail, GLFWDragOperationType operation);
|
||||
|
||||
/*! @brief Sets the acceptance status of the current drag operation.
|
||||
*
|
||||
* This function allows the application to asynchronously change whether
|
||||
* the current drag operation is accepted or rejected. This is useful when
|
||||
* the acceptance decision cannot be made synchronously in the drag callback,
|
||||
* for example when waiting for user input or network responses.
|
||||
*
|
||||
* The acceptance status affects the visual feedback shown to the user
|
||||
* (e.g., cursor changes) and whether a drop will be accepted if the user
|
||||
* releases the mouse button.
|
||||
*
|
||||
* @param[in] window The window receiving the drag operation.
|
||||
* @param[in] accepted `true` to accept the drag, `false` to reject it.
|
||||
*
|
||||
* @errors Possible errors include @ref GLFW_NOT_INITIALIZED.
|
||||
*
|
||||
* @remark This function has no effect if there is no active drag operation
|
||||
* over the specified window.
|
||||
*
|
||||
* @remark On macOS, this function is a no-op as the system uses periodic
|
||||
* dragging updates. The application should return the updated acceptance
|
||||
* status from the drag callback instead.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
* @sa @ref drag_events
|
||||
* @sa @ref glfwSetDragCallback
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI void glfwSetDragAcceptance(GLFWwindow* window, bool accepted);
|
||||
|
||||
/*! @brief Returns whether the specified joystick is present.
|
||||
*
|
||||
* This function returns whether the specified joystick is present.
|
||||
|
||||
9
glfw/input.c
vendored
9
glfw/input.c
vendored
@@ -1141,6 +1141,15 @@ GLFWAPI int glfwStartDrag(GLFWwindow* handle, const GLFWdragitem* items, int ite
|
||||
return _glfwPlatformStartDrag(window, items, item_count, thumbnail, operation);
|
||||
}
|
||||
|
||||
GLFWAPI void glfwSetDragAcceptance(GLFWwindow* handle, bool accepted)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformSetDragAcceptance(window, accepted);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwJoystickPresent(int jid)
|
||||
{
|
||||
_GLFWjoystick* js;
|
||||
|
||||
1
glfw/internal.h
vendored
1
glfw/internal.h
vendored
@@ -768,6 +768,7 @@ void _glfwPlatformUpdateIMEState(_GLFWwindow *w, const GLFWIMEUpdateEvent *ev);
|
||||
void _glfwPlatformChangeCursorTheme(void);
|
||||
|
||||
int _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWdragitem* items, int item_count, const GLFWimage* thumbnail, GLFWDragOperationType operation);
|
||||
void _glfwPlatformSetDragAcceptance(_GLFWwindow* window, bool accepted);
|
||||
|
||||
void _glfwPlatformPollEvents(void);
|
||||
void _glfwPlatformWaitEvents(void);
|
||||
|
||||
5
glfw/null_window.c
vendored
5
glfw/null_window.c
vendored
@@ -539,6 +539,11 @@ int _glfwPlatformStartDrag(_GLFWwindow* window UNUSED,
|
||||
return false;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetDragAcceptance(_GLFWwindow* window UNUSED, bool accepted UNUSED)
|
||||
{
|
||||
// No-op for null platform
|
||||
}
|
||||
|
||||
void _glfwPlatformSetClipboardString(const char* string)
|
||||
{
|
||||
char* copy = _glfw_strdup(string);
|
||||
|
||||
2
glfw/wl_platform.h
vendored
2
glfw/wl_platform.h
vendored
@@ -317,6 +317,8 @@ typedef struct _GLFWWaylandDataOffer
|
||||
struct wl_surface *surface;
|
||||
const char **mimes;
|
||||
size_t mimes_capacity, mimes_count;
|
||||
bool drag_accepted;
|
||||
uint32_t serial;
|
||||
} _GLFWWaylandDataOffer;
|
||||
|
||||
// Wayland-specific global data
|
||||
|
||||
48
glfw/wl_window.c
vendored
48
glfw/wl_window.c
vendored
@@ -2492,6 +2492,8 @@ static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device
|
||||
if (d->id == id) {
|
||||
d->offer_type = DRAG_AND_DROP;
|
||||
d->surface = surface;
|
||||
d->serial = serial;
|
||||
d->drag_accepted = false;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
int format_priority = 0;
|
||||
while (window)
|
||||
@@ -2504,6 +2506,7 @@ static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device
|
||||
|
||||
// If accepted, check MIME type priorities
|
||||
if (accepted) {
|
||||
d->drag_accepted = true;
|
||||
for (size_t j = 0; j < d->mimes_count; j++) {
|
||||
int prio = _glfwInputDrop(window, d->mimes[j], NULL, 0);
|
||||
if (prio > format_priority) {
|
||||
@@ -2569,16 +2572,43 @@ static void drop(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to update drag acceptance status and notify compositor
|
||||
static void update_drag_acceptance(_GLFWWaylandDataOffer *d, _GLFWwindow* window, bool accepted) {
|
||||
if (accepted != d->drag_accepted) {
|
||||
d->drag_accepted = accepted;
|
||||
// If acceptance changed, update MIME selection and notify compositor
|
||||
if (accepted) {
|
||||
// Re-select best MIME type if now accepting
|
||||
int format_priority = 0;
|
||||
d->mime_for_drop = NULL;
|
||||
for (size_t j = 0; j < d->mimes_count; j++) {
|
||||
int prio = _glfwInputDrop(window, d->mimes[j], NULL, 0);
|
||||
if (prio > format_priority) {
|
||||
format_priority = prio;
|
||||
d->mime_for_drop = d->mimes[j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
d->mime_for_drop = NULL;
|
||||
}
|
||||
wl_data_offer_accept(d->id, d->serial, d->mime_for_drop);
|
||||
}
|
||||
}
|
||||
|
||||
static void motion(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, uint32_t time UNUSED, wl_fixed_t x, wl_fixed_t y) {
|
||||
// Find the current drag offer and send motion events
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||
_GLFWWaylandDataOffer *d = &_glfw.wl.dataOffers[i];
|
||||
if (d->offer_type == DRAG_AND_DROP) {
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
while (window) {
|
||||
if (window->wl.surface == _glfw.wl.dataOffers[i].surface) {
|
||||
if (window->wl.surface == d->surface) {
|
||||
double xpos = wl_fixed_to_double(x);
|
||||
double ypos = wl_fixed_to_double(y);
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
|
||||
// Update acceptance status based on callback return value
|
||||
update_drag_acceptance(d, window, accepted);
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
@@ -3157,3 +3187,15 @@ _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWdragitem* items, int item_
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
_glfwPlatformSetDragAcceptance(_GLFWwindow* window, bool accepted) {
|
||||
// Find the active drag offer for this window and update its acceptance status
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
_GLFWWaylandDataOffer *d = &_glfw.wl.dataOffers[i];
|
||||
if (d->offer_type == DRAG_AND_DROP && window->wl.surface == d->surface) {
|
||||
update_drag_acceptance(d, window, accepted);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1
glfw/x11_platform.h
vendored
1
glfw/x11_platform.h
vendored
@@ -385,6 +385,7 @@ typedef struct _GLFWlibraryX11
|
||||
char format[128];
|
||||
int format_priority;
|
||||
Window target_window; // For drag events: the window being dragged over
|
||||
bool drag_accepted; // Whether the current drag is accepted
|
||||
} xdnd;
|
||||
|
||||
// Drag source state
|
||||
|
||||
40
glfw/x11_window.c
vendored
40
glfw/x11_window.c
vendored
@@ -1836,6 +1836,7 @@ static void processEvent(XEvent *event)
|
||||
_glfw.x11.xdnd.target_window = window->x11.handle;
|
||||
memset(_glfw.x11.xdnd.format, 0, sizeof(_glfw.x11.xdnd.format));
|
||||
_glfw.x11.xdnd.format_priority = 0;
|
||||
_glfw.x11.xdnd.drag_accepted = false;
|
||||
|
||||
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
|
||||
return;
|
||||
@@ -1869,6 +1870,7 @@ static void processEvent(XEvent *event)
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, 0, 0, (const char**)atom_names, valid_mime_count);
|
||||
|
||||
if (atom_names && accepted) {
|
||||
_glfw.x11.xdnd.drag_accepted = true;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (atom_names[i]) {
|
||||
@@ -1957,8 +1959,9 @@ static void processEvent(XEvent *event)
|
||||
|
||||
_glfwInputCursorPos(window, xpos, ypos);
|
||||
|
||||
// Call the drag move callback
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
// Call the drag move callback and update acceptance status
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
_glfw.x11.xdnd.drag_accepted = accepted;
|
||||
|
||||
XEvent reply = { ClientMessage };
|
||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||
@@ -1968,7 +1971,7 @@ static void processEvent(XEvent *event)
|
||||
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
|
||||
reply.xclient.data.l[3] = 0;
|
||||
|
||||
if (_glfw.x11.xdnd.format_priority > 0)
|
||||
if (_glfw.x11.xdnd.format_priority > 0 && _glfw.x11.xdnd.drag_accepted)
|
||||
{
|
||||
// Reply that we are ready to copy the dragged data
|
||||
reply.xclient.data.l[1] = 1; // Accept with no rectangle
|
||||
@@ -3758,3 +3761,34 @@ int _glfwPlatformStartDrag(_GLFWwindow* window,
|
||||
return true;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetDragAcceptance(_GLFWwindow* window, bool accepted) {
|
||||
// Check if there's an active drag over this window
|
||||
if (_glfw.x11.xdnd.source == None ||
|
||||
_glfw.x11.xdnd.target_window != window->x11.handle) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update acceptance status
|
||||
_glfw.x11.xdnd.drag_accepted = accepted;
|
||||
|
||||
// Send an XdndStatus message to update the drag source
|
||||
XEvent reply = { ClientMessage };
|
||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||
reply.xclient.message_type = _glfw.x11.XdndStatus;
|
||||
reply.xclient.format = 32;
|
||||
reply.xclient.data.l[0] = window->x11.handle;
|
||||
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
|
||||
reply.xclient.data.l[3] = 0;
|
||||
|
||||
if (_glfw.x11.xdnd.format_priority > 0 && accepted) {
|
||||
// Reply that we are ready to copy the dragged data
|
||||
reply.xclient.data.l[1] = 1; // Accept with no rectangle
|
||||
if (_glfw.x11.xdnd.version >= 2)
|
||||
reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy;
|
||||
}
|
||||
|
||||
XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
|
||||
False, NoEventMask, &reply);
|
||||
XFlush(_glfw.x11.display);
|
||||
}
|
||||
|
||||
|
||||
16
kitty/glfw.c
16
kitty/glfw.c
@@ -653,12 +653,18 @@ static int
|
||||
drag_callback(GLFWwindow *w, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int mime_count) {
|
||||
(void)xpos; (void)ypos;
|
||||
if (!set_callback_window(w)) return 0;
|
||||
if (event == GLFW_DRAG_ENTER) {
|
||||
for (int i = 0; i < mime_count; i++) {
|
||||
if (is_droppable_mime(mime_types[i])) return 1;
|
||||
}
|
||||
int ret = 0;
|
||||
switch (event) {
|
||||
case GLFW_DRAG_ENTER:
|
||||
for (int i = 0; i < mime_count; i++) {
|
||||
if (is_droppable_mime(mime_types[i])) { ret = 1; break; }
|
||||
}
|
||||
break;
|
||||
case GLFW_DRAG_MOVE: ret = 1;
|
||||
case GLFW_DRAG_LEAVE: break;
|
||||
}
|
||||
return 0;
|
||||
global_state.callback_os_window = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
Reference in New Issue
Block a user