Cleanup new chunked drop code and use it in kitty
Currently the chunking is useful but it will become useful for a future drag and drop TUI protocol
This commit is contained in:
parent
ed5eb8f45c
commit
9a2ddc887b
9 changed files with 144 additions and 93 deletions
|
|
@ -1521,11 +1521,8 @@ - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
|
|||
drop_data->eof_reached = false;
|
||||
drop_data->current_data = NULL;
|
||||
drop_data->data_offset = 0;
|
||||
|
||||
_glfwInputDrop(window, drop_data);
|
||||
|
||||
// Note: drop_data is NOT freed here - application must call glfwFinishDrop
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
|
@ -3884,9 +3881,7 @@ void _glfwPlatformUpdateDragState(_GLFWwindow* window) {
|
|||
|
||||
ssize_t
|
||||
_glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, size_t capacity, monotonic_t timeout UNUSED) {
|
||||
if (!drop || !mime || !buffer || capacity == 0) return -EINVAL;
|
||||
|
||||
NSPasteboard* pasteboard = (__bridge NSPasteboard*)drop->platform_data;
|
||||
NSPasteboard* pasteboard = (NSPasteboard*)drop->platform_data;
|
||||
if (!pasteboard) return -EINVAL;
|
||||
|
||||
// Check if the MIME type is available
|
||||
|
|
@ -3906,14 +3901,12 @@ void _glfwPlatformUpdateDragState(_GLFWwindow* window) {
|
|||
drop->current_data = NULL;
|
||||
}
|
||||
drop->data_offset = 0;
|
||||
free(drop->current_mime); drop->current_mime = NULL;
|
||||
}
|
||||
|
||||
// If we need to fetch data for this MIME type
|
||||
if (drop->current_data == NULL || drop->current_mime == NULL ||
|
||||
strcmp(drop->current_mime, mime) != 0) {
|
||||
|
||||
if (drop->current_data == NULL || drop->current_mime == NULL) {
|
||||
NSData* data = nil;
|
||||
|
||||
// Handle special MIME types
|
||||
if (strcmp(mime, "text/uri-list") == 0) {
|
||||
NSDictionary* options = @{NSPasteboardURLReadingFileURLsOnlyKey:@YES};
|
||||
|
|
@ -3943,11 +3936,9 @@ void _glfwPlatformUpdateDragState(_GLFWwindow* window) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!data) return -ENOENT;
|
||||
|
||||
drop->current_data = [data retain];
|
||||
drop->current_mime = mime;
|
||||
drop->current_mime = _glfw_strdup(mime);
|
||||
drop->data_offset = 0;
|
||||
}
|
||||
|
||||
|
|
@ -3955,23 +3946,19 @@ void _glfwPlatformUpdateDragState(_GLFWwindow* window) {
|
|||
NSData* data = (NSData*)drop->current_data;
|
||||
NSUInteger dataLength = [data length];
|
||||
|
||||
if (drop->data_offset >= dataLength) {
|
||||
return 0; // EOF
|
||||
}
|
||||
|
||||
if (drop->data_offset >= dataLength) return 0; // EOF
|
||||
NSUInteger remaining = dataLength - drop->data_offset;
|
||||
NSUInteger to_read = (remaining < capacity) ? remaining : capacity;
|
||||
|
||||
[data getBytes:buffer range:NSMakeRange(drop->data_offset, to_read)];
|
||||
drop->data_offset += to_read;
|
||||
|
||||
return (ssize_t)to_read;
|
||||
}
|
||||
|
||||
void
|
||||
_glfwPlatformFinishDrop(GLFWDropData* drop, GLFWDragOperationType operation UNUSED, bool success UNUSED) {
|
||||
if (!drop) return;
|
||||
|
||||
free(drop->current_mime); drop->current_mime = NULL;
|
||||
// Release the retained current data
|
||||
if (drop->current_data) {
|
||||
[(NSData*)drop->current_data release];
|
||||
|
|
|
|||
6
glfw/input.c
vendored
6
glfw/input.c
vendored
|
|
@ -1161,11 +1161,7 @@ GLFWAPI const char** glfwGetDropMimeTypes(GLFWDropData* drop, int* count)
|
|||
|
||||
GLFWAPI ssize_t glfwReadDropData(GLFWDropData* drop, const char* mime, void* buffer, size_t capacity, monotonic_t timeout)
|
||||
{
|
||||
assert(drop != NULL);
|
||||
assert(mime != NULL);
|
||||
assert(buffer != NULL);
|
||||
assert(capacity > 0);
|
||||
|
||||
if (drop == NULL || mime == NULL || buffer == NULL || capacity < 1) return -EINVAL;
|
||||
_GLFW_REQUIRE_INIT_OR_RETURN(-1);
|
||||
return _glfwPlatformReadDropData(drop, mime, buffer, capacity, timeout);
|
||||
}
|
||||
|
|
|
|||
2
glfw/internal.h
vendored
2
glfw/internal.h
vendored
|
|
@ -90,7 +90,7 @@ struct GLFWDropData {
|
|||
const char** mime_types; // Array of available MIME types (owned by drop object)
|
||||
int mime_count; // Number of MIME types
|
||||
int mime_array_size; // Original array size for proper cleanup
|
||||
const char* current_mime; // Currently being read MIME type
|
||||
char* current_mime; // Currently being read MIME type
|
||||
int read_fd; // File descriptor for reading data (Wayland/X11)
|
||||
size_t bytes_read; // Total bytes read so far for current mime
|
||||
void* platform_data; // Platform-specific data (offer for Wayland, pasteboard for Cocoa)
|
||||
|
|
|
|||
62
glfw/wl_window.c
vendored
62
glfw/wl_window.c
vendored
|
|
@ -2522,14 +2522,14 @@ static void drag_leave(void *data UNUSED, struct wl_data_device *wl_data_device
|
|||
}
|
||||
}
|
||||
|
||||
static void drop(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED) {
|
||||
static void
|
||||
drop(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED) {
|
||||
for (size_t i = 0; i < arraysz(_glfw.wl.dataOffers); i++) {
|
||||
if (_glfw.wl.dataOffers[i].offer_type == DRAG_AND_DROP) {
|
||||
_GLFWWaylandDataOffer *offer = &_glfw.wl.dataOffers[i];
|
||||
|
||||
_GLFWwindow* window = _glfw.windowListHead;
|
||||
while (window)
|
||||
{
|
||||
while (window) {
|
||||
if (window->wl.surface == offer->surface) {
|
||||
// Heap-allocate drop data structure for chunked reading
|
||||
// The application is responsible for freeing this via glfwFinishDrop
|
||||
|
|
@ -2543,26 +2543,20 @@ static void drop(void *data UNUSED, struct wl_data_device *wl_data_device UNUSED
|
|||
drop_data->mime_types = offer->mimes;
|
||||
drop_data->mime_count = (int)offer->mimes_count;
|
||||
drop_data->mime_array_size = (int)offer->mimes_count;
|
||||
// Clear offer's references since drop object now owns the mimes
|
||||
offer->mimes = NULL;
|
||||
offer->mimes_count = 0;
|
||||
|
||||
drop_data->current_mime = NULL;
|
||||
drop_data->read_fd = -1;
|
||||
drop_data->bytes_read = 0;
|
||||
drop_data->platform_data = offer; // Store the offer for later use
|
||||
drop_data->platform_data = offer->id; // Store the offer for later use
|
||||
offer->mimes = NULL; offer->id = NULL;
|
||||
destroy_data_offer(offer);
|
||||
drop_data->eof_reached = false;
|
||||
|
||||
memset(offer, 0, sizeof(offer[0]));
|
||||
_glfwInputDrop(window, drop_data);
|
||||
|
||||
// Note: drop_data is NOT freed here - application must call glfwFinishDrop
|
||||
break;
|
||||
}
|
||||
window = window->next;
|
||||
}
|
||||
|
||||
// Note: We no longer destroy the offer here as the drop_data holds a reference
|
||||
// The offer will be destroyed when glfwFinishDrop is called
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3189,10 +3183,7 @@ _glfwPlatformGetDropMimeTypes(GLFWDropData* drop, int* count) {
|
|||
|
||||
ssize_t
|
||||
_glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, size_t capacity, monotonic_t timeout) {
|
||||
if (!drop || !mime || !buffer || capacity == 0) return -EINVAL;
|
||||
|
||||
_GLFWWaylandDataOffer *offer = (_GLFWWaylandDataOffer*)drop->platform_data;
|
||||
if (!offer || !offer->id) return -EINVAL;
|
||||
if (!drop->platform_data) return -EINVAL;
|
||||
|
||||
// Check if the MIME type is available
|
||||
bool mime_found = false;
|
||||
|
|
@ -3212,27 +3203,23 @@ _glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, si
|
|||
}
|
||||
drop->bytes_read = 0;
|
||||
drop->eof_reached = false;
|
||||
free(drop->current_mime); drop->current_mime = NULL;
|
||||
}
|
||||
|
||||
// If we've reached EOF for this MIME type, return 0
|
||||
if (drop->eof_reached && drop->current_mime && strcmp(drop->current_mime, mime) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (drop->eof_reached && drop->current_mime && strcmp(drop->current_mime, mime) == 0) return 0;
|
||||
|
||||
// Open a new pipe if we don't have one for this MIME type
|
||||
if (drop->read_fd < 0 || drop->current_mime == NULL || strcmp(drop->current_mime, mime) != 0) {
|
||||
if (drop->read_fd < 0 || drop->current_mime == NULL) {
|
||||
int pipefd[2];
|
||||
if (pipe2(pipefd, O_CLOEXEC | O_NONBLOCK) != 0) return -EIO;
|
||||
|
||||
wl_data_offer_receive(offer->id, mime, pipefd[1]);
|
||||
wl_data_offer_receive(drop->platform_data, mime, pipefd[1]);
|
||||
close(pipefd[1]);
|
||||
|
||||
// Round trip to ensure the compositor processes the receive request
|
||||
wl_display_roundtrip(_glfw.wl.display);
|
||||
|
||||
// Flush to ensure the compositor processes the receive request
|
||||
wl_display_flush(_glfw.wl.display);
|
||||
drop->read_fd = pipefd[0];
|
||||
// mime points to drop->mime_types entry, valid for duration of drop callback
|
||||
drop->current_mime = mime;
|
||||
drop->current_mime = _glfw_strdup(mime);
|
||||
drop->bytes_read = 0;
|
||||
drop->eof_reached = false;
|
||||
}
|
||||
|
|
@ -3264,20 +3251,20 @@ _glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, si
|
|||
}
|
||||
|
||||
// Read data from the pipe
|
||||
ssize_t bytes_read = read(drop->read_fd, buffer, capacity);
|
||||
ssize_t bytes_read = -1;
|
||||
errno = EINTR;
|
||||
while (errno == EINTR) { errno = 0; bytes_read = read(drop->read_fd, buffer, capacity); }
|
||||
if (bytes_read < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return -ETIME; // No data available yet
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (bytes_read == 0) {
|
||||
// EOF reached
|
||||
drop->eof_reached = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
drop->bytes_read += bytes_read;
|
||||
return bytes_read;
|
||||
}
|
||||
|
|
@ -3285,6 +3272,7 @@ _glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, si
|
|||
void
|
||||
_glfwPlatformFinishDrop(GLFWDropData* drop, GLFWDragOperationType operation UNUSED, bool success UNUSED) {
|
||||
if (!drop) return;
|
||||
free(drop->current_mime); drop->current_mime = NULL;
|
||||
|
||||
// Close any open file descriptor
|
||||
if (drop->read_fd >= 0) {
|
||||
|
|
@ -3293,19 +3281,15 @@ _glfwPlatformFinishDrop(GLFWDropData* drop, GLFWDragOperationType operation UNUS
|
|||
}
|
||||
|
||||
// Destroy the associated data offer
|
||||
|
||||
// Note: Wayland doesn't have a way to report the operation type or success back to the source
|
||||
// in the same way as X11, as the source is notified through other means
|
||||
_GLFWWaylandDataOffer* offer = (_GLFWWaylandDataOffer*)drop->platform_data;
|
||||
if (offer) {
|
||||
destroy_data_offer(offer);
|
||||
}
|
||||
if (drop->platform_data) wl_data_offer_destroy(drop->platform_data);
|
||||
drop->platform_data = NULL;
|
||||
|
||||
// Free the mime types array (owned by drop object)
|
||||
if (drop->mime_types) {
|
||||
for (int i = 0; i < drop->mime_array_size; i++) {
|
||||
if (drop->mime_types[i])
|
||||
free((char*)drop->mime_types[i]);
|
||||
}
|
||||
for (int i = 0; i < drop->mime_array_size; i++) free((char*)drop->mime_types[i]);
|
||||
free(drop->mime_types);
|
||||
drop->mime_types = NULL;
|
||||
}
|
||||
|
|
|
|||
19
glfw/x11_window.c
vendored
19
glfw/x11_window.c
vendored
|
|
@ -3883,8 +3883,6 @@ _glfwPlatformGetDropMimeTypes(GLFWDropData* drop, int* count) {
|
|||
|
||||
ssize_t
|
||||
_glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, size_t capacity, monotonic_t timeout) {
|
||||
if (!drop || !mime || !buffer || capacity == 0) return -EINVAL;
|
||||
|
||||
// Check if the MIME type is available
|
||||
bool mime_found = false;
|
||||
for (int i = 0; i < drop->mime_count; i++) {
|
||||
|
|
@ -3903,15 +3901,12 @@ _glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, si
|
|||
}
|
||||
drop->x11_data_size = 0;
|
||||
drop->data_offset = 0;
|
||||
drop->current_mime = NULL;
|
||||
free(drop->current_mime); drop->current_mime = NULL;
|
||||
}
|
||||
|
||||
// If we need to fetch data for this MIME type
|
||||
if (drop->current_data == NULL || drop->current_mime == NULL ||
|
||||
strcmp(drop->current_mime, mime) != 0) {
|
||||
|
||||
if (drop->current_data == NULL || drop->current_mime == NULL) {
|
||||
Atom target_atom = XInternAtom(_glfw.x11.display, mime, False);
|
||||
|
||||
// Request the data via XConvertSelection
|
||||
XConvertSelection(_glfw.x11.display,
|
||||
_glfw.x11.XdndSelection,
|
||||
|
|
@ -3963,7 +3958,7 @@ _glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, si
|
|||
drop->x11_data_size = size;
|
||||
drop->data_offset = 0;
|
||||
// mime points to drop->mime_types entry, valid for duration of drop callback
|
||||
drop->current_mime = mime;
|
||||
drop->current_mime = _glfw_strdup(mime);
|
||||
got_data = true;
|
||||
} else {
|
||||
if (data) XFree(data);
|
||||
|
|
@ -3983,22 +3978,18 @@ _glfwPlatformReadDropData(GLFWDropData* drop, const char* mime, void* buffer, si
|
|||
}
|
||||
|
||||
// Read data from buffer
|
||||
if (drop->data_offset >= drop->x11_data_size) {
|
||||
return 0; // EOF
|
||||
}
|
||||
|
||||
if (drop->data_offset >= drop->x11_data_size) return 0; // EOF
|
||||
size_t remaining = drop->x11_data_size - drop->data_offset;
|
||||
size_t to_read = (remaining < capacity) ? remaining : capacity;
|
||||
|
||||
memcpy(buffer, (unsigned char*)drop->current_data + drop->data_offset, to_read);
|
||||
drop->data_offset += to_read;
|
||||
|
||||
return (ssize_t)to_read;
|
||||
}
|
||||
|
||||
void
|
||||
_glfwPlatformFinishDrop(GLFWDropData* drop, GLFWDragOperationType operation, bool success) {
|
||||
if (!drop) return;
|
||||
free(drop->current_mime); drop->current_mime = NULL;
|
||||
|
||||
// Free current data if any
|
||||
if (drop->current_data) {
|
||||
|
|
|
|||
|
|
@ -1883,20 +1883,28 @@ def update_tab_bar_data(self, os_window_id: int) -> None:
|
|||
if tm is not None:
|
||||
tm.update_tab_bar_data()
|
||||
|
||||
def on_drop(self, os_window_id: int, mime: str, data: bytes) -> None:
|
||||
def on_drop(self, os_window_id: int, drop: dict[str, bytes] | Exception) -> None:
|
||||
if isinstance(drop, Exception):
|
||||
self.show_error(_('Drop failed'), str(drop))
|
||||
return
|
||||
tm = self.os_window_map.get(os_window_id)
|
||||
if tm is not None:
|
||||
w = tm.active_window
|
||||
if w is not None:
|
||||
text = data.decode('utf-8', 'replace')
|
||||
if mime == 'text/uri-list':
|
||||
urls = parse_uri_list(text)
|
||||
text = ''
|
||||
if uri_list := drop.pop('text/uri-list', b''):
|
||||
urls = parse_uri_list(uri_list.decode('utf-8', 'replace'))
|
||||
if w.at_prompt:
|
||||
import shlex
|
||||
text = ' '.join(map(shlex.quote, urls))
|
||||
else:
|
||||
text = '\n'.join(urls)
|
||||
w.paste_text(text)
|
||||
elif tp := drop.pop('text/plain', b''):
|
||||
text = tp.decode('utf-8', 'replace')
|
||||
elif tp := drop.pop('text/plain;charset=utf-8', b''):
|
||||
text = tp.decode('utf-8', 'replace')
|
||||
if text:
|
||||
w.paste_text(text)
|
||||
|
||||
@ac('win', '''
|
||||
Focus the nth OS window if positive or the previously active OS windows if negative. When the number is larger
|
||||
|
|
|
|||
9
kitty/glfw-wrapper.c
generated
9
kitty/glfw-wrapper.c
generated
|
|
@ -368,6 +368,15 @@ load_glfw(const char* path) {
|
|||
*(void **) (&glfwUpdateDragState_impl) = dlsym(handle, "glfwUpdateDragState");
|
||||
if (glfwUpdateDragState_impl == NULL) fail("Failed to load glfw function glfwUpdateDragState with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwGetDropMimeTypes_impl) = dlsym(handle, "glfwGetDropMimeTypes");
|
||||
if (glfwGetDropMimeTypes_impl == NULL) fail("Failed to load glfw function glfwGetDropMimeTypes with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwReadDropData_impl) = dlsym(handle, "glfwReadDropData");
|
||||
if (glfwReadDropData_impl == NULL) fail("Failed to load glfw function glfwReadDropData with error: %s", dlerror());
|
||||
|
||||
*(void **) (&glfwFinishDrop_impl) = dlsym(handle, "glfwFinishDrop");
|
||||
if (glfwFinishDrop_impl == NULL) fail("Failed to load glfw function glfwFinishDrop 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());
|
||||
|
||||
|
|
|
|||
49
kitty/glfw-wrapper.h
generated
49
kitty/glfw-wrapper.h
generated
|
|
@ -1005,6 +1005,22 @@ typedef struct GLFWwindow GLFWwindow;
|
|||
*/
|
||||
typedef struct GLFWcursor GLFWcursor;
|
||||
|
||||
/*! @brief Opaque drop data object.
|
||||
*
|
||||
* Opaque drop data object representing data from a drag and drop operation.
|
||||
* This object is passed to the drop callback and can be used to query
|
||||
* available MIME types and read the dropped data in chunks.
|
||||
*
|
||||
* @see @ref path_drop
|
||||
* @see @ref glfwGetDropMimeTypes
|
||||
* @see @ref glfwReadDropData
|
||||
*
|
||||
* @since Added in version 4.0.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef struct GLFWDropData GLFWDropData;
|
||||
|
||||
typedef enum {
|
||||
GLFW_RELEASE = 0,
|
||||
GLFW_PRESS = 1,
|
||||
|
|
@ -1499,25 +1515,30 @@ typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*);
|
|||
* This is the function pointer type for drop callbacks. A drop
|
||||
* callback function has the following signature:
|
||||
* @code
|
||||
* void function_name(GLFWwindow* window, const char* mime, const char* data, size_t sz)
|
||||
* void function_name(GLFWwindow* window, GLFWDropData* drop)
|
||||
* @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.
|
||||
* @param[in] sz The size of the dropped data
|
||||
* @param[in] drop A heap-allocated opaque pointer representing the dropped data. Use
|
||||
* @ref glfwGetDropMimeTypes to get available MIME types and
|
||||
* @ref glfwReadDropData to read the data in chunks.
|
||||
*
|
||||
* @pointer_lifetime The data is valid until the
|
||||
* callback function returns.
|
||||
* @note The drop object is heap-allocated and remains valid until the
|
||||
* application calls @ref glfwFinishDrop to free it. The application is
|
||||
* responsible for calling glfwFinishDrop when it has finished reading
|
||||
* the dropped data, even if reading fails or is not needed.
|
||||
*
|
||||
* @sa @ref path_drop
|
||||
* @sa @ref glfwSetDropCallback
|
||||
* @sa @ref glfwGetDropMimeTypes
|
||||
* @sa @ref glfwReadDropData
|
||||
* @sa @ref glfwFinishDrop
|
||||
*
|
||||
* @since Added in version 3.1.
|
||||
* @since Changed in version 4.0 to receive opaque drop data pointer.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef void (* GLFWdropfun)(GLFWwindow*, const char *, const char*, size_t);
|
||||
typedef void (* GLFWdropfun)(GLFWwindow*, GLFWDropData*);
|
||||
|
||||
/*! @brief Drag event types.
|
||||
*
|
||||
|
|
@ -2302,6 +2323,18 @@ typedef void (*glfwUpdateDragState_func)(GLFWwindow*);
|
|||
GFW_EXTERN glfwUpdateDragState_func glfwUpdateDragState_impl;
|
||||
#define glfwUpdateDragState glfwUpdateDragState_impl
|
||||
|
||||
typedef const char** (*glfwGetDropMimeTypes_func)(GLFWDropData*, int*);
|
||||
GFW_EXTERN glfwGetDropMimeTypes_func glfwGetDropMimeTypes_impl;
|
||||
#define glfwGetDropMimeTypes glfwGetDropMimeTypes_impl
|
||||
|
||||
typedef ssize_t (*glfwReadDropData_func)(GLFWDropData*, const char*, void*, size_t, monotonic_t);
|
||||
GFW_EXTERN glfwReadDropData_func glfwReadDropData_impl;
|
||||
#define glfwReadDropData glfwReadDropData_impl
|
||||
|
||||
typedef void (*glfwFinishDrop_func)(GLFWDropData*, GLFWDragOperationType, bool);
|
||||
GFW_EXTERN glfwFinishDrop_func glfwFinishDrop_impl;
|
||||
#define glfwFinishDrop glfwFinishDrop_impl
|
||||
|
||||
typedef int (*glfwJoystickPresent_func)(int);
|
||||
GFW_EXTERN glfwJoystickPresent_func glfwJoystickPresent_impl;
|
||||
#define glfwJoystickPresent glfwJoystickPresent_impl
|
||||
|
|
|
|||
47
kitty/glfw.c
47
kitty/glfw.c
|
|
@ -700,10 +700,53 @@ end:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
read_drop_data(GLFWDropData *drop, const char *mime) {
|
||||
RAII_PyObject(ans, PyBytes_FromStringAndSize(NULL, 8192));
|
||||
if (!ans) return NULL;
|
||||
size_t pos = 0;
|
||||
monotonic_t timeout = s_double_to_monotonic_t(2);
|
||||
while (true) {
|
||||
int ret = glfwReadDropData(drop, mime, PyBytes_AS_STRING(ans) + pos, PyBytes_GET_SIZE(ans) - pos, timeout);
|
||||
if (ret > 0) {
|
||||
pos += ret;
|
||||
if (pos >= (size_t)PyBytes_GET_SIZE(ans)) {
|
||||
if (_PyBytes_Resize(&ans, pos * 2) != 0) return NULL;
|
||||
}
|
||||
} else if (ret == 0) {
|
||||
if (_PyBytes_Resize(&ans, pos) != 0) return NULL;
|
||||
return Py_NewRef(ans);
|
||||
}
|
||||
else {
|
||||
errno = -ret;
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drop_callback(GLFWwindow *w, const char *mime, const char *data, size_t sz) {
|
||||
get_mime_data(GLFWDropData *drop, const char **mimes, int mime_count, PyObject *ans) {
|
||||
for (int i = 0; i < mime_count; i++) {
|
||||
if (is_droppable_mime(mimes[i])) {
|
||||
RAII_PyObject(data, read_drop_data(drop, mimes[i]));
|
||||
if (data == NULL) return ;
|
||||
if (PyDict_SetItemString(ans, mimes[i], data) != 0) return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
drop_callback(GLFWwindow *w, GLFWDropData *drop) {
|
||||
int num_mimes;
|
||||
const char** mimes = glfwGetDropMimeTypes(drop, &num_mimes);
|
||||
RAII_PyObject(ans, PyDict_New());
|
||||
get_mime_data(drop, mimes, num_mimes, ans);
|
||||
RAII_PyObject(exc, PyErr_GetRaisedException());
|
||||
glfwFinishDrop(drop, GLFW_DRAG_OPERATION_COPY, true);
|
||||
if (!set_callback_window(w)) return;
|
||||
WINDOW_CALLBACK(on_drop, "sy#", mime, data, (Py_ssize_t)sz);
|
||||
if (exc != NULL) { WINDOW_CALLBACK(on_drop, "O", exc); }
|
||||
else if (PyDict_Size(ans)) WINDOW_CALLBACK(on_drop, "O", ans);
|
||||
request_tick_callback();
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue