mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-05-13 16:37:27 +00:00
parent
c0bb8ae2a0
commit
fac4420804
13 changed files with 365 additions and 154 deletions
5
glfw/cocoa_platform.h
vendored
5
glfw/cocoa_platform.h
vendored
|
|
@ -170,6 +170,11 @@ typedef struct _GLFWwindowNS
|
|||
|
||||
// Current drag operation type for NSDraggingSource
|
||||
GLFWDragOperationType dragOperationType;
|
||||
|
||||
// Cached MIME types from drag enter (for move events)
|
||||
const char** dragMimes;
|
||||
int dragMimeCount; // Current count of MIME types (may be reduced by callback)
|
||||
int dragMimeArraySize; // Original array size for proper cleanup
|
||||
} _GLFWwindowNS;
|
||||
|
||||
// Cocoa-specific global data
|
||||
|
|
|
|||
|
|
@ -1350,6 +1350,33 @@ is_modifier_pressed(NSUInteger flags, NSUInteger target_mask, NSUInteger other_m
|
|||
return YES;
|
||||
}
|
||||
|
||||
// Helper function to free dragged MIME types array
|
||||
static void freeDragMimes(_GLFWwindow* window) {
|
||||
if (window->ns.dragMimes) {
|
||||
// Free based on array size, not count (callback may have reduced count)
|
||||
for (int i = 0; i < window->ns.dragMimeArraySize; i++) {
|
||||
if (window->ns.dragMimes[i])
|
||||
free((char*)window->ns.dragMimes[i]);
|
||||
}
|
||||
free(window->ns.dragMimes);
|
||||
window->ns.dragMimes = NULL;
|
||||
window->ns.dragMimeCount = 0;
|
||||
window->ns.dragMimeArraySize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to free entries that were filtered out by callback
|
||||
static void freeFilteredDragMimes(_GLFWwindow* window, int old_count, int new_count) {
|
||||
if (window->ns.dragMimes && new_count < old_count) {
|
||||
for (int i = new_count; i < old_count; i++) {
|
||||
if (window->ns.dragMimes[i]) {
|
||||
free((char*)window->ns.dragMimes[i]);
|
||||
window->ns.dragMimes[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||
{
|
||||
const NSRect contentRect = [window->ns.view frame];
|
||||
|
|
@ -1366,22 +1393,25 @@ is_modifier_pressed(NSUInteger flags, NSUInteger target_mask, NSUInteger other_m
|
|||
max_types += [item.types count];
|
||||
}
|
||||
|
||||
// Free any previously cached MIME types
|
||||
freeDragMimes(window);
|
||||
|
||||
// Pre-allocate C array for MIME types
|
||||
const char** mime_array = (const char**)calloc(max_types, sizeof(const char*));
|
||||
if (!mime_array) {
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, xpos, ypos, NULL, 0);
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, xpos, ypos, NULL, NULL);
|
||||
return accepted ? NSDragOperationGeneric : NSDragOperationNone;
|
||||
}
|
||||
|
||||
int mime_count = 0;
|
||||
|
||||
// Check for common types first
|
||||
// Check for common types first (use _glfw_strdup since we need to own the strings)
|
||||
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
||||
if ([pasteboard canReadObjectForClasses:@[[NSURL class]] options:options]) {
|
||||
mime_array[mime_count++] = "text/uri-list";
|
||||
mime_array[mime_count++] = _glfw_strdup("text/uri-list");
|
||||
}
|
||||
if ([pasteboard canReadObjectForClasses:@[[NSString class]] options:nil]) {
|
||||
mime_array[mime_count++] = "text/plain";
|
||||
mime_array[mime_count++] = _glfw_strdup("text/plain");
|
||||
}
|
||||
|
||||
// Get additional types from pasteboard items
|
||||
|
|
@ -1398,16 +1428,27 @@ is_modifier_pressed(NSUInteger flags, NSUInteger target_mask, NSUInteger other_m
|
|||
}
|
||||
}
|
||||
if (!duplicate) {
|
||||
mime_array[mime_count++] = mime;
|
||||
// Use _glfw_strdup since uti_to_mime returns strings from autoreleased objects
|
||||
mime_array[mime_count++] = _glfw_strdup(mime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call drag enter callback with MIME types
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, xpos, ypos, mime_array, mime_count);
|
||||
// Store MIME types for later use in move events
|
||||
window->ns.dragMimes = mime_array;
|
||||
window->ns.dragMimeCount = mime_count;
|
||||
window->ns.dragMimeArraySize = mime_count;
|
||||
|
||||
free(mime_array);
|
||||
// Call drag enter callback with writable MIME types array
|
||||
int old_count = mime_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, xpos, ypos, mime_array, &mime_count);
|
||||
|
||||
// Free any entries that were filtered out by the callback
|
||||
freeFilteredDragMimes(window, old_count, mime_count);
|
||||
|
||||
// Update cached mime count with callback result
|
||||
window->ns.dragMimeCount = mime_count;
|
||||
|
||||
if (accepted)
|
||||
return NSDragOperationGeneric;
|
||||
|
|
@ -1421,8 +1462,16 @@ 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 and return acceptance status
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
// Call drag move callback with cached MIME types
|
||||
int old_count = window->ns.dragMimeCount;
|
||||
int mime_count = old_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, window->ns.dragMimes, &mime_count);
|
||||
|
||||
// Free any entries that were filtered out by the callback
|
||||
freeFilteredDragMimes(window, old_count, mime_count);
|
||||
|
||||
// Update cached mime count with callback result
|
||||
window->ns.dragMimeCount = mime_count;
|
||||
|
||||
if (accepted)
|
||||
return NSDragOperationGeneric;
|
||||
|
|
@ -1433,7 +1482,10 @@ is_modifier_pressed(NSUInteger flags, NSUInteger target_mask, NSUInteger other_m
|
|||
{
|
||||
(void)sender;
|
||||
// Call drag leave callback
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_LEAVE, 0, 0, NULL, 0);
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_LEAVE, 0, 0, NULL, NULL);
|
||||
|
||||
// Free cached MIME types
|
||||
freeDragMimes(window);
|
||||
}
|
||||
|
||||
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
||||
|
|
@ -3807,9 +3859,16 @@ 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.
|
||||
void _glfwPlatformUpdateDragState(_GLFWwindow* window) {
|
||||
// Call the drag callback with STATUS_UPDATE to get updated acceptance and MIME list
|
||||
// Position values are not valid for this event type
|
||||
if (window->ns.dragMimes) {
|
||||
int old_count = window->ns.dragMimeCount;
|
||||
int mime_count = old_count;
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_STATUS_UPDATE, 0, 0, window->ns.dragMimes, &mime_count);
|
||||
// Free any entries that were filtered out by the callback
|
||||
freeFilteredDragMimes(window, old_count, mime_count);
|
||||
window->ns.dragMimeCount = mime_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
57
glfw/glfw3.h
vendored
57
glfw/glfw3.h
vendored
|
|
@ -1761,17 +1761,15 @@ typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
|||
* This is the function pointer type for drop callbacks. A drop
|
||||
* callback function has the following signature:
|
||||
* @code
|
||||
* int function_name(GLFWwindow* window, const char* mime, const char* text)
|
||||
* void function_name(GLFWwindow* window, const char* mime, const char* data, size_t sz)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] window The window that received the event.
|
||||
* @param[in] mime The UTF-8 encoded drop mime-type
|
||||
* @param[in] data The dropped data or NULL for drag enter events
|
||||
* @param[in] data The dropped data.
|
||||
* @param[in] sz The size of the dropped data
|
||||
* @return For drag events should return the priority for the specified mime type. A priority of zero
|
||||
* or lower means the mime type is not accepted. Highest priority will be the finally accepted mime-type.
|
||||
*
|
||||
* @pointer_lifetime The text is valid until the
|
||||
* @pointer_lifetime The data is valid until the
|
||||
* callback function returns.
|
||||
*
|
||||
* @sa @ref path_drop
|
||||
|
|
@ -1781,7 +1779,7 @@ typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
|||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef int (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||
typedef void (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||
|
||||
/*! @brief Drag event types.
|
||||
*
|
||||
|
|
@ -1795,7 +1793,9 @@ typedef enum {
|
|||
/*! The drag operation moved within the window. */
|
||||
GLFW_DRAG_MOVE = 2,
|
||||
/*! The drag operation left the window. */
|
||||
GLFW_DRAG_LEAVE = 3
|
||||
GLFW_DRAG_LEAVE = 3,
|
||||
/*! Async status update request (xpos/ypos are invalid). */
|
||||
GLFW_DRAG_STATUS_UPDATE = 4
|
||||
} GLFWDragEventType;
|
||||
|
||||
/*! @brief Drag operation types.
|
||||
|
|
@ -1838,7 +1838,7 @@ typedef struct GLFWdragitem {
|
|||
* This is the function pointer type for drag event callbacks. A drag event
|
||||
* callback function has the following signature:
|
||||
* @code
|
||||
* int function_name(GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int mime_count)
|
||||
* int function_name(GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int* mime_count)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] window The window that received the drag event.
|
||||
|
|
@ -1846,12 +1846,16 @@ typedef struct GLFWdragitem {
|
|||
* or @ref GLFW_DRAG_LEAVE.
|
||||
* @param[in] xpos The x-coordinate of the drag position in window coordinates.
|
||||
* @param[in] ypos The y-coordinate of the drag position in window coordinates.
|
||||
* @param[in] mime_types Array of MIME type strings available from the drag source.
|
||||
* For @ref GLFW_DRAG_ENTER events this contains all available MIME types.
|
||||
* For other events this may be `NULL`. The strings are only valid for the
|
||||
* 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.
|
||||
* @param[in,out] mime_types A writable array of MIME type strings available from the drag source.
|
||||
* For @ref GLFW_DRAG_ENTER and @ref GLFW_DRAG_MOVE events this is non-NULL and contains all
|
||||
* available MIME types. The callback is responsible for sorting this list by priority and
|
||||
* keeping only the MIME types it wants to accept. The first MIME type in the sorted list
|
||||
* will be used for the drop operation. The strings are only valid for the duration of the
|
||||
* callback; if you need to store them, make copies. For @ref GLFW_DRAG_LEAVE events this
|
||||
* is `NULL`.
|
||||
* @param[in,out] mime_count Pointer to the number of MIME types in the array. The callback
|
||||
* should update this to reflect the new count after sorting and filtering. For
|
||||
* @ref GLFW_DRAG_LEAVE events this is `NULL`.
|
||||
* @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.
|
||||
|
|
@ -1859,13 +1863,13 @@ typedef struct GLFWdragitem {
|
|||
*
|
||||
* @sa @ref drag_events
|
||||
* @sa @ref glfwSetDragCallback
|
||||
* @sa @ref glfwSetDragAcceptance
|
||||
* @sa @ref glfwUpdateDragState
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef int (* GLFWdragfun)(GLFWwindow*, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int mime_count);
|
||||
typedef int (* GLFWdragfun)(GLFWwindow*, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int* mime_count);
|
||||
|
||||
typedef void (* GLFWliveresizefun)(GLFWwindow*, bool);
|
||||
|
||||
|
|
@ -5070,19 +5074,17 @@ 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.
|
||||
/*! @brief Schedules a call to the drag callback to update drag state.
|
||||
*
|
||||
* 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.
|
||||
* This function schedules a call to the drag callback to get updated
|
||||
* acceptance status and MIME type list. Use this when the application
|
||||
* needs to update its drag state asynchronously.
|
||||
*
|
||||
* 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.
|
||||
* On Wayland and X11, this will immediately call the drag callback with
|
||||
* the current drag state. On macOS this is a no-op since the drag callback
|
||||
* is called periodically anyway.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
|
|
@ -5090,8 +5092,7 @@ GLFWAPI int glfwStartDrag(GLFWwindow* window, const GLFWdragitem* items, int ite
|
|||
* 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.
|
||||
* dragging updates via the drag callback.
|
||||
*
|
||||
* @thread_safety This function must only be called from the main thread.
|
||||
*
|
||||
|
|
@ -5102,7 +5103,7 @@ GLFWAPI int glfwStartDrag(GLFWwindow* window, const GLFWdragitem* items, int ite
|
|||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
GLFWAPI void glfwSetDragAcceptance(GLFWwindow* window, bool accepted);
|
||||
GLFWAPI void glfwUpdateDragState(GLFWwindow* window);
|
||||
|
||||
/*! @brief Returns whether the specified joystick is present.
|
||||
*
|
||||
|
|
|
|||
11
glfw/input.c
vendored
11
glfw/input.c
vendored
|
|
@ -403,16 +403,15 @@ void _glfwInputCursorEnter(_GLFWwindow* window, bool entered)
|
|||
|
||||
// Notifies shared code of files or directories dropped on a window
|
||||
//
|
||||
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz)
|
||||
void _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz)
|
||||
{
|
||||
if (window->callbacks.drop)
|
||||
return window->callbacks.drop((GLFWwindow*) window, mime, text, sz);
|
||||
return 0;
|
||||
window->callbacks.drop((GLFWwindow*) window, mime, text, sz);
|
||||
}
|
||||
|
||||
// Notifies shared code of a drag event
|
||||
//
|
||||
int _glfwInputDragEvent(_GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int mime_count)
|
||||
int _glfwInputDragEvent(_GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int* mime_count)
|
||||
{
|
||||
if (window->callbacks.drag)
|
||||
return window->callbacks.drag((GLFWwindow*) window, event, xpos, ypos, mime_types, mime_count);
|
||||
|
|
@ -1141,13 +1140,13 @@ 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)
|
||||
GLFWAPI void glfwUpdateDragState(GLFWwindow* handle)
|
||||
{
|
||||
_GLFWwindow* window = (_GLFWwindow*) handle;
|
||||
assert(window != NULL);
|
||||
|
||||
_GLFW_REQUIRE_INIT();
|
||||
_glfwPlatformSetDragAcceptance(window, accepted);
|
||||
_glfwPlatformUpdateDragState(window);
|
||||
}
|
||||
|
||||
GLFWAPI int glfwJoystickPresent(int jid)
|
||||
|
|
|
|||
6
glfw/internal.h
vendored
6
glfw/internal.h
vendored
|
|
@ -768,7 +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 _glfwPlatformUpdateDragState(_GLFWwindow* window);
|
||||
|
||||
void _glfwPlatformPollEvents(void);
|
||||
void _glfwPlatformWaitEvents(void);
|
||||
|
|
@ -822,8 +822,8 @@ void _glfwInputScroll(_GLFWwindow* window, const GLFWScrollEvent *ev);
|
|||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||
void _glfwInputCursorEnter(_GLFWwindow* window, bool entered);
|
||||
int _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz);
|
||||
int _glfwInputDragEvent(_GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int mime_count);
|
||||
void _glfwInputDrop(_GLFWwindow* window, const char *mime, const char *text, size_t sz);
|
||||
int _glfwInputDragEvent(_GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int* mime_count);
|
||||
void _glfwInputColorScheme(GLFWColorScheme, bool);
|
||||
void _glfwPlatformInputColorScheme(GLFWColorScheme);
|
||||
void _glfwInputJoystick(_GLFWjoystick* js, int event);
|
||||
|
|
|
|||
2
glfw/null_window.c
vendored
2
glfw/null_window.c
vendored
|
|
@ -539,7 +539,7 @@ int _glfwPlatformStartDrag(_GLFWwindow* window UNUSED,
|
|||
return false;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetDragAcceptance(_GLFWwindow* window UNUSED, bool accepted UNUSED)
|
||||
void _glfwPlatformUpdateDragState(_GLFWwindow* window UNUSED)
|
||||
{
|
||||
// No-op for null platform
|
||||
}
|
||||
|
|
|
|||
89
glfw/wl_window.c
vendored
89
glfw/wl_window.c
vendored
|
|
@ -2486,6 +2486,29 @@ static void handle_primary_selection_offer(void *data UNUSED, struct zwp_primary
|
|||
zwp_primary_selection_offer_v1_add_listener(id, &primary_selection_offer_listener, NULL);
|
||||
}
|
||||
|
||||
// Helper function to update drag state from callback results
|
||||
static void update_drag_state(_GLFWWaylandDataOffer *d, _GLFWwindow* window UNUSED, bool accepted, int mime_count) {
|
||||
bool acceptance_changed = (accepted != d->drag_accepted);
|
||||
// The first MIME in the sorted list is the preferred one for drop
|
||||
const char* new_preferred_mime = (accepted && mime_count > 0) ? d->mimes[0] : NULL;
|
||||
bool mime_changed = false;
|
||||
|
||||
// Check if the preferred MIME changed
|
||||
if (d->mime_for_drop == NULL && new_preferred_mime != NULL) {
|
||||
mime_changed = true;
|
||||
} else if (d->mime_for_drop != NULL && new_preferred_mime == NULL) {
|
||||
mime_changed = true;
|
||||
} else if (d->mime_for_drop != NULL && new_preferred_mime != NULL) {
|
||||
mime_changed = (strcmp(d->mime_for_drop, new_preferred_mime) != 0);
|
||||
}
|
||||
|
||||
if (acceptance_changed || mime_changed) {
|
||||
d->drag_accepted = accepted;
|
||||
d->mime_for_drop = new_preferred_mime;
|
||||
wl_data_offer_accept(d->id, d->serial, d->mime_for_drop);
|
||||
}
|
||||
}
|
||||
|
||||
static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED, uint32_t serial, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer *id) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
_GLFWWaylandDataOffer *d = _glfw.wl.dataOffers + i;
|
||||
|
|
@ -2494,32 +2517,23 @@ static void drag_enter(void *data UNUSED, struct wl_data_device *wl_data_device
|
|||
d->surface = surface;
|
||||
d->serial = serial;
|
||||
d->drag_accepted = false;
|
||||
d->mime_for_drop = NULL;
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
int format_priority = 0;
|
||||
while (window)
|
||||
{
|
||||
if (window->wl.surface == surface) {
|
||||
// Call drag enter callback with MIME types
|
||||
// Call drag enter callback with writable MIME types array
|
||||
double xpos = wl_fixed_to_double(x);
|
||||
double ypos = wl_fixed_to_double(y);
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, xpos, ypos, d->mimes, (int)d->mimes_count);
|
||||
int mime_count = (int)d->mimes_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, xpos, ypos, d->mimes, &mime_count);
|
||||
|
||||
// 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) {
|
||||
format_priority = prio;
|
||||
d->mime_for_drop = d->mimes[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update drag state based on callback results
|
||||
update_drag_state(d, window, accepted, mime_count);
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
}
|
||||
wl_data_offer_accept(id, serial, d->mime_for_drop);
|
||||
} else if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||
_glfw.wl.dataOffers[i].offer_type = EXPIRED; // previous drag offer
|
||||
}
|
||||
|
|
@ -2534,7 +2548,7 @@ static void drag_leave(void *data UNUSED, struct wl_data_device *wl_data_device
|
|||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
while (window) {
|
||||
if (window->wl.surface == _glfw.wl.dataOffers[i].surface) {
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_LEAVE, 0, 0, NULL, 0);
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_LEAVE, 0, 0, NULL, NULL);
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
|
|
@ -2572,29 +2586,6 @@ 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++) {
|
||||
|
|
@ -2605,10 +2596,12 @@ static void motion(void *data UNUSED, struct wl_data_device *wl_data_device UNUS
|
|||
if (window->wl.surface == d->surface) {
|
||||
double xpos = wl_fixed_to_double(x);
|
||||
double ypos = wl_fixed_to_double(y);
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
// Pass the MIME types array for move events
|
||||
int mime_count = (int)d->mimes_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, d->mimes, &mime_count);
|
||||
|
||||
// Update acceptance status based on callback return value
|
||||
update_drag_acceptance(d, window, accepted);
|
||||
// Update drag state based on callback results
|
||||
update_drag_state(d, window, accepted, mime_count);
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
|
|
@ -3188,12 +3181,18 @@ _glfwPlatformStartDrag(_GLFWwindow* window, const GLFWdragitem* items, int item_
|
|||
}
|
||||
|
||||
void
|
||||
_glfwPlatformSetDragAcceptance(_GLFWwindow* window, bool accepted) {
|
||||
// Find the active drag offer for this window and update its acceptance status
|
||||
_glfwPlatformUpdateDragState(_GLFWwindow* window) {
|
||||
// Find the active drag offer for this window and call the drag callback immediately
|
||||
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);
|
||||
// Call the drag callback with STATUS_UPDATE event to get updated state
|
||||
// Position values are not valid for this event type
|
||||
int mime_count = (int)d->mimes_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_STATUS_UPDATE, 0, 0, d->mimes, &mime_count);
|
||||
|
||||
// Update drag state based on callback results
|
||||
update_drag_state(d, window, accepted, mime_count);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
glfw/x11_init.c
vendored
11
glfw/x11_init.c
vendored
|
|
@ -819,6 +819,17 @@ void _glfwPlatformTerminate(void)
|
|||
if (_glfw.x11.clipboard_atoms.array) { free(_glfw.x11.clipboard_atoms.array); }
|
||||
if (_glfw.x11.primary_atoms.array) { free(_glfw.x11.primary_atoms.array); }
|
||||
|
||||
// Free cached drag MIME types (use array size, not count)
|
||||
if (_glfw.x11.xdnd.mimes) {
|
||||
for (int i = 0; i < _glfw.x11.xdnd.mimes_array_size; i++) {
|
||||
if (_glfw.x11.xdnd.mimes[i]) XFree(_glfw.x11.xdnd.mimes[i]);
|
||||
}
|
||||
free(_glfw.x11.xdnd.mimes);
|
||||
_glfw.x11.xdnd.mimes = NULL;
|
||||
_glfw.x11.xdnd.mimes_count = 0;
|
||||
_glfw.x11.xdnd.mimes_array_size = 0;
|
||||
}
|
||||
|
||||
if (_glfw.x11.display)
|
||||
{
|
||||
XCloseDisplay(_glfw.x11.display);
|
||||
|
|
|
|||
3
glfw/x11_platform.h
vendored
3
glfw/x11_platform.h
vendored
|
|
@ -386,6 +386,9 @@ typedef struct _GLFWlibraryX11
|
|||
int format_priority;
|
||||
Window target_window; // For drag events: the window being dragged over
|
||||
bool drag_accepted; // Whether the current drag is accepted
|
||||
char** mimes; // Cached MIME types from drag enter
|
||||
int mimes_count; // Current count of MIME types (may be reduced by callback)
|
||||
int mimes_array_size; // Original array size for proper cleanup
|
||||
} xdnd;
|
||||
|
||||
// Drag source state
|
||||
|
|
|
|||
132
glfw/x11_window.c
vendored
132
glfw/x11_window.c
vendored
|
|
@ -1399,6 +1399,18 @@ handle_xi_motion_event(_GLFWwindow *window, XIDeviceEvent *de) {
|
|||
}
|
||||
}
|
||||
|
||||
// Helper to free entries that were filtered out by drag callback
|
||||
static void freeFilteredXdndMimes(int old_count, int new_count) {
|
||||
if (_glfw.x11.xdnd.mimes && new_count < old_count) {
|
||||
for (int i = new_count; i < old_count; i++) {
|
||||
if (_glfw.x11.xdnd.mimes[i]) {
|
||||
XFree(_glfw.x11.xdnd.mimes[i]);
|
||||
_glfw.x11.xdnd.mimes[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Process the specified X event
|
||||
//
|
||||
|
|
@ -1831,6 +1843,17 @@ static void processEvent(XEvent *event)
|
|||
Atom* formats = NULL;
|
||||
const bool list = event->xclient.data.l[1] & 1;
|
||||
|
||||
// Free any previously cached MIME types
|
||||
if (_glfw.x11.xdnd.mimes) {
|
||||
for (int j = 0; j < _glfw.x11.xdnd.mimes_array_size; j++) {
|
||||
if (_glfw.x11.xdnd.mimes[j]) XFree(_glfw.x11.xdnd.mimes[j]);
|
||||
}
|
||||
free(_glfw.x11.xdnd.mimes);
|
||||
_glfw.x11.xdnd.mimes = NULL;
|
||||
_glfw.x11.xdnd.mimes_count = 0;
|
||||
_glfw.x11.xdnd.mimes_array_size = 0;
|
||||
}
|
||||
|
||||
_glfw.x11.xdnd.source = event->xclient.data.l[0];
|
||||
_glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
|
||||
_glfw.x11.xdnd.target_window = window->x11.handle;
|
||||
|
|
@ -1855,38 +1878,43 @@ static void processEvent(XEvent *event)
|
|||
formats = (Atom*) event->xclient.data.l + 2;
|
||||
}
|
||||
|
||||
// Get atom names and store them in the xdnd structure
|
||||
char **atom_names = calloc(count, sizeof(char*));
|
||||
int valid_mime_count = 0;
|
||||
if (atom_names) {
|
||||
get_atom_names(formats, count, atom_names);
|
||||
// Count valid MIME types
|
||||
// Compact the array to only valid MIME types
|
||||
for (i = 0; i < count; i++) {
|
||||
if (atom_names[i]) valid_mime_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Call the drag enter callback with the MIME types
|
||||
// Position is not known yet at enter time, will be updated with XdndPosition
|
||||
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]) {
|
||||
int prio = _glfwInputDrop(window, atom_names[i], NULL, 0);
|
||||
if (prio > _glfw.x11.xdnd.format_priority) {
|
||||
_glfw.x11.xdnd.format_priority = prio;
|
||||
strncpy(_glfw.x11.xdnd.format, atom_names[i], arraysz(_glfw.x11.xdnd.format) - 1);
|
||||
if (valid_mime_count != (int)i) {
|
||||
atom_names[valid_mime_count] = atom_names[i];
|
||||
atom_names[i] = NULL;
|
||||
}
|
||||
XFree(atom_names[i]);
|
||||
valid_mime_count++;
|
||||
}
|
||||
}
|
||||
free(atom_names);
|
||||
} else if (atom_names) {
|
||||
for (i = 0; i < count; i++)
|
||||
if (atom_names[i]) XFree(atom_names[i]);
|
||||
free(atom_names);
|
||||
// Store the MIME types for later use
|
||||
_glfw.x11.xdnd.mimes = atom_names;
|
||||
_glfw.x11.xdnd.mimes_count = valid_mime_count;
|
||||
_glfw.x11.xdnd.mimes_array_size = valid_mime_count;
|
||||
}
|
||||
|
||||
// Call the drag enter callback with writable MIME types array
|
||||
// Position is not known yet at enter time, will be updated with XdndPosition
|
||||
int mime_count = valid_mime_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_ENTER, 0, 0, (const char**)_glfw.x11.xdnd.mimes, &mime_count);
|
||||
|
||||
// Free any entries that were filtered out by the callback
|
||||
freeFilteredXdndMimes(valid_mime_count, mime_count);
|
||||
|
||||
// Update state based on callback results
|
||||
_glfw.x11.xdnd.drag_accepted = accepted;
|
||||
// Update cached mime count with callback result
|
||||
_glfw.x11.xdnd.mimes_count = mime_count;
|
||||
if (accepted && mime_count > 0) {
|
||||
// The first MIME type in the reordered list is the preferred one
|
||||
strncpy(_glfw.x11.xdnd.format, _glfw.x11.xdnd.mimes[0], arraysz(_glfw.x11.xdnd.format) - 1);
|
||||
_glfw.x11.xdnd.format_priority = 1;
|
||||
}
|
||||
|
||||
if (list && formats)
|
||||
|
|
@ -1931,7 +1959,19 @@ static void processEvent(XEvent *event)
|
|||
else if (event->xclient.message_type == _glfw.x11.XdndLeave)
|
||||
{
|
||||
// The drag operation has left the window
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_LEAVE, 0, 0, NULL, 0);
|
||||
_glfwInputDragEvent(window, GLFW_DRAG_LEAVE, 0, 0, NULL, NULL);
|
||||
|
||||
// Free cached MIME types (use array size, not count)
|
||||
if (_glfw.x11.xdnd.mimes) {
|
||||
for (int j = 0; j < _glfw.x11.xdnd.mimes_array_size; j++) {
|
||||
if (_glfw.x11.xdnd.mimes[j]) XFree(_glfw.x11.xdnd.mimes[j]);
|
||||
}
|
||||
free(_glfw.x11.xdnd.mimes);
|
||||
_glfw.x11.xdnd.mimes = NULL;
|
||||
_glfw.x11.xdnd.mimes_count = 0;
|
||||
_glfw.x11.xdnd.mimes_array_size = 0;
|
||||
}
|
||||
|
||||
_glfw.x11.xdnd.source = None;
|
||||
_glfw.x11.xdnd.target_window = None;
|
||||
}
|
||||
|
|
@ -1959,10 +1999,27 @@ static void processEvent(XEvent *event)
|
|||
|
||||
_glfwInputCursorPos(window, xpos, ypos);
|
||||
|
||||
// Call the drag move callback and update acceptance status
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, NULL, 0);
|
||||
// Call the drag move callback with MIME types and update acceptance status
|
||||
int old_count = _glfw.x11.xdnd.mimes_count;
|
||||
int mime_count = old_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_MOVE, xpos, ypos, (const char**)_glfw.x11.xdnd.mimes, &mime_count);
|
||||
_glfw.x11.xdnd.drag_accepted = accepted;
|
||||
|
||||
// Free any entries that were filtered out by the callback
|
||||
freeFilteredXdndMimes(old_count, mime_count);
|
||||
|
||||
// Update cached mime count with callback result
|
||||
_glfw.x11.xdnd.mimes_count = mime_count;
|
||||
|
||||
// Update the preferred format based on reordered list
|
||||
if (accepted && mime_count > 0) {
|
||||
strncpy(_glfw.x11.xdnd.format, _glfw.x11.xdnd.mimes[0], arraysz(_glfw.x11.xdnd.format) - 1);
|
||||
_glfw.x11.xdnd.format_priority = 1;
|
||||
} else {
|
||||
memset(_glfw.x11.xdnd.format, 0, sizeof(_glfw.x11.xdnd.format));
|
||||
_glfw.x11.xdnd.format_priority = 0;
|
||||
}
|
||||
|
||||
XEvent reply = { ClientMessage };
|
||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||
reply.xclient.message_type = _glfw.x11.XdndStatus;
|
||||
|
|
@ -3761,16 +3818,35 @@ int _glfwPlatformStartDrag(_GLFWwindow* window,
|
|||
return true;
|
||||
}
|
||||
|
||||
void _glfwPlatformSetDragAcceptance(_GLFWwindow* window, bool accepted) {
|
||||
void _glfwPlatformUpdateDragState(_GLFWwindow* window) {
|
||||
// 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
|
||||
// Call the drag callback with STATUS_UPDATE event to get updated state
|
||||
// Position values are not valid for this event type
|
||||
int old_count = _glfw.x11.xdnd.mimes_count;
|
||||
int mime_count = old_count;
|
||||
int accepted = _glfwInputDragEvent(window, GLFW_DRAG_STATUS_UPDATE, 0, 0, (const char**)_glfw.x11.xdnd.mimes, &mime_count);
|
||||
_glfw.x11.xdnd.drag_accepted = accepted;
|
||||
|
||||
// Free any entries that were filtered out by the callback
|
||||
freeFilteredXdndMimes(old_count, mime_count);
|
||||
|
||||
// Update cached mime count with callback result
|
||||
_glfw.x11.xdnd.mimes_count = mime_count;
|
||||
|
||||
// Update the preferred format based on reordered list
|
||||
if (accepted && mime_count > 0) {
|
||||
strncpy(_glfw.x11.xdnd.format, _glfw.x11.xdnd.mimes[0], arraysz(_glfw.x11.xdnd.format) - 1);
|
||||
_glfw.x11.xdnd.format_priority = 1;
|
||||
} else {
|
||||
memset(_glfw.x11.xdnd.format, 0, sizeof(_glfw.x11.xdnd.format));
|
||||
_glfw.x11.xdnd.format_priority = 0;
|
||||
}
|
||||
|
||||
// Send an XdndStatus message to update the drag source
|
||||
XEvent reply = { ClientMessage };
|
||||
reply.xclient.window = _glfw.x11.xdnd.source;
|
||||
|
|
|
|||
3
kitty/glfw-wrapper.c
generated
3
kitty/glfw-wrapper.c
generated
|
|
@ -365,6 +365,9 @@ load_glfw(const char* path) {
|
|||
*(void **) (&glfwStartDrag_impl) = dlsym(handle, "glfwStartDrag");
|
||||
if (glfwStartDrag_impl == NULL) fail("Failed to load glfw function glfwStartDrag with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwUpdateDragState_impl) = dlsym(handle, "glfwUpdateDragState");
|
||||
if (glfwUpdateDragState_impl == NULL) fail("Failed to load glfw function glfwUpdateDragState with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwJoystickPresent_impl) = dlsym(handle, "glfwJoystickPresent");
|
||||
if (glfwJoystickPresent_impl == NULL) fail("Failed to load glfw function glfwJoystickPresent with error: %s", dlerror());
|
||||
|
||||
|
|
|
|||
45
kitty/glfw-wrapper.h
generated
45
kitty/glfw-wrapper.h
generated
|
|
@ -1499,17 +1499,15 @@ typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
|||
* This is the function pointer type for drop callbacks. A drop
|
||||
* callback function has the following signature:
|
||||
* @code
|
||||
* int function_name(GLFWwindow* window, const char* mime, const char* text)
|
||||
* void function_name(GLFWwindow* window, const char* mime, const char* data, size_t sz)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] window The window that received the event.
|
||||
* @param[in] mime The UTF-8 encoded drop mime-type
|
||||
* @param[in] data The dropped data or NULL for drag enter events
|
||||
* @param[in] data The dropped data.
|
||||
* @param[in] sz The size of the dropped data
|
||||
* @return For drag events should return the priority for the specified mime type. A priority of zero
|
||||
* or lower means the mime type is not accepted. Highest priority will be the finally accepted mime-type.
|
||||
*
|
||||
* @pointer_lifetime The text is valid until the
|
||||
* @pointer_lifetime The data is valid until the
|
||||
* callback function returns.
|
||||
*
|
||||
* @sa @ref path_drop
|
||||
|
|
@ -1519,7 +1517,7 @@ typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
|||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef int (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||
typedef void (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||
|
||||
/*! @brief Drag event types.
|
||||
*
|
||||
|
|
@ -1533,7 +1531,9 @@ typedef enum {
|
|||
/*! The drag operation moved within the window. */
|
||||
GLFW_DRAG_MOVE = 2,
|
||||
/*! The drag operation left the window. */
|
||||
GLFW_DRAG_LEAVE = 3
|
||||
GLFW_DRAG_LEAVE = 3,
|
||||
/*! Async status update request (xpos/ypos are invalid). */
|
||||
GLFW_DRAG_STATUS_UPDATE = 4
|
||||
} GLFWDragEventType;
|
||||
|
||||
/*! @brief Drag operation types.
|
||||
|
|
@ -1576,7 +1576,7 @@ typedef struct GLFWdragitem {
|
|||
* This is the function pointer type for drag event callbacks. A drag event
|
||||
* callback function has the following signature:
|
||||
* @code
|
||||
* int function_name(GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int mime_count)
|
||||
* int function_name(GLFWwindow* window, int event, double xpos, double ypos, const char** mime_types, int* mime_count)
|
||||
* @endcode
|
||||
*
|
||||
* @param[in] window The window that received the drag event.
|
||||
|
|
@ -1584,23 +1584,30 @@ typedef struct GLFWdragitem {
|
|||
* or @ref GLFW_DRAG_LEAVE.
|
||||
* @param[in] xpos The x-coordinate of the drag position in window coordinates.
|
||||
* @param[in] ypos The y-coordinate of the drag position in window coordinates.
|
||||
* @param[in] mime_types Array of MIME type strings available from the drag source.
|
||||
* For @ref GLFW_DRAG_ENTER events this contains all available MIME types.
|
||||
* For other events this may be `NULL`. The strings are only valid for the
|
||||
* 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.
|
||||
* @param[in,out] mime_types A writable array of MIME type strings available from the drag source.
|
||||
* For @ref GLFW_DRAG_ENTER and @ref GLFW_DRAG_MOVE events this is non-NULL and contains all
|
||||
* available MIME types. The callback is responsible for sorting this list by priority and
|
||||
* keeping only the MIME types it wants to accept. The first MIME type in the sorted list
|
||||
* will be used for the drop operation. The strings are only valid for the duration of the
|
||||
* callback; if you need to store them, make copies. For @ref GLFW_DRAG_LEAVE events this
|
||||
* is `NULL`.
|
||||
* @param[in,out] mime_count Pointer to the number of MIME types in the array. The callback
|
||||
* should update this to reflect the new count after sorting and filtering. For
|
||||
* @ref GLFW_DRAG_LEAVE events this is `NULL`.
|
||||
* @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 glfwUpdateDragState
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef int (* GLFWdragfun)(GLFWwindow*, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int mime_count);
|
||||
typedef int (* GLFWdragfun)(GLFWwindow*, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int* mime_count);
|
||||
|
||||
typedef void (* GLFWliveresizefun)(GLFWwindow*, bool);
|
||||
|
||||
|
|
@ -2291,6 +2298,10 @@ typedef int (*glfwStartDrag_func)(GLFWwindow*, const GLFWdragitem*, int, const G
|
|||
GFW_EXTERN glfwStartDrag_func glfwStartDrag_impl;
|
||||
#define glfwStartDrag glfwStartDrag_impl
|
||||
|
||||
typedef void (*glfwUpdateDragState_func)(GLFWwindow*);
|
||||
GFW_EXTERN glfwUpdateDragState_func glfwUpdateDragState_impl;
|
||||
#define glfwUpdateDragState glfwUpdateDragState_impl
|
||||
|
||||
typedef int (*glfwJoystickPresent_func)(int);
|
||||
GFW_EXTERN glfwJoystickPresent_func glfwJoystickPresent_impl;
|
||||
#define glfwJoystickPresent glfwJoystickPresent_impl
|
||||
|
|
|
|||
66
kitty/glfw.c
66
kitty/glfw.c
|
|
@ -650,32 +650,76 @@ is_droppable_mime(const char *mime) {
|
|||
}
|
||||
|
||||
static int
|
||||
drag_callback(GLFWwindow *w, GLFWDragEventType event, double xpos, double ypos, const char** mime_types, int mime_count) {
|
||||
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;
|
||||
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; }
|
||||
case GLFW_DRAG_MOVE:
|
||||
case GLFW_DRAG_STATUS_UPDATE:
|
||||
if (mime_types && mime_count && *mime_count > 0) {
|
||||
// Sort MIME types by priority (descending) and keep only accepted ones
|
||||
// Use simple bubble sort since lists are typically small
|
||||
int count = *mime_count;
|
||||
int new_count = 0;
|
||||
|
||||
// Use stack-allocated array for priorities (count is typically small)
|
||||
int priorities[64];
|
||||
int* prio_arr = (count <= 64) ? priorities : (int*)malloc(count * sizeof(int));
|
||||
if (!prio_arr) {
|
||||
global_state.callback_os_window = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// First pass: filter droppable MIME types and cache priorities
|
||||
for (int i = 0; i < count; i++) {
|
||||
int prio = is_droppable_mime(mime_types[i]);
|
||||
if (prio > 0) {
|
||||
// Move this mime to the new_count position
|
||||
if (new_count != i) {
|
||||
const char* temp = mime_types[new_count];
|
||||
mime_types[new_count] = mime_types[i];
|
||||
mime_types[i] = temp;
|
||||
}
|
||||
prio_arr[new_count] = prio;
|
||||
new_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: sort by cached priorities (descending)
|
||||
for (int i = 0; i < new_count - 1; i++) {
|
||||
for (int j = i + 1; j < new_count; j++) {
|
||||
if (prio_arr[j] > prio_arr[i]) {
|
||||
const char* temp = mime_types[i];
|
||||
mime_types[i] = mime_types[j];
|
||||
mime_types[j] = temp;
|
||||
int temp_prio = prio_arr[i];
|
||||
prio_arr[i] = prio_arr[j];
|
||||
prio_arr[j] = temp_prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prio_arr != priorities) free(prio_arr);
|
||||
|
||||
*mime_count = new_count;
|
||||
ret = (new_count > 0) ? 1 : 0;
|
||||
}
|
||||
break;
|
||||
case GLFW_DRAG_MOVE: ret = 1;
|
||||
case GLFW_DRAG_LEAVE: break;
|
||||
case GLFW_DRAG_LEAVE:
|
||||
break;
|
||||
}
|
||||
global_state.callback_os_window = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
drop_callback(GLFWwindow *w, const char *mime, const char *data, size_t sz) {
|
||||
if (!set_callback_window(w)) return 0;
|
||||
#define RETURN(x) { global_state.callback_os_window = NULL; return x; }
|
||||
if (!data) return is_droppable_mime(mime);
|
||||
if (!set_callback_window(w)) return;
|
||||
WINDOW_CALLBACK(on_drop, "sy#", mime, data, (Py_ssize_t)sz);
|
||||
request_tick_callback();
|
||||
RETURN(0);
|
||||
#undef RETURN
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue