WIP: UI: Add Drag & Drop Feedback on Windows #107056

Draft
Guillermo Venegas wants to merge 3 commits from guishe/blender:drag-and-drop-update into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
6 changed files with 328 additions and 269 deletions
Showing only changes of commit a402e5c94d - Show all commits

View File

@ -21,4 +21,8 @@ add_definitions(
-DHAVE_SYS_TIME_H
)
if(WITH_INPUT_NDOF)
add_definitions(-DWITH_INPUT_NDOF)
endif()
blender_add_lib(extern_xdnd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")

432
extern/xdnd/xdnd.c vendored
View File

@ -627,7 +627,7 @@ static void xdnd_send_status (DndClass * dnd, Window window, Window from, int wi
xevent.xany.display = dnd->display;
xevent.xclient.window = window;
xevent.xclient.message_type = dnd->XdndStatus;
xevent.xclient.format = 32;
xevent.xclient.format = 32;
XDND_STATUS_TARGET_WIN (&xevent) = from;
XDND_STATUS_WILL_ACCEPT_SET (&xevent, will_accept);
@ -1254,183 +1254,6 @@ Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist)
return result;
}
/* returns non-zero if event is handled */
int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent)
{
int result = 0;
if (xevent->type == SelectionNotify) {
dnd_debug1 ("got SelectionNotify");
if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM && dnd->stage == XDND_DROP_STAGE_CONVERTING) {
int error;
dnd_debug1 (" property is Xdnd_NON_PROTOCOL_ATOM - getting selection");
error = xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);
/* error is not actually used, i think future versions of the protocol maybe should return
an error status to the calling window with the XdndFinished client message */
if (dnd_version_at_least (dnd->dragging_version, 2)) {
#if XDND_VERSION >= 3
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, error);
#else
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_window, error);
#endif
dnd_debug1 (" sending finished");
}
xdnd_xfree (dnd->dragger_typelist);
xdnd_reset (dnd);
dnd->stage = XDND_DROP_STAGE_IDLE;
result = 1;
} else {
dnd_debug1 (" property is not Xdnd_NON_PROTOCOL_ATOM - ignoring");
}
} else if (xevent->type == ClientMessage) {
dnd_debug2 ("got ClientMessage to xevent->xany.window = %ld", xevent->xany.window);
if (xevent->xclient.message_type == dnd->XdndEnter) {
dnd_debug2 (" message_type is XdndEnter, version = %ld", XDND_ENTER_VERSION (xevent));
#if XDND_VERSION >= 3
if (XDND_ENTER_VERSION (xevent) < 3)
return 0;
#endif
xdnd_reset (dnd);
dnd->dragger_window = XDND_ENTER_SOURCE_WIN (xevent);
#if XDND_VERSION >= 3
dnd->dropper_toplevel = xevent->xany.window;
dnd->dropper_window = 0; /* enter goes to the top level window only,
so we don't really know what the
sub window is yet */
#else
dnd->dropper_window = xevent->xany.window;
#endif
xdnd_xfree (dnd->dragger_typelist);
if (XDND_ENTER_THREE_TYPES (xevent)) {
dnd_debug1 (" three types only");
xdnd_get_three_types (dnd, xevent, &dnd->dragger_typelist);
} else {
dnd_debug1 (" more than three types - getting list");
xdnd_get_type_list (dnd, dnd->dragger_window, &dnd->dragger_typelist);
}
if (dnd->dragger_typelist)
dnd->stage = XDND_DROP_STAGE_ENTERED;
else
dnd_debug1 (" typelist returned as zero!");
dnd->dragging_version = XDND_ENTER_VERSION (xevent);
result = 1;
} else if (xevent->xclient.message_type == dnd->XdndLeave) {
#if XDND_VERSION >= 3
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
xevent->xany.window = dnd->dropper_window;
#endif
dnd_debug1 (" message_type is XdndLeave");
if (dnd->dragger_window == XDND_LEAVE_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
dnd_debug1 (" leaving");
if (dnd->widget_apply_leave)
(*dnd->widget_apply_leave) (dnd, xevent->xany.window);
dnd->stage = XDND_DROP_STAGE_IDLE;
xdnd_xfree (dnd->dragger_typelist);
result = 1;
dnd->dropper_toplevel = dnd->dropper_window = 0;
} else {
dnd_debug1 (" wrong stage or from wrong window");
}
} else if (xevent->xclient.message_type == dnd->XdndPosition) {
dnd_debug2 (" message_type is XdndPosition to %ld", xevent->xany.window);
if (dnd->dragger_window == XDND_POSITION_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
int want_position;
Atom action;
XRectangle rectangle;
Window last_window;
last_window = dnd->dropper_window;
#if XDND_VERSION >= 3
/* version 3 gives us the top-level window only. WE have to find the child that the pointer is over: */
if (1 || xevent->xany.window != dnd->dropper_toplevel || !dnd->dropper_window) {
Window parent, child, new_child = 0;
dnd->dropper_toplevel = xevent->xany.window;
parent = dnd->root_window;
child = dnd->dropper_toplevel;
for (;;) {
int xd, yd;
new_child = 0;
if (!XTranslateCoordinates (dnd->display, parent, child,
XDND_POSITION_ROOT_X (xevent), XDND_POSITION_ROOT_Y (xevent),
&xd, &yd, &new_child))
break;
if (!new_child)
break;
child = new_child;
}
dnd->dropper_window = xevent->xany.window = child;
dnd_debug2 (" child window translates to %ld", dnd->dropper_window);
} else if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) {
xevent->xany.window = dnd->dropper_window;
dnd_debug2 (" child window previously found: %ld", dnd->dropper_window);
}
#endif
action = dnd->XdndActionCopy;
dnd->supported_action = dnd->XdndActionCopy;
dnd->x = XDND_POSITION_ROOT_X (xevent);
dnd->y = XDND_POSITION_ROOT_Y (xevent);
dnd->time = CurrentTime;
if (dnd_version_at_least (dnd->dragging_version, 1))
dnd->time = XDND_POSITION_TIME (xevent);
if (dnd_version_at_least (dnd->dragging_version, 1))
action = XDND_POSITION_ACTION (xevent);
#if XDND_VERSION >= 3
if (last_window && last_window != xevent->xany.window)
if (dnd->widget_apply_leave)
(*dnd->widget_apply_leave) (dnd, last_window);
#endif
dnd->will_accept = (*dnd->widget_apply_position) (dnd, xevent->xany.window, dnd->dragger_window,
action, dnd->x, dnd->y, dnd->time, dnd->dragger_typelist,
&want_position, &dnd->supported_action, &dnd->desired_type, &rectangle);
dnd_debug2 (" will accept = %d", dnd->will_accept);
#if XDND_VERSION >= 3
dnd_debug2 (" sending status of %ld", dnd->dropper_toplevel);
xdnd_send_status (dnd, dnd->dragger_window, dnd->dropper_toplevel, dnd->will_accept,
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
#else
dnd_debug2 (" sending status of %ld", xevent->xany.window);
xdnd_send_status (dnd, dnd->dragger_window, xevent->xany.window, dnd->will_accept,
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
#endif
result = 1;
} else {
dnd_debug1 (" wrong stage or from wrong window");
}
} else if (xevent->xclient.message_type == dnd->XdndDrop) {
#if XDND_VERSION >= 3
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
xevent->xany.window = dnd->dropper_window;
#endif
dnd_debug1 (" message_type is XdndDrop");
if (dnd->dragger_window == XDND_DROP_SOURCE_WIN (xevent) && dnd->stage == XDND_DROP_STAGE_ENTERED) {
dnd->time = CurrentTime;
if (dnd_version_at_least (dnd->dragging_version, 1))
dnd->time = XDND_DROP_TIME (xevent);
if (dnd->will_accept) {
dnd_debug1 (" will_accept is true - converting selectiong");
dnd_debug2 (" my window is %ld", dnd->dropper_window);
dnd_debug2 (" source window is %ld", dnd->dragger_window);
xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type);
dnd->stage = XDND_DROP_STAGE_CONVERTING;
} else {
dnd_debug1 (" will_accept is false - sending finished");
if (dnd_version_at_least (dnd->dragging_version, 2)) {
#if XDND_VERSION >= 3
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, 1);
#else
xdnd_send_finished (dnd, dnd->dragger_window, xevent->xany.window, 1);
#endif
}
xdnd_xfree (dnd->dragger_typelist);
xdnd_reset (dnd);
dnd->stage = XDND_DROP_STAGE_IDLE;
}
result = 1;
} else {
dnd_debug1 (" wrong stage or from wrong window");
}
}
}
return result;
}
/*
Following here is a sample implementation: Suppose we want a window
@ -1550,50 +1373,241 @@ static int widget_apply_position (DndClass * dnd, Window widgets_window, Window
return 1;
}
Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
void handle_update(DndClass * dnd, XEvent * xevent){
dnd_debug2 (" message_type is XdndPosition to %ld", xevent->xany.window);
if (dnd->dragger_window == XDND_POSITION_SOURCE_WIN (xevent)) {
int want_position;
Atom action;
XRectangle rectangle;
Window last_window;
last_window = dnd->dropper_window;
#if XDND_VERSION >= 3
/* version 3 gives us the top-level window only. WE have to find the child that the pointer is over: */
if (1 || xevent->xany.window != dnd->dropper_toplevel || !dnd->dropper_window) {
Window parent, child, new_child = 0;
dnd->dropper_toplevel = xevent->xany.window;
parent = dnd->root_window;
child = dnd->dropper_toplevel;
for (;;) {
int xd, yd;
new_child = 0;
if (!XTranslateCoordinates (dnd->display, parent, child,
XDND_POSITION_ROOT_X (xevent), XDND_POSITION_ROOT_Y (xevent),
&xd, &yd, &new_child))
break;
if (!new_child)
break;
child = new_child;
}
dnd->dropper_window = xevent->xany.window = child;
dnd_debug2 (" child window translates to %ld", dnd->dropper_window);
} else if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window) {
xevent->xany.window = dnd->dropper_window;
dnd_debug2 (" child window previously found: %ld", dnd->dropper_window);
}
#endif
action = dnd->XdndActionCopy;
dnd->supported_action = dnd->XdndActionCopy;
dnd->x = XDND_POSITION_ROOT_X (xevent);
dnd->y = XDND_POSITION_ROOT_Y (xevent);
dnd->time = CurrentTime;
if (dnd_version_at_least (dnd->dragging_version, 1))
dnd->time = XDND_POSITION_TIME (xevent);
if (dnd_version_at_least (dnd->dragging_version, 1))
action = XDND_POSITION_ACTION (xevent);
#if XDND_VERSION >= 3
if (last_window && last_window != xevent->xany.window)
if (dnd->widget_apply_leave)
(*dnd->widget_apply_leave) (dnd, last_window);
#endif
dnd->will_accept = (*dnd->widget_apply_position) (dnd, xevent->xany.window, dnd->dragger_window,
action, dnd->x, dnd->y, dnd->time, dnd->dragger_typelist,
&want_position, &dnd->supported_action, &dnd->desired_type, &rectangle);
dnd_debug2 (" will accept = %d", dnd->will_accept);
#if XDND_VERSION >= 3
dnd_debug2 (" sending status of %ld", dnd->dropper_toplevel);
xdnd_send_status (dnd, dnd->dragger_window, dnd->dropper_toplevel, dnd->will_accept,
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
#else
dnd_debug2 (" sending status of %ld", xevent->xany.window);
xdnd_send_status (dnd, dnd->dragger_window, xevent->xany.window, dnd->will_accept,
want_position, rectangle.x, rectangle.y, rectangle.width, rectangle.height, dnd->supported_action);
#endif
} else {
dnd_debug1 (" wrong stage or from wrong window");
}
}
void handle_enter(DndClass * dnd, XEvent * xevent){
dnd_debug2 (" message_type is XdndEnter, version = %ld", XDND_ENTER_VERSION (xevent));
#if XDND_VERSION >= 3
if (XDND_ENTER_VERSION (xevent) < 3)
return;
#endif
xdnd_reset (dnd);
dnd->dragger_window = XDND_ENTER_SOURCE_WIN (xevent);
#if XDND_VERSION >= 3
dnd->dropper_toplevel = xevent->xany.window;
dnd->dropper_window = 0; /* enter goes to the top level window only,
so we don't really know what the
sub window is yet */
#else
dnd->dropper_window = xevent->xany.window;
#endif
xdnd_xfree (dnd->dragger_typelist);
if (XDND_ENTER_THREE_TYPES (xevent)) {
dnd_debug1 (" three types only");
xdnd_get_three_types (dnd, xevent, &dnd->dragger_typelist);
} else {
dnd_debug1 (" more than three types - getting list");
xdnd_get_type_list (dnd, dnd->dragger_window, &dnd->dragger_typelist);
}
dnd->dragging_version = XDND_ENTER_VERSION (xevent);
if (!dnd->dragger_typelist){
return;
}
for (;xevent->xclient.message_type != dnd->XdndPosition;)
{
XNextEvent(dnd->display, xevent);
}
handle_update(dnd, xevent);
/* Send request for obtain selection data. */
xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type);
/* Wait to receive selection. */
for (;xevent->type != SelectionNotify;)
{
XNextEvent(dnd->display, xevent);
}
if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM ) {
xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);
}
}
void handle_exit(DndClass * dnd, XEvent * xevent){
#if XDND_VERSION >= 3
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
xevent->xany.window = dnd->dropper_window;
#endif
dnd_debug1 (" message_type is XdndLeave");
if (dnd->dragger_window == XDND_LEAVE_SOURCE_WIN (xevent) ) {
dnd_debug1 (" leaving");
if (dnd->widget_apply_leave)
(*dnd->widget_apply_leave) (dnd, xevent->xany.window);
xdnd_xfree (dnd->dragger_typelist);
dnd->dropper_toplevel = dnd->dropper_window = 0;
} else {
dnd_debug1 (" wrong stage or from wrong window");
}
}
void handle_drop(DndClass * dnd, XEvent * xevent){
#if XDND_VERSION >= 3
if (xevent->xany.window == dnd->dropper_toplevel && dnd->dropper_window)
xevent->xany.window = dnd->dropper_window;
#endif
dnd_debug1 (" message_type is XdndDrop");
if (dnd->dragger_window == XDND_DROP_SOURCE_WIN (xevent)) {
dnd->time = CurrentTime;
if (dnd_version_at_least (dnd->dragging_version, 1))
dnd->time = XDND_DROP_TIME (xevent);
if (dnd->will_accept) {
dnd_debug1 (" will_accept is true - converting selectiong");
dnd_debug2 (" my window is %ld", dnd->dropper_window);
dnd_debug2 (" source window is %ld", dnd->dragger_window);
xdnd_convert_selection (dnd, dnd->dragger_window, dnd->dropper_window, dnd->desired_type);
} else {
dnd_debug1 (" will_accept is false - sending finished");
if (dnd_version_at_least (dnd->dragging_version, 2)) {
#if XDND_VERSION >= 3
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, 1);
#else
xdnd_send_finished (dnd, dnd->dragger_window, xevent->xany.window, 1);
#endif
}
xdnd_xfree (dnd->dragger_typelist);
xdnd_reset (dnd);
}
} else {
dnd_debug1 (" wrong stage or from wrong window");
}
/* Wait to receive selection. */
for (;xevent->type != SelectionNotify;)
{
XNextEvent(dnd->display, xevent);
}
if (xevent->xselection.property == dnd->Xdnd_NON_PROTOCOL_ATOM ) {
int error;
dnd_debug1 (" property is Xdnd_NON_PROTOCOL_ATOM - getting selection");
error = xdnd_get_selection (dnd, dnd->dragger_window, xevent->xselection.property, xevent->xany.window);
/* error is not actually used, i think future versions of the protocol maybe should return
an error status to the calling window with the XdndFinished client message */
if (dnd_version_at_least (dnd->dragging_version, 2)) {
#if XDND_VERSION >= 3
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_toplevel, error);
#else
xdnd_send_finished (dnd, dnd->dragger_window, dnd->dropper_window, error);
#endif
dnd_debug1 (" sending finished");
}
xdnd_xfree (dnd->dragger_typelist);
xdnd_reset (dnd);
}
}
GHOST_TEventType xdnd_handle_event (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
unsigned char **data, int *length, Atom * type, int *x, int *y)
{
Atom action = 0;
GHOST_TEventType event_type = 0;
static int initialised = 0;
static DndClass dnd;
if (!initialised) {
xdnd_init (&dnd, display);
if (!initialised)
{
xdnd_init(&dnd, display);
initialised = 1;
}
if (xevent->type != ClientMessage || xevent->xclient.message_type != dnd.XdndEnter) {
if (xevent->type != ClientMessage)
{
return 0;
} else {
struct xdnd_get_drop_info i;
/* setup user structure */
memset (&i, 0, sizeof (i));
}
static struct xdnd_get_drop_info i;
if (xevent->xclient.message_type == dnd.XdndEnter)
{
/* setup user structure */
memset(&i, 0, sizeof(i));
i.actionlist = actionlist;
i.typelist = typelist;
dnd.user_hook1 = &i;
/* setup methods */
/* setup methods */
dnd.widget_insert_drop = widget_insert_drop;
dnd.widget_apply_position = widget_apply_position;
/* main loop */
for (;;) {
xdnd_handle_drop_events (&dnd, xevent);
if (dnd.stage == XDND_DROP_STAGE_IDLE)
break;
XNextEvent (dnd.display, xevent);
}
/* return results */
if (i.drop_data) {
*length = i.drop_data_length;
*data = i.drop_data;
action = i.return_action;
*type = i.return_type;
*x = i.x;
*y = i.y;
}
event_type = GHOST_kEventDraggingEntered;
handle_enter(&dnd, xevent);
}
return action;
else if (xevent->xclient.message_type == dnd.XdndPosition)
{
event_type = GHOST_kEventDraggingUpdated;
handle_update(&dnd, xevent);
}
else if (xevent->xclient.message_type == dnd.XdndDrop)
{
event_type = GHOST_kEventDraggingDropDone;
handle_drop(&dnd, xevent);
}
else if (xevent->xclient.message_type == dnd.XdndLeave)
{
event_type = GHOST_kEventDraggingExited;
handle_exit(&dnd, xevent);
}
/* return results */
*length = i.drop_data_length;
i.drop_data_length=0;
*data = i.drop_data;
/* data wil be free outside */
i.drop_data=NULL;
*type = i.return_type;
*x = i.x;
*y = i.y;
return event_type;
}

4
extern/xdnd/xdnd.h vendored
View File

@ -16,7 +16,7 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
*/
#include "../../intern/ghost/GHOST_Types.h"
#ifndef _X_DND_H
#define _X_DND_H
@ -208,7 +208,7 @@ Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist);
libraries main event loop and be called if the event type is
ClientMessage or SelectionNotify */
int xdnd_handle_drop_events (DndClass * dnd, XEvent * xevent);
Atom xdnd_get_drop (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
GHOST_TEventType xdnd_handle_event (Display * display, XEvent * xevent, Atom * typelist, Atom * actionlist,
unsigned char **data, int *length, Atom * type, int *x, int *y);

View File

@ -81,12 +81,13 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *p_data_object,
DWORD *pdw_effect)
{
/* We accept all drop by default. */
void *data = getGhostData(p_data_object);
m_window->setAcceptDragOperation(true);
*pdw_effect = DROPEFFECT_NONE;
m_draggedObjectType = getGhostType(p_data_object);
m_system->pushDragDropEvent(
GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, NULL);
GHOST_kEventDraggingEntered, m_draggedObjectType, m_window, pt.x, pt.y, data);
return S_OK;
}

View File

@ -202,24 +202,25 @@ bool GHOST_DropTargetX11::GHOST_HandleClientMessage(XEvent *event)
uchar *dropBuffer;
int dropBufferSize, dropX, dropY;
if (xdnd_get_drop(m_system->getXDisplay(),
event,
m_dndTypes,
m_dndActions,
&dropBuffer,
&dropBufferSize,
&dropType,
&dropX,
&dropY)) {
void *data = getGhostData(dropType, dropBuffer, dropBufferSize);
GHOST_TEventType event_type = xdnd_handle_event(m_system->getXDisplay(),
event,
m_dndTypes,
m_dndActions,
&dropBuffer,
&dropBufferSize,
&dropType,
&dropX,
&dropY);
if (event_type > 0) {
if (data) {
m_system->pushDragDropEvent(
GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, dropX, dropY, data);
void *data = nullptr;
if (dropBufferSize > 0) {
data = getGhostData(dropType, dropBuffer, dropBufferSize);
}
m_system->pushDragDropEvent(event_type, m_draggedObjectType, m_window, dropX, dropY, data);
if (dropBufferSize > 0) {
free(dropBuffer);
}
free(dropBuffer);
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
return true;

View File

@ -1192,6 +1192,39 @@ void wm_window_reset_drawable(void)
}
}
void update_mouse_position_from_draganddrop(wmWindowManager *wm,
wmWindow *win,
wmEvent *event,
GHOST_TEventDragnDropData *ddd)
{
/* Ensure the event state matches modifiers (window was inactive). */
wm_window_update_eventstate_modifiers(wm, win);
/* Entering window, update mouse position (without sending an event). */
wm_window_update_eventstate(win);
wm_event_init_from_window(win, event); /* copy last state, like mouse coords */
/* activate region */
event->type = MOUSEMOVE;
event->val = KM_NOTHING;
copy_v2_v2_int(event->prev_xy, event->xy);
wm_cursor_position_from_ghost_screen_coords(win, &ddd->x, &ddd->y);
event->xy[0] = ddd->x;
event->xy[1] = ddd->y;
/* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't)
* Write this into the event state. */
copy_v2_v2_int(win->eventstate->xy, event->xy);
event->flag = 0;
/* No context change! `C->wm->windrawable` is drawable, or for area queues. */
wm->winactive = win;
win->active = 1;
wm_event_add(win, event);
}
/**
* Called by ghost, here we handle events for windows themselves or send to event system.
*
@ -1439,51 +1472,15 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
}
break;
}
case GHOST_kEventDraggingDropDone: {
case GHOST_kEventDraggingEntered: {
WM_drag_free_list(&wm->drags);
wm_drags_exit(wm, win);
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
/* Ensure the event state matches modifiers (window was inactive). */
wm_window_update_eventstate_modifiers(wm, win);
/* Entering window, update mouse position (without sending an event). */
wm_window_update_eventstate(win);
wmEvent event;
wm_event_init_from_window(win, &event); /* copy last state, like mouse coords */
/* activate region */
event.type = MOUSEMOVE;
event.val = KM_NOTHING;
copy_v2_v2_int(event.prev_xy, event.xy);
wm_cursor_position_from_ghost_screen_coords(win, &ddd->x, &ddd->y);
event.xy[0] = ddd->x;
event.xy[1] = ddd->y;
/* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't)
* Write this into the event state. */
copy_v2_v2_int(win->eventstate->xy, event.xy);
event.flag = 0;
/* No context change! `C->wm->windrawable` is drawable, or for area queues. */
wm->winactive = win;
win->active = 1;
wm_event_add(win, &event);
/* make blender drop event with custom data pointing to wm drags */
event.type = EVT_DROP;
event.val = KM_RELEASE;
event.custom = EVT_DATA_DRAGDROP;
event.customdata = &wm->drags;
event.customdata_free = true;
wm_event_add(win, &event);
// printf("Drop detected\n");
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
/* add drag data to wm for paths: */
if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
GHOST_TStringArray *stra = ddd->data;
@ -1496,9 +1493,51 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt
break; /* only one drop element supported now */
}
}
break;
}
case GHOST_kEventDraggingUpdated: {
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
wmEvent event;
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
break;
}
case GHOST_kEventDraggingDropDone: {
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
wmEvent event;
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
/* make blender drop event with custom data pointing to wm drags */
event.type = EVT_DROP;
event.val = KM_RELEASE;
event.custom = EVT_DATA_DRAGDROP;
event.customdata = &wm->drags;
event.customdata_free = true;
wm_event_add(win, &event);
if (wm->drags.first != NULL && ddd->dataType == GHOST_kDragnDropTypeFilenames) {
GHOST_TStringArray *stra = ddd->data;
if (stra->count > 0) {
/* try to get icon type from extension */
int icon = ED_file_extension_icon((char *)stra->strings[0]);
wmDragPath *path_data = WM_drag_create_path_data((char **)stra->strings, stra->count);
WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, 0.0, WM_DRAG_NOP);
/* void poin should point to string, it makes a copy */
break; /* only one drop element supported now */
}
}
break;
}
case GHOST_kEventDraggingExited: {
WM_drag_free_list(&wm->drags);
wm_drags_exit(wm, win);
GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
wmEvent event;
update_mouse_position_from_draganddrop(wm, win, &event, ddd);
break;
}
case GHOST_kEventNativeResolutionChange: {
/* Only update if the actual pixel size changes. */
float prev_pixelsize = U.pixelsize;