From cb0d7b8583eafd77166219564f500793910bc170 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 14 Sep 2026 15:09:14 -0700 Subject: [PATCH] wayland drag and drop --- NTMakefile | 12 +++- WatMakefile | 12 +++- examples/basic/dnd.c | 59 ++++++++++++++++ include/Mw/LowLevel/Wayland.h | 3 + pl/rules.pl | 1 + src/backend/wayland/interfaces.c | 115 +++++++++++++++++++++++++++---- 6 files changed, 186 insertions(+), 16 deletions(-) create mode 100644 examples/basic/dnd.c diff --git a/NTMakefile b/NTMakefile index 26723bc..213800d 100644 --- a/NTMakefile +++ b/NTMakefile @@ -6,9 +6,9 @@ MW_LDFLAGS = /DLL EXE_CFLAGS = /Iinclude EXE_LDFLAGS = .SUFFIXES: .obj .c -all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +all: src\Mw.dll examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\dnd.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe lib: src\Mw.dll -examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe +examples: examples\basic\box.exe examples\basic\calculator.exe examples\basic\checkbox.exe examples\basic\clipboard.exe examples\basic\colorpicker.exe examples\basic\combobox.exe examples\basic\dnd.exe examples\basic\document.exe examples\basic\example.exe examples\basic\filechooser.exe examples\basic\image.exe examples\basic\listbox.exe examples\basic\messagebox.exe examples\basic\periodic.exe examples\basic\progressbar.exe examples\basic\radiobox.exe examples\basic\rotate.exe examples\basic\scrollbar.exe examples\basic\sevensegment.exe examples\basic\subwindow.exe examples\basic\tab.exe examples\basic\treeview.exe examples\basic\viewport.exe examples\gldemos\boing.exe examples\gldemos\clock.exe examples\gldemos\cube.exe examples\gldemos\gears.exe examples\gldemos\triangle.exe examples\gldemos\tripaint.exe clean: del /f /q external\libz\src\adler32.obj del /f /q external\libz\src\compress.obj @@ -112,6 +112,7 @@ clean: del /f /q examples\basic\clipboard.obj del /f /q examples\basic\colorpicker.obj del /f /q examples\basic\combobox.obj + del /f /q examples\basic\dnd.obj del /f /q examples\basic\document.obj del /f /q examples\basic\example.obj del /f /q examples\basic\filechooser.obj @@ -140,6 +141,7 @@ clean: del /f /q examples\basic\clipboard.exe del /f /q examples\basic\colorpicker.exe del /f /q examples\basic\combobox.exe + del /f /q examples\basic\dnd.exe del /f /q examples\basic\document.exe del /f /q examples\basic\example.exe del /f /q examples\basic\filechooser.exe @@ -199,6 +201,12 @@ examples\basic\combobox.exe: examples\basic\combobox.obj src\Mw.dll examples\basic\combobox.obj: examples/basic/combobox.c $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/combobox.c +examples\basic\dnd.exe: examples\basic\dnd.obj src\Mw.dll + $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\dnd.obj src\Mw.lib + +examples\basic\dnd.obj: examples/basic/dnd.c + $(CC) $(EXE_CFLAGS) /Fo$@ examples/basic/dnd.c + examples\basic\document.exe: examples\basic\document.obj src\Mw.dll $(LD) $(EXE_LDFLAGS) /OUT:$@ examples\basic\document.obj src\Mw.lib diff --git a/WatMakefile b/WatMakefile index 7924e17..0b846d1 100644 --- a/WatMakefile +++ b/WatMakefile @@ -5,9 +5,9 @@ MW_CFLAGS = -bd -i=include -i=external/libz/include -d_MILSKO -d_MILSKO_BUILD -d MW_LDFLAGS = system nt_dll EXE_CFLAGS = -i=include EXE_LDFLAGS = system nt -all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +all: src/Mw.dll examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/dnd.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe lib: src/Mw.dll -examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe +examples: examples/basic/box.exe examples/basic/calculator.exe examples/basic/checkbox.exe examples/basic/clipboard.exe examples/basic/colorpicker.exe examples/basic/combobox.exe examples/basic/dnd.exe examples/basic/document.exe examples/basic/example.exe examples/basic/filechooser.exe examples/basic/image.exe examples/basic/listbox.exe examples/basic/messagebox.exe examples/basic/periodic.exe examples/basic/progressbar.exe examples/basic/radiobox.exe examples/basic/rotate.exe examples/basic/scrollbar.exe examples/basic/sevensegment.exe examples/basic/subwindow.exe examples/basic/tab.exe examples/basic/treeview.exe examples/basic/viewport.exe examples/gldemos/boing.exe examples/gldemos/clock.exe examples/gldemos/cube.exe examples/gldemos/gears.exe examples/gldemos/triangle.exe examples/gldemos/tripaint.exe clean: .SYMBOLIC %erase external/libz/src/adler32.obj %erase external/libz/src/compress.obj @@ -111,6 +111,7 @@ clean: .SYMBOLIC %erase examples/basic/clipboard.obj %erase examples/basic/colorpicker.obj %erase examples/basic/combobox.obj + %erase examples/basic/dnd.obj %erase examples/basic/document.obj %erase examples/basic/example.obj %erase examples/basic/filechooser.obj @@ -139,6 +140,7 @@ clean: .SYMBOLIC %erase examples/basic/clipboard.exe %erase examples/basic/colorpicker.exe %erase examples/basic/combobox.exe + %erase examples/basic/dnd.exe %erase examples/basic/document.exe %erase examples/basic/example.exe %erase examples/basic/filechooser.exe @@ -198,6 +200,12 @@ examples/basic/combobox.exe: examples/basic/combobox.obj src/Mw.dll examples/basic/combobox.obj: examples/basic/combobox.c $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/combobox.c +examples/basic/dnd.exe: examples/basic/dnd.obj src/Mw.dll + $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/dnd.obj library clib3r.lib library src/Mw.lib + +examples/basic/dnd.obj: examples/basic/dnd.c + $(CC) $(EXE_CFLAGS) -fo=$@ examples/basic/dnd.c + examples/basic/document.exe: examples/basic/document.obj src/Mw.dll $(LD) $(EXE_LDFLAGS) name $@ file examples/basic/document.obj library clib3r.lib library src/Mw.lib diff --git a/examples/basic/dnd.c b/examples/basic/dnd.c new file mode 100644 index 0000000..f88a650 --- /dev/null +++ b/examples/basic/dnd.c @@ -0,0 +1,59 @@ +#include + +MwWidget window, instructions, text1, cur_text; + +static void MWAPI resize(MwWidget handle, void* user_data, void* call_data) { + unsigned int w, h; + + (void)user_data; + (void)call_data; + + w = MwGetInteger(handle, MwNwidth); + h = MwGetInteger(handle, MwNheight); + + MwVaApply(instructions, + MwNy, 50, + MwNwidth, w - 50 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); + + MwVaApply(text1, + MwNy, 150, + MwNwidth, w - 25 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); +} +static void MWAPI dnd(MwWidget handle, void* user_data, void* call_data) { + char* filename = call_data; + + (void)handle; + (void)user_data; + + if(filename != NULL) { + MwVaApply(cur_text, MwNtext, filename, NULL); + MwForceRender(cur_text); + } +} + +int main() { + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, + MwNtitle, "dnd", + NULL); + instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, + MwNtext, "drag a file and its name will show up below.", + NULL); + text1 = MwVaCreateWidget(MwLabelClass, "label", window, 25, 150, 300, 75, + MwNtext, "", + NULL); + + cur_text = text1; + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(window, MwNdragAndDropHandler, dnd, NULL); + + resize(window, NULL, NULL); + + MwLoop(window); +} diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index fd97178..44a3983 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -292,6 +292,9 @@ typedef struct wl_clipboard_device_context { struct zwp_primary_selection_offer_v1* zwp; } offer; + const char* accepted_types[6]; + char selected_mime_type[4096]; + MwLL ll; // struct wl_seat* seat; } wl_clipboard_device_context_t; diff --git a/pl/rules.pl b/pl/rules.pl index ad62d6c..551d391 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -207,6 +207,7 @@ new_example("examples/basic/combobox"); new_example("examples/basic/treeview"); new_example("examples/basic/box"); new_example("examples/basic/clipboard"); +new_example("examples/basic/dnd"); new_example("examples/basic/sevensegment"); new_example("examples/basic/calculator"); new_example("examples/basic/filechooser"); diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index cbab2ad..eaabf16 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -100,11 +100,32 @@ static void wl_offer(void* data, struct wl_data_offer* wl_data_offer, const char* mime_type) { wl_clipboard_device_context_t* self = data; - wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); + int i; + for(i = 0; i < sizeof(self->accepted_types) / sizeof(self->accepted_types[0]); i++) { + if(strcmp(self->accepted_types[i], mime_type) == 0) { + wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); + memset(self->selected_mime_type, 0, 4096); + snprintf(self->selected_mime_type, sizeof(self->selected_mime_type), "%s", mime_type); + break; + } + } }; +static void wl_source_actions(void* data, + struct wl_data_offer* wl_data_offer, + uint32_t source_actions) { + + // printf("%d\n", source_actions); +}; + +static void wl_action(void* data, + struct wl_data_offer* wl_data_offer, + uint32_t dnd_action) {}; + struct wl_data_offer_listener offer_listener = { - .offer = wl_offer, + .offer = wl_offer, + .source_actions = wl_source_actions, + .action = wl_action, }; static void wl_data_device_data_offer(void* data, @@ -125,7 +146,7 @@ static void wl_data_device_enter(void* data, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer* id) { - MwLL self = data; + wl_clipboard_device_context_t* self = data; (void)wl_data_device; (void)surface; (void)x; @@ -134,33 +155,86 @@ static void wl_data_device_enter(void* data, WAYLAND_EVENT_OP_START(self); - self->wayland.clipboard_serial = serial; + self->ll->wayland.clipboard_serial = serial; WAYLAND_EVENT_OP_END(self); }; static void wl_data_device_leave(void* data, struct wl_data_device* wl_data_device) { - MwLL self = data; + wl_clipboard_device_context_t* self = data; - WAYLAND_EVENT_OP_START(self); - wl_data_device_destroy(wl_data_device); - WAYLAND_EVENT_OP_END(self); + if(self->offer.wl) { + wl_data_offer_destroy(self->offer.wl); + self->offer.wl = NULL; + } }; static void wl_data_device_motion(void* data, struct wl_data_device* wl_data_device, uint32_t time, wl_fixed_t x, wl_fixed_t y) { - (void)data; (void)wl_data_device; (void)time; (void)x; (void)y; + wl_clipboard_device_context_t* self = data; + + if(self->selected_mime_type[0] != '\0' && self->offer.wl) { + wl_data_offer_set_actions(self->offer.wl, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); + } }; static void wl_data_device_drop(void* data, struct wl_data_device* wl_data_device) { - (void)data; - (void)wl_data_device; + wl_clipboard_device_context_t* self = data; + int fds[2]; + fd_set set; + char* buf = NULL; + struct timeval timeout; + int rc = 0; + + if(pipe(fds) != 0) { + + return; + } + + FD_ZERO(&set); + FD_SET(fds[0], &set); + timeout.tv_sec = 0; + timeout.tv_usec = 1000; + + wl_data_offer_receive(self->offer.wl, self->selected_mime_type, fds[1]); + close(fds[1]); + + MwLLWaylandFlush(self->ll); + wl_display_roundtrip(self->ll->wayland.display); + + while(MwTRUE) { + rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); + if(rc <= 0) { + break; + } else { + char b; + ssize_t n = read(fds[0], &b, sizeof(b)); + if(n <= 0) { + break; + } + arrpush(buf, b); + } + } + arrpush(buf, 0); + close(fds[0]); + + setup_clipboard(self->ll, self->ll->wayland.pointer_seat); + + if(strstr(buf, "file://")) { + MwLLDispatch(self->ll, drag_and_drop, buf + sizeof("file://") - 1); + } else { + MwLLDispatch(self->ll, drag_and_drop, buf); + } + + arrfree(buf); + + self->selected_mime_type[0] = '\0'; }; static void wl_data_device_selection(void* data, @@ -256,6 +330,7 @@ static void wl_data_source_listener_target(void* data, (void)data; (void)wl_data_source; (void)mime_type; + printf("test\n"); }; static void wl_data_source_listener_send(void* data, struct wl_data_source* wl_data_source, @@ -297,6 +372,7 @@ static void wl_data_source_listener_cancelled(void* data, wl_data_source_offer(self->wayland.clipboard_source.wl, "TEXT"); wl_data_source_offer(self->wayland.clipboard_source.wl, "STRING"); wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/uri-list"); wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self); @@ -348,7 +424,7 @@ struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_ /* wl_data_device_manager setup function */ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { (void)version; - wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 2); + wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 3); wayland->clipboard_source.wl = wl_data_device_manager_create_data_source(wayland->clipboard_manager.wl); @@ -357,6 +433,7 @@ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLL wl_data_source_offer(wayland->clipboard_source.wl, "TEXT"); wl_data_source_offer(wayland->clipboard_source.wl, "STRING"); wl_data_source_offer(wayland->clipboard_source.wl, "UTF8_STRING"); + wl_data_source_offer(wayland->clipboard_source.wl, "text/uri-list"); wl_data_source_add_listener(wayland->clipboard_source.wl, &wl_data_source_listener, wayland); @@ -1040,6 +1117,13 @@ static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat) { device_ctx_zwp->ll = self; zwp_primary_selection_device_v1_add_listener(device_ctx_zwp->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx_zwp); arrpush(self->wayland.clipboard_devices_zwp, device_ctx_zwp); + + device_ctx_zwp->accepted_types[0] = "text/plain"; + device_ctx_zwp->accepted_types[1] = "text/plain;charset=utf-8"; + device_ctx_zwp->accepted_types[2] = "TEXT"; + device_ctx_zwp->accepted_types[3] = "STRING"; + device_ctx_zwp->accepted_types[4] = "UTF8_STRING"; + device_ctx_zwp->accepted_types[5] = "text/uri-list"; } static void setup_clipboard(MwLL self, struct wl_seat* wl_seat) { wl_clipboard_device_context_t* device_ctx_wl = malloc(sizeof(wl_clipboard_device_context_t)); @@ -1050,6 +1134,13 @@ static void setup_clipboard(MwLL self, struct wl_seat* wl_seat) { wl_data_device_add_listener(device_ctx_wl->device.wl, &wl_data_device_listener, device_ctx_wl); arrpush(self->wayland.clipboard_devices_wl, device_ctx_wl); + + device_ctx_wl->accepted_types[0] = "text/plain"; + device_ctx_wl->accepted_types[1] = "text/plain;charset=utf-8"; + device_ctx_wl->accepted_types[2] = "TEXT"; + device_ctx_wl->accepted_types[3] = "STRING"; + device_ctx_wl->accepted_types[4] = "UTF8_STRING"; + device_ctx_wl->accepted_types[5] = "text/uri-list"; }; static void keyboard_repeat_info(void* data,