diff --git a/extern/xdnd/CMakeLists.txt b/extern/xdnd/CMakeLists.txt index 9133fb14feb..0aae9a5c2a1 100644 --- a/extern/xdnd/CMakeLists.txt +++ b/extern/xdnd/CMakeLists.txt @@ -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}") diff --git a/extern/xdnd/xdnd.c b/extern/xdnd/xdnd.c index e8c51377e27..76048926007 100644 --- a/extern/xdnd/xdnd.c +++ b/extern/xdnd/xdnd.c @@ -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; } - - diff --git a/extern/xdnd/xdnd.h b/extern/xdnd/xdnd.h index c903b51c8d0..506ba2b9ee2 100644 --- a/extern/xdnd/xdnd.h +++ b/extern/xdnd/xdnd.h @@ -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); diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cc b/intern/ghost/intern/GHOST_DropTargetWin32.cc index b21bd5fabad..9f4d42390e8 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cc +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cc @@ -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; } diff --git a/intern/ghost/intern/GHOST_DropTargetX11.cc b/intern/ghost/intern/GHOST_DropTargetX11.cc index f3b42a1da93..31fa5f9a970 100644 --- a/intern/ghost/intern/GHOST_DropTargetX11.cc +++ b/intern/ghost/intern/GHOST_DropTargetX11.cc @@ -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; diff --git a/source/blender/editors/interface/interface_drag.cc b/source/blender/editors/interface/interface_drag.cc index fc478ac106d..d8e161c9541 100644 --- a/source/blender/editors/interface/interface_drag.cc +++ b/source/blender/editors/interface/interface_drag.cc @@ -70,7 +70,7 @@ void UI_but_drag_set_path(uiBut *but, const char *path) if (but->dragflag & UI_BUT_DRAGPOIN_FREE) { WM_drag_data_free(but->dragtype, but->dragpoin); } - but->dragpoin = WM_drag_create_path_data(path); + but->dragpoin = WM_drag_create_path_data(&path, 1); but->dragflag |= UI_BUT_DRAGPOIN_FREE; } diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index e5368b6a792..c78a9b8b428 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC_SYS ) set(SRC + io_utils.c io_alembic.c io_cache.c io_collada.c @@ -38,6 +39,7 @@ set(SRC io_stl_ops.c io_usd.c + io_utils.h io_alembic.h io_cache.h io_collada.h diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c index cf20f4bc768..7e1dd882279 100644 --- a/source/blender/editors/io/io_obj.c +++ b/source/blender/editors/io/io_obj.c @@ -38,6 +38,7 @@ # include "IO_path_util_types.h" # include "IO_wavefront_obj.h" # include "io_obj.h" +# include "io_utils.h" static const EnumPropertyItem io_obj_export_evaluation_mode[] = { {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"}, @@ -370,12 +371,6 @@ void WM_OT_obj_export(struct wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } -static int wm_obj_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - WM_event_add_fileselect(C, op); - return OPERATOR_RUNNING_MODAL; -} - static int wm_obj_import_exec(bContext *C, wmOperator *op) { struct OBJImportParams import_params; @@ -457,6 +452,7 @@ static void wm_obj_import_draw(bContext *C, wmOperator *op) PointerRNA ptr; wmWindowManager *wm = CTX_wm_manager(C); RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + files_drop_info_draw(C, op, ICON_FILE_3D); ui_obj_import_settings(op->layout, &ptr); } @@ -467,9 +463,9 @@ void WM_OT_obj_import(struct wmOperatorType *ot) ot->name = "Import Wavefront OBJ"; ot->description = "Load a Wavefront OBJ scene"; ot->idname = "WM_OT_obj_import"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_PRESET; + ot->flag = OPTYPE_UNDO | OPTYPE_PRESET; - ot->invoke = wm_obj_import_invoke; + ot->invoke = wm_io_import_invoke; ot->exec = wm_obj_import_exec; ot->poll = WM_operator_winactive; ot->ui = wm_obj_import_draw; @@ -482,6 +478,7 @@ void WM_OT_obj_import(struct wmOperatorType *ot) WM_FILESEL_DIRECTORY | WM_FILESEL_FILES, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); + skip_save_import_paths_props(ot, WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILES); RNA_def_float( ot->srna, "global_scale", @@ -533,4 +530,22 @@ void WM_OT_obj_import(struct wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN); } +bool obj_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) +{ + if (drag->type == WM_DRAG_PATH) { + const eFileSel_File_Types file_type = WM_drag_get_path_file_type(drag); + if (file_type == FILE_TYPE_OBJECT_IO && + BLI_path_extension_check(WM_drag_get_paths(drag)[0], ".obj")) { + return true; + } + } + return false; +} + +void WM_obj_dropbox_add() +{ + ListBase *lb = WM_dropboxmap_find("Window", 0, 0); + WM_dropbox_add(lb, "WM_OT_obj_import", obj_file_drop_poll, files_drop_copy, NULL, NULL); +} + #endif /* WITH_IO_WAVEFRONT_OBJ */ diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h index 30857b33f21..3b6cdc3cc1e 100644 --- a/source/blender/editors/io/io_obj.h +++ b/source/blender/editors/io/io_obj.h @@ -10,3 +10,4 @@ struct wmOperatorType; void WM_OT_obj_export(struct wmOperatorType *ot); void WM_OT_obj_import(struct wmOperatorType *ot); +void WM_obj_dropbox_add(); diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index d8c4d140ad2..e01c32ec5a0 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -33,18 +33,22 @@ void ED_operatortypes_io(void) /* Collada operators: */ WM_operatortype_append(WM_OT_collada_export); WM_operatortype_append(WM_OT_collada_import); + // WM_collada_dropbox_add(); #endif #ifdef WITH_ALEMBIC WM_operatortype_append(WM_OT_alembic_import); WM_operatortype_append(WM_OT_alembic_export); + // WM_alembic_dropbox_add(); #endif #ifdef WITH_USD WM_operatortype_append(WM_OT_usd_import); WM_operatortype_append(WM_OT_usd_export); + // WM_usd_dropbox_add(); #endif #ifdef WITH_IO_GPENCIL WM_operatortype_append(WM_OT_gpencil_import_svg); + // WM_gpencil_dropbox_add(); # ifdef WITH_PUGIXML WM_operatortype_append(WM_OT_gpencil_export_svg); # endif @@ -63,14 +67,17 @@ void ED_operatortypes_io(void) #ifdef WITH_IO_WAVEFRONT_OBJ WM_operatortype_append(WM_OT_obj_export); WM_operatortype_append(WM_OT_obj_import); + WM_obj_dropbox_add(); #endif #ifdef WITH_IO_PLY WM_operatortype_append(WM_OT_ply_export); WM_operatortype_append(WM_OT_ply_import); + // WM_ply_dropbox_add(); #endif #ifdef WITH_IO_STL WM_operatortype_append(WM_OT_stl_import); + // WM_stl_dropbox_add(); #endif } diff --git a/source/blender/editors/io/io_utils.c b/source/blender/editors/io/io_utils.c new file mode 100644 index 00000000000..2bfd8766d41 --- /dev/null +++ b/source/blender/editors/io/io_utils.c @@ -0,0 +1,106 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#if defined(WITH_COLLADA) || defined(WITH_IO_GPENCIL) || defined(WITH_IO_WAVEFRONT_OBJ) || \ + defined(WITH_IO_PLY) || defined(WITH_IO_STL) || defined(WITH_USD) + +# include "DNA_space_types.h" + +# include "BKE_context.h" + +# include "BLI_path_util.h" +# include "BLI_string.h" +# include "BLI_utildefines.h" +# include "BLT_translation.h" + +# include "ED_fileselect.h" + +# include "RNA_access.h" +# include "RNA_define.h" + +# include "UI_interface.h" + +# include "WM_api.h" +# include "io_utils.h" + +int wm_io_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + if (filepath[0]) { + return WM_operator_props_dialog_popup(C, op, 300); + } + WM_event_add_fileselect(C, op); + return OPERATOR_RUNNING_MODAL; +} + +void skip_save_import_paths_props(wmOperatorType *ot, const eFileSel_Flag flag) +{ + if (flag & WM_FILESEL_FILEPATH) { + RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "filepath"), PROP_SKIP_SAVE); + } + if (flag & WM_FILESEL_FILENAME) { + RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "filename"), PROP_SKIP_SAVE); + } + if (flag & WM_FILESEL_DIRECTORY) { + RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "directory"), PROP_SKIP_SAVE); + } + if (flag & WM_FILESEL_FILES) { + RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "files"), PROP_SKIP_SAVE); + } + if (flag & WM_FILESEL_RELPATH) { + RNA_def_property_flag(RNA_struct_type_find_property(ot->srna, "relative_path"), + PROP_SKIP_SAVE); + } +} + +void files_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) +{ + const char **paths = WM_drag_get_paths(drag); + RNA_string_set(drop->ptr, "filepath", paths[0]); + + char dir[FILE_MAX], file[FILE_MAX]; + BLI_split_dirfile(paths[0], dir, file, sizeof(dir), sizeof(file)); + + RNA_string_set(drop->ptr, "directory", dir); + RNA_collection_clear(drop->ptr, "files"); + + const int path_count = WM_drag_get_path_count(drag); + for (int i = 0; i < path_count; i++) { + BLI_split_dirfile(paths[i], dir, file, sizeof(dir), sizeof(file)); + PointerRNA itemptr; + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } +} + +void file_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) +{ + RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]); +} + +void file_drop_info_draw(bContext *C, wmOperator *op, int icon) +{ + ScrArea *area = CTX_wm_area(C); + if (area->spacetype != SPACE_FILE) { + char filepath[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filepath); + uiLayout *box = uiLayoutBox(op->layout); + uiItemL(box, filepath, icon); + } +} + +void files_drop_info_draw(bContext *C, wmOperator *op, int icon) +{ + ScrArea *area = CTX_wm_area(C); + if (area->spacetype != SPACE_FILE) { + char label[FILE_MAX] = "Multiple files selected."; + + if (RNA_collection_length(op->ptr, "files") == 1) { + RNA_string_get(op->ptr, "filepath", label); + } + uiLayout *box = uiLayoutBox(op->layout); + uiItemL(box, label, icon); + } +} + +#endif diff --git a/source/blender/editors/io/io_utils.h b/source/blender/editors/io/io_utils.h new file mode 100644 index 00000000000..efd2768a00b --- /dev/null +++ b/source/blender/editors/io/io_utils.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#if defined(WITH_COLLADA) || defined(WITH_IO_GPENCIL) || defined(WITH_IO_WAVEFRONT_OBJ) || \ + defined(WITH_IO_PLY) || defined(WITH_IO_STL) || defined(WITH_USD) + +# include "WM_types.h" + +struct wmOperator; +struct wmOperatorType; +struct wmDrag; +struct wmDropBox; + +int wm_io_import_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)); + +void skip_save_import_paths_props(wmOperatorType *ot, const eFileSel_Flag flag); + +void file_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop); +// Function that copies file directories for operators that support importing multiple files +void files_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop); + +void file_drop_info_draw(bContext *C, wmOperator *op, int icon); +// Function that summarizes file information for operators that support importing multiple files +void files_drop_info_draw(bContext *C, wmOperator *op, int icon); + +#endif diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index cc33c6b847c..e5ea6a2019d 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4564,7 +4564,7 @@ static void screen_animation_region_tag_redraw( ED_region_tag_redraw(region); } -//#define PROFILE_AUDIO_SYNCH +// #define PROFILE_AUDIO_SYNCH static int screen_animation_step_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { @@ -5756,7 +5756,7 @@ static bool blend_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEven static void blend_file_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { /* copy drag path to properties */ - RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag)); + RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]); } void ED_keymap_screen(wmKeyConfig *keyconf) diff --git a/source/blender/editors/space_clip/space_clip.cc b/source/blender/editors/space_clip/space_clip.cc index 5543730ec19..fd082e60b7b 100644 --- a/source/blender/editors/space_clip/space_clip.cc +++ b/source/blender/editors/space_clip/space_clip.cc @@ -527,7 +527,7 @@ static void clip_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *drop) PointerRNA itemptr; char dir[FILE_MAX], file[FILE_MAX]; - BLI_split_dirfile(WM_drag_get_path(drag), dir, file, sizeof(dir), sizeof(file)); + BLI_split_dirfile(WM_drag_get_paths(drag)[0], dir, file, sizeof(dir), sizeof(file)); RNA_string_set(drop->ptr, "directory", dir); diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index cf27155deb2..8283544d79f 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -172,7 +172,7 @@ static bool path_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNU static void path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { char pathname[FILE_MAX + 2]; - BLI_snprintf(pathname, sizeof(pathname), "\"%s\"", WM_drag_get_path(drag)); + BLI_snprintf(pathname, sizeof(pathname), "\"%s\"", WM_drag_get_paths(drag)[0]); RNA_string_set(drop->ptr, "text", pathname); } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index fe7179f8b8a..c603993052e 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -783,7 +783,7 @@ static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED( static void filepath_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { - RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag)); + RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]); } /* region dropbox definition */ diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 62f2de591ce..eafa35a8b89 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -268,7 +268,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) static void image_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { /* copy drag path to properties */ - RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag)); + RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]); } /* area+region dropbox definition */ diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 05a7a60fc7e..ff09fc72c1b 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -711,7 +711,7 @@ static void node_id_path_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox *dr return; } - const char *path = WM_drag_get_path(drag); + const char *path = WM_drag_get_paths(drag)[0]; if (path) { RNA_string_set(drop->ptr, "filepath", path); RNA_struct_property_unset(drop->ptr, "name"); diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c index 3f3737c5c6e..23c5695ee67 100644 --- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c @@ -247,7 +247,7 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop) return; } - const char *path = WM_drag_get_path(drag); + const char *path = WM_drag_get_paths(drag)[0]; /* Path dropped. */ if (path) { if (RNA_struct_find_property(drop->ptr, "filepath")) { @@ -335,7 +335,7 @@ static void get_drag_path(wmDrag *drag, char r_path[FILE_MAX]) BLI_path_abs(r_path, BKE_main_blendfile_path_from_global()); } else { - BLI_strncpy(r_path, WM_drag_get_path(drag), FILE_MAX); + BLI_strncpy(r_path, WM_drag_get_paths(drag)[0], FILE_MAX); } } diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 2b60ba768b0..66aca4607fd 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -312,7 +312,7 @@ static bool text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNU static void text_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { /* copy drag path to properties */ - RNA_string_set(drop->ptr, "filepath", WM_drag_get_path(drag)); + RNA_string_set(drop->ptr, "filepath", WM_drag_get_paths(drag)[0]); } static bool text_drop_paste_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event)) diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc index 08aae53128e..7d7c0414cc3 100644 --- a/source/blender/editors/space_view3d/space_view3d.cc +++ b/source/blender/editors/space_view3d/space_view3d.cc @@ -903,7 +903,7 @@ static void view3d_id_path_drop_copy(bContext * /*C*/, wmDrag *drag, wmDropBox * RNA_struct_property_unset(drop->ptr, "filepath"); return; } - const char *path = WM_drag_get_path(drag); + const char *path = WM_drag_get_paths(drag)[0]; if (path) { RNA_string_set(drop->ptr, "filepath", path); RNA_struct_property_unset(drop->ptr, "image"); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 751eeccec96..db80ae9846c 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -1445,13 +1445,15 @@ const ListBase *WM_drag_asset_list_get(const wmDrag *drag); const char *WM_drag_get_item_name(struct wmDrag *drag); -/* Path drag and drop. */ +/* Paths drag and drop. */ /** - * \param path: The path to drag. Value will be copied into the drag data so the passed string may - * be destructed. + * \param paths: The paths to drag. Value will be copied into the drag data so the passed strings + * may be destructed. Only paths that share the same extension of the first file will be copied. + * \param path_count: the number of paths in #paths */ -wmDragPath *WM_drag_create_path_data(const char *path); -const char *WM_drag_get_path(const wmDrag *drag); +wmDragPath *WM_drag_create_path_data(const char **paths, int path_count); +const char **WM_drag_get_paths(const wmDrag *drag); +const int WM_drag_get_path_count(const wmDrag *drag); /** * Note that even though the enum return type uses bit-flags, this should never have multiple * type-bits set, so `ELEM()` like comparison is possible. diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 14ebbf5cef1..70b96c101ac 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -1133,7 +1133,9 @@ typedef struct wmDragAssetListItem { } wmDragAssetListItem; typedef struct wmDragPath { - char *path; + char **paths; + char *tooltip; + int path_count; /* Note that even though the enum type uses bit-flags, this should never have multiple type-bits * set, so `ELEM()` like comparison is possible. */ int file_type; /* eFileSel_File_Types */ diff --git a/source/blender/windowmanager/intern/wm_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc index 6575a2fc91d..a2f29f1b42d 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.cc +++ b/source/blender/windowmanager/intern/wm_dragdrop.cc @@ -750,29 +750,70 @@ const ListBase *WM_drag_asset_list_get(const wmDrag *drag) return &drag->asset_items; } -wmDragPath *WM_drag_create_path_data(const char *path) +wmDragPath *WM_drag_create_path_data(const char **paths, int path_count) { wmDragPath *path_data = MEM_new("wmDragPath"); - path_data->path = BLI_strdup(path); - path_data->file_type = ED_path_extension_type(path); + + const char *ext = BLI_path_extension(paths[0]); + + int valid_path_count = 1; + for (int i = 1; i < path_count; i++) { + if ((ext == nullptr && BLI_path_extension(paths[i]) == nullptr) || + (ext != nullptr && BLI_path_extension_check(paths[i], ext))) { + valid_path_count++; + } + } + path_data->paths = (char **)MEM_mallocN(valid_path_count * sizeof(char *), "paths"); + + int path_index = 0; + for (int i = 0; i < path_count; i++) { + if ((ext == nullptr && BLI_path_extension(paths[i]) == nullptr) || + (ext != nullptr && BLI_path_extension_check(paths[i], ext))) { + path_data->paths[path_index] = BLI_strdup(paths[i]); + path_index++; + } + } + + path_data->file_type = ED_path_extension_type(paths[0]); + path_data->path_count = valid_path_count; + if (path_count == 1) { + path_data->tooltip = BLI_strdup(paths[0]); + } + else { + const char *tooltip = TIP_("Dragging %d %s files."); + path_data->tooltip = BLI_sprintfN(tooltip, valid_path_count, ext); + } return path_data; } static void wm_drag_free_path_data(wmDragPath **path_data) { - MEM_freeN((*path_data)->path); + for (int i = 0; i < (*path_data)->path_count; i++) { + MEM_freeN((*path_data)->paths[i]); + } + MEM_freeN((*path_data)->paths); + MEM_freeN((*path_data)->tooltip); MEM_delete(*path_data); *path_data = nullptr; } -const char *WM_drag_get_path(const wmDrag *drag) +const char **WM_drag_get_paths(const wmDrag *drag) { if (drag->type != WM_DRAG_PATH) { return nullptr; } const wmDragPath *path_data = static_cast(drag->poin); - return path_data->path; + return const_cast(path_data->paths); +} +const int WM_drag_get_path_count(const wmDrag *drag) +{ + if (drag->type != WM_DRAG_PATH) { + return 0; + } + + const wmDragPath *path_data = static_cast(drag->poin); + return path_data->path_count; } int WM_drag_get_path_file_type(const wmDrag *drag) @@ -836,7 +877,7 @@ const char *WM_drag_get_item_name(wmDrag *drag) } case WM_DRAG_PATH: { const wmDragPath *path_drag_data = static_cast(drag->poin); - return path_drag_data->path; + return path_drag_data->tooltip; } case WM_DRAG_NAME: return static_cast(drag->poin); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 1ea110dfc28..a9fd65d6d38 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -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,37 +1472,40 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt } break; } + case GHOST_kEventDraggingEntered: { + 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); + + /* add drag data to wm for paths: */ + if (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_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); - /* 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); + update_mouse_position_from_draganddrop(wm, win, &event, ddd); /* make blender drop event with custom data pointing to wm drags */ event.type = EVT_DROP; @@ -1479,27 +1515,29 @@ static bool ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_pt event.customdata_free = true; wm_event_add(win, &event); - - // printf("Drop detected\n"); - - /* add drag data to wm for paths: */ - - if (ddd->dataType == GHOST_kDragnDropTypeFilenames) { + if (wm->drags.first != NULL && ddd->dataType == GHOST_kDragnDropTypeFilenames) { GHOST_TStringArray *stra = ddd->data; - for (int a = 0; a < stra->count; a++) { - printf("drop file %s\n", stra->strings[a]); + if (stra->count > 0) { /* try to get icon type from extension */ - int icon = ED_file_extension_icon((char *)stra->strings[a]); - wmDragPath *path_data = WM_drag_create_path_data((char *)stra->strings[a]); + 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;