WINGs/wview_wl: implement internal DnD for Wayland

Implement wl_drag_begin as a simple internal drag-and-drop state machine
for WINGs-to-WINGs drag operations (color wells, text widgets).

On button press, waits for motion to confirm drag intent, then enters
a drag loop tracking the cursor. On release, finds the view under the
cursor and if it has drag destination procs + matching types, fetches
data from the source and calls performDragOperation on the destination.

This handles same-process DnD without needing wl_data_device protocol.
This commit is contained in:
Ollie 2026-05-23 19:07:54 +02:00
parent 1c96a93ac8
commit a438713b92
1 changed files with 63 additions and 1 deletions

View File

@ -555,7 +555,69 @@ static void wl_balloon_draw(void *vctx, W_View *view, int x, int y,
static void wl_drag_begin(void *vctx, W_View *view, WMEvent *event)
{
(void)vctx; (void)view; (void)event;
W_Screen *scr = (W_Screen *)vctx;
if (!view->dragSourceProcs || event->type != WME_BUTTON_PRESS)
return;
/* Wait for motion to confirm drag */
WMEvent ev;
WMMaskEvent(scr, ButtonMotionMask | ButtonReleaseMask, &ev);
if (ev.type != WME_MOTION)
return;
if (view->dragSourceProcs->beganDrag) {
WMPoint pt = wmkpoint(ev.u.motion.x_root, ev.u.motion.y_root);
view->dragSourceProcs->beganDrag(view, &pt);
}
/* Drag loop */
W_View *destView = NULL;
Bool deposited = False;
int done = 0;
while (!done) {
WMMaskEvent(scr, ButtonMotionMask | ButtonReleaseMask, &ev);
switch (ev.type) {
case WME_MOTION:
/* Find view under cursor */
{
W_View *top = scr->rootView;
int mx = ev.u.motion.x_root;
int my = ev.u.motion.y_root;
destView = W_FindViewAtPoint(top, mx, my);
}
break;
case WME_BUTTON_RELEASE:
if (destView && destView->dragDestinationProcs &&
destView->droppableTypes && view->dragSourceProcs->dropDataTypes) {
WMArray *types = view->dragSourceProcs->dropDataTypes(view);
WMArray *dropData = WMCreateArray(WMGetArrayItemCount(types));
int i;
for (i = 0; i < WMGetArrayItemCount(types); i++) {
char *type = WMGetFromArray(types, i);
WMData *data = view->dragSourceProcs->fetchDragData(view, type);
if (data)
WMAddToArray(dropData, data);
}
if (WMGetArrayItemCount(dropData) > 0 &&
destView->dragDestinationProcs->performDragOperation) {
WMPoint pt = wmkpoint(ev.u.button.x_root, ev.u.button.y_root);
destView->dragDestinationProcs->performDragOperation(
destView, dropData, NULL, &pt);
deposited = True;
}
WMFreeArray(dropData);
}
done = 1;
break;
}
}
if (view->dragSourceProcs->endedDrag) {
WMPoint pt = wmkpoint(ev.u.button.x_root, ev.u.button.y_root);
view->dragSourceProcs->endedDrag(view, &pt, deposited);
}
}
static void wl_flush(void *vctx)