Drag-n-drop support on Linux

This commit implements drag-n-drop support from external applications into Blender.
Used xdnd implementation from Paul Sheer.
This commit is contained in:
Sergey Sharybin 2012-02-17 16:58:09 +00:00
parent 7c15fb4f2c
commit e8a1daaf9b
15 changed files with 2379 additions and 1 deletions

@ -71,3 +71,7 @@ endif()
if(WITH_CARVE)
add_subdirectory(carve)
endif()
if(UNIX AND NOT APPLE)
add_subdirectory(xdnd)
endif()

3
extern/SConscript vendored

@ -34,3 +34,6 @@ if env['WITH_BF_LIBMV']:
if env['WITH_BF_CARVE']:
SConscript(['carve/SConscript'])
if env['OURPLATFORM'] in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'freebsd9', 'aix4', 'aix5'):
SConscript(['xdnd/SConscript'])

43
extern/xdnd/CMakeLists.txt vendored Normal file

@ -0,0 +1,43 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2012, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Sergey Sharybin.
#
# ***** END GPL LICENSE BLOCK *****
set(INC
.
)
set(INC_SYS
)
set(SRC
xdnd.c
xdnd.h
)
add_definitions(
-DHAVE_SYS_TIME_H
)
blender_add_lib(extern_xdnd "${SRC}" "${INC}" "${INC_SYS}")

10
extern/xdnd/SConscript vendored Normal file

@ -0,0 +1,10 @@
#!/usr/bin/python
Import('env')
defs = ['HAVE_SYS_TIME_H']
sources = env.Glob('*.c')
incs = '.'
env.BlenderLib ( 'extern_xdnd', sources, Split(incs), defs, libtype=['extern','player'], priority=[10, 185])

1599
extern/xdnd/xdnd.c vendored Normal file

File diff suppressed because it is too large Load Diff

221
extern/xdnd/xdnd.h vendored Normal file

@ -0,0 +1,221 @@
/* xdnd.c, xdnd.h - C program library for handling the Xdnd protocol
Copyright (C) 1996-2000 Paul Sheer
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
*/
#ifndef _X_DND_H
#define _X_DND_H
#ifdef __cplusplus
extern "C" {
#endif
/* you can set this to either 2 (which support 0 and 1 as well) or 3 */
/* #define XDND_VERSION 2 */
#define XDND_VERSION 3
/* XdndEnter */
#define XDND_THREE 3
#define XDND_ENTER_SOURCE_WIN(e) ((e)->xclient.data.l[0])
#define XDND_ENTER_THREE_TYPES(e) (((e)->xclient.data.l[1] & 0x1UL) == 0)
#define XDND_ENTER_THREE_TYPES_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
#define XDND_ENTER_VERSION(e) ((e)->xclient.data.l[1] >> 24)
#define XDND_ENTER_VERSION_SET(e,v) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24)
#define XDND_ENTER_TYPE(e,i) ((e)->xclient.data.l[2 + i]) /* i => (0, 1, 2) */
/* XdndPosition */
#define XDND_POSITION_SOURCE_WIN(e) ((e)->xclient.data.l[0])
#define XDND_POSITION_ROOT_X(e) ((e)->xclient.data.l[2] >> 16)
#define XDND_POSITION_ROOT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFUL)
#define XDND_POSITION_ROOT_SET(e,x,y) (e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL)
#define XDND_POSITION_TIME(e) ((e)->xclient.data.l[3])
#define XDND_POSITION_ACTION(e) ((e)->xclient.data.l[4])
/* XdndStatus */
#define XDND_STATUS_TARGET_WIN(e) ((e)->xclient.data.l[0])
#define XDND_STATUS_WILL_ACCEPT(e) ((e)->xclient.data.l[1] & 0x1L)
#define XDND_STATUS_WILL_ACCEPT_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
#define XDND_STATUS_WANT_POSITION(e) ((e)->xclient.data.l[1] & 0x2UL)
#define XDND_STATUS_WANT_POSITION_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x2UL) | (((b) == 0) ? 0 : 0x2UL)
#define XDND_STATUS_RECT_X(e) ((e)->xclient.data.l[2] >> 16)
#define XDND_STATUS_RECT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFL)
#define XDND_STATUS_RECT_WIDTH(e) ((e)->xclient.data.l[3] >> 16)
#define XDND_STATUS_RECT_HEIGHT(e) ((e)->xclient.data.l[3] & 0xFFFFL)
#define XDND_STATUS_RECT_SET(e,x,y,w,h) {(e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL); (e)->xclient.data.l[3] = ((w) << 16) | ((h) & 0xFFFFUL); }
#define XDND_STATUS_ACTION(e) ((e)->xclient.data.l[4])
/* XdndLeave */
#define XDND_LEAVE_SOURCE_WIN(e) ((e)->xclient.data.l[0])
/* XdndDrop */
#define XDND_DROP_SOURCE_WIN(e) ((e)->xclient.data.l[0])
#define XDND_DROP_TIME(e) ((e)->xclient.data.l[2])
/* XdndFinished */
#define XDND_FINISHED_TARGET_WIN(e) ((e)->xclient.data.l[0])
struct _DndCursor {
int width, height;
int x, y;
unsigned char *image_data, *mask_data;
char *_action;
Pixmap image_pixmap, mask_pixmap;
Cursor cursor;
Atom action;
};
typedef struct _DndCursor DndCursor;
typedef struct _DndClass DndClass;
struct _DndClass {
/* insert chars sequentionally into the target widget, type will be the same as `desired_type'
returned from widget_apply_position. This may be called several times in succession
with sequention blocks of data. Must return non-zero on failure */
int (*widget_insert_drop) (DndClass * dnd, unsigned char *data, int length, int remaining, Window into, Window from, Atom type);
/* In response to DELETE requests : FIXME - not yet used */
int (*widget_delete_selection) (DndClass * dnd, Window window, Window from);
/* returns 1 if widget exists, zero otherwise. If this method is not
set then the code assumes that no widgets have support for recieving drops.
In this case none of the widget methods need be set. */
int (*widget_exists) (DndClass * dnd, Window window);
/* must update the widgets border to its default appearance */
void (*widget_apply_leave) (DndClass * dnd, Window widgets_window);
/* must update the widgets border to give the appearance of being able to recieve a drop,
plus return all data to pointers. As per the protocol, if the widget cannot
perform the action specified by `action' then it should return either XdndActionPrivate
or XdndActionCopy into supported_action (leaving 0 supported_action unchanged is equivalent
to XdndActionCopy). Returns 1 if ready to ok drop */
int (*widget_apply_position) (DndClass * dnd, Window widgets_window, Window from,
Atom action, int x, int y, Time t, Atom * typelist,
int *want_position, Atom * supported_action, Atom * desired_type,
XRectangle * rectangle);
/* returns drag data of the specified type. This will be one of `typelist' given to xdnd_drag */
void (*widget_get_data) (DndClass * dnd, Window window, unsigned char **data, int *length, Atom type);
/* this is called from with the main event loop if an expose event is recieved and is optional */
void (*handle_expose_events) (DndClass * dnd, XEvent * xevent);
/* creates a chooser dialog if the action is XdndActionAsk. Returns non-zero on cancel */
int (*action_choose_dialog) (DndClass * dnd, char **descriptions, Atom * actions, Atom * result);
#if 0 /* implemented internally */
/* returns a widget that is dnd aware within a parent widget that lies under the point x, y */
Window (*widget_get_child_widget) (DndClass * dnd, Window parent, int x, int y);
#endif
void *pad1[8];
DndCursor *cursors;
Display *display;
Atom XdndAware;
Atom XdndSelection;
Atom XdndEnter;
Atom XdndLeave;
Atom XdndPosition;
Atom XdndDrop;
Atom XdndFinished;
Atom XdndStatus;
Atom XdndActionCopy;
Atom XdndActionMove;
Atom XdndActionLink;
Atom XdndActionAsk;
Atom XdndActionPrivate;
Atom XdndTypeList;
Atom XdndActionList;
Atom XdndActionDescription;
Atom Xdnd_NON_PROTOCOL_ATOM;
Atom version;
Atom pad2[16];
Window root_window;
#define XDND_DROP_STAGE_IDLE 0
#define XDND_DRAG_STAGE_DRAGGING 1
#define XDND_DRAG_STAGE_ENTERED 2
#define XDND_DROP_STAGE_CONVERTING 3
#define XDND_DROP_STAGE_ENTERED 4
int stage;
int dragging_version;
int internal_drag;
int want_position;
int ready_to_drop;
int will_accept;
XRectangle rectangle;
Window dropper_window, dragger_window;
Atom *dragger_typelist;
Atom desired_type;
Atom supported_action;
Time time;
/* drop position from last XdndPosition */
int x, y;
int pad3[16];
/* move euclidian pixels before considering this to be an actual drag */
float drag_threshold;
/* block for only this many seconds on not receiving a XdndFinished from target, default : 10 */
int time_out;
#define XDND_OPTION_NO_HYSTERESIS (1<<0)
int options;
/* user hooks */
void *user_hook1;
void *user_hook2;
void *user_hook3;
Window dropper_toplevel;
void *pad4[15];
};
void xdnd_init (DndClass * dnd, Display * display);
void xdnd_shut (DndClass * dnd);
/* for nested widgets where parent and child receive drops of different
types; then always pass typelist as null */
void xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist);
int xdnd_is_dnd_aware (DndClass * dnd, Window window, int *version, Atom * typelist);
void xdnd_set_type_list (DndClass * dnd, Window window, Atom * typelist);
void xdnd_set_actions (DndClass * dnd, Window window, Atom * actions, char **descriptions);
int xdnd_get_actions (DndClass * dnd, Window window, Atom ** actions, char ***descriptions);
int xdnd_choose_action_dialog (DndClass * dnd, Atom * actions, char **descriptions, Atom * result);
Atom xdnd_drag (DndClass * dnd, Window from, Atom action, Atom * typelist);
/* Returns 1 if event is handled, This must be placed in the widget
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,
unsigned char **data, int *length, Atom * type, int *x, int *y);
#ifdef __cplusplus
}
#endif
#endif /* !_X_DND_H */

@ -220,11 +220,17 @@ elseif(UNIX)
intern/GHOST_SystemX11.cpp
intern/GHOST_SystemPathsX11.cpp
intern/GHOST_WindowX11.cpp
intern/GHOST_DropTargetX11.cpp
intern/GHOST_DisplayManagerX11.h
intern/GHOST_SystemX11.h
intern/GHOST_SystemPathsX11.h
intern/GHOST_WindowX11.h
intern/GHOST_DropTargetX11.h
)
list(APPEND INC
../../extern/xdnd
)
if(X11_XF86keysym_INCLUDE_PATH)

@ -42,6 +42,8 @@ elif window_system in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'f
# defs += ['PREFIX=\\"/usr/local/\\"'] # XXX, make an option
defs += ['WITH_X11_XINPUT'] # XXX, make an option
incs += ' #/extern/xdnd'
elif window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'):
for f in pf:
try:

@ -0,0 +1,310 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2012 by the Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Sergey Sharybin.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file ghost/intern/GHOST_DropTargetX11.cpp
* \ingroup GHOST
*/
#include "GHOST_DropTargetX11.h"
#include "GHOST_Debug.h"
#include <ctype.h>
#include <assert.h>
bool GHOST_DropTargetX11::m_xdndInitialized = false;
DndClass GHOST_DropTargetX11::m_dndClass;
Atom * GHOST_DropTargetX11::m_dndTypes = NULL;
Atom * GHOST_DropTargetX11::m_dndActions = NULL;
const char *GHOST_DropTargetX11::m_dndMimeTypes[] = {"url/url", "text/uri-list", "text/plain", "application/octet-stream"};
int GHOST_DropTargetX11::m_refCounter = 0;
#define dndTypeURLID 0
#define dndTypeURIListID 1
#define dndTypePlainTextID 2
#define dndTypeOctetStreamID 3
#define dndTypeURL m_dndTypes[dndTypeURLID]
#define dndTypeURIList m_dndTypes[dndTypeURIListID]
#define dndTypePlainText m_dndTypes[dndTypePlainTextID]
#define dndTypeOctetStream m_dndTypes[dndTypeOctetStreamID]
void GHOST_DropTargetX11::Initialize(void)
{
Display *display = m_system->getXDisplay();
int dndTypesCount = sizeof(m_dndMimeTypes) / sizeof(char*);
int counter;
xdnd_init(&m_dndClass, display);
m_dndTypes = new Atom[dndTypesCount + 1];
XInternAtoms(display, (char**)m_dndMimeTypes, dndTypesCount, 0, m_dndTypes);
m_dndTypes[dndTypesCount] = 0;
m_dndActions = new Atom[8];
counter = 0;
m_dndActions[counter++] = m_dndClass.XdndActionCopy;
m_dndActions[counter++] = m_dndClass.XdndActionMove;
#if 0 /* Not supported yet */
dndActions[counter++] = dnd->XdndActionLink;
dndActions[counter++] = dnd->XdndActionAsk;
dndActions[counter++] = dnd->XdndActionPrivate;
dndActions[counter++] = dnd->XdndActionList;
dndActions[counter++] = dnd->XdndActionDescription;
#endif
m_dndActions[counter++] = 0;
}
void GHOST_DropTargetX11::Uninitialize(void)
{
xdnd_shut(&m_dndClass);
}
GHOST_DropTargetX11::GHOST_DropTargetX11(GHOST_WindowX11 * window, GHOST_SystemX11 * system)
:
m_window(window),
m_system(system)
{
if (!m_xdndInitialized) {
Initialize();
m_xdndInitialized = true;
GHOST_PRINT("XDND initialized\n");
}
Window wnd = window->getXWindow();
xdnd_set_dnd_aware(&m_dndClass, wnd, 0);
xdnd_set_type_list(&m_dndClass, wnd, m_dndTypes);
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
m_refCounter++;
}
GHOST_DropTargetX11::~GHOST_DropTargetX11()
{
m_refCounter--;
if (m_refCounter == 0) {
Uninitialize();
m_xdndInitialized = false;
GHOST_PRINT("XDND uninitialized\n");
}
}
/* based on a code from Saul Rennison
* http://stackoverflow.com/questions/2673207/c-c-url-decode-library */
typedef enum DecodeState_e {
STATE_SEARCH = 0, ///< searching for an ampersand to convert
STATE_CONVERTING ///< convert the two proceeding characters from hex
} DecodeState_e;
void GHOST_DropTargetX11::UrlDecode(char *decodedOut, int bufferSize, const char *encodedIn)
{
unsigned int i;
unsigned int len = strlen(encodedIn);
DecodeState_e state = STATE_SEARCH;
int j, asciiCharacter;
char tempNumBuf[3] = {0};
bool bothDigits = true;
memset(decodedOut, 0, bufferSize);
for (i = 0; i < len; ++i) {
switch (state) {
case STATE_SEARCH:
if (encodedIn[i] != '%') {
strncat(decodedOut, &encodedIn[i], 1);
assert(strlen(decodedOut) < bufferSize);
break;
}
// We are now converting
state = STATE_CONVERTING;
break;
case STATE_CONVERTING:
bothDigits = true;
// Create a buffer to hold the hex. For example, if %20, this
// buffer would hold 20 (in ASCII)
memset(tempNumBuf, 0, sizeof(tempNumBuf));
// Conversion complete (i.e. don't convert again next iter)
state = STATE_SEARCH;
strncpy(tempNumBuf, &encodedIn[i], 2);
// Ensure both characters are hexadecimal
for (j = 0; j < 2; ++j) {
if (!isxdigit(tempNumBuf[j]))
bothDigits = false;
}
if (!bothDigits)
break;
// Convert two hexadecimal characters into one character
sscanf(tempNumBuf, "%x", &asciiCharacter);
// Ensure we aren't going to overflow
assert(strlen(decodedOut) < bufferSize);
// Concatenate this character onto the output
strncat(decodedOut, (char*)&asciiCharacter, 1);
// Skip the next character
i++;
break;
}
}
}
char *GHOST_DropTargetX11::FileUrlDecode(char *fileUrl)
{
if(!strncpy(fileUrl, "file://", 7) == 0) {
/* assume one character of encoded URL can be expanded to 4 chars max */
int decodedSize = 4 * strlen(fileUrl) + 1;
char *decodedPath = (char *)malloc(decodedSize);
UrlDecode(decodedPath, decodedSize, fileUrl + 7);
return decodedPath;
}
return NULL;
}
void *GHOST_DropTargetX11::getURIListGhostData(unsigned char *dropBuffer, int dropBufferSize)
{
GHOST_TStringArray *strArray = NULL;
int totPaths = 0, curLength = 0;
/* count total number of file pathes in buffer */
for (int i = 0; i <= dropBufferSize; i++) {
if (dropBuffer[i] == 0 || dropBuffer[i] == '\n' || dropBuffer[i] == '\r') {
if (curLength) {
totPaths++;
curLength = 0;
}
}
else curLength++;
}
strArray = (GHOST_TStringArray*)malloc(sizeof(GHOST_TStringArray));
strArray->count = 0;
strArray->strings = (GHOST_TUns8**)malloc(totPaths*sizeof(GHOST_TUns8*));
curLength = 0;
for (int i = 0; i <= dropBufferSize; i++) {
if (dropBuffer[i] == 0 || dropBuffer[i] == '\n' || dropBuffer[i] == '\r') {
if (curLength) {
char *curPath = (char *)malloc(curLength + 1);
char *decodedPath;
strncpy(curPath, (char*)dropBuffer + i - curLength, curLength);
curPath[curLength] = 0;
decodedPath = FileUrlDecode(curPath);
if(decodedPath) {
strArray->strings[strArray->count] = (GHOST_TUns8*)decodedPath;
strArray->count++;
}
free(curPath);
curLength = 0;
}
}
else curLength++;
}
return strArray;
}
void *GHOST_DropTargetX11::getGhostData(Atom dropType, unsigned char *dropBuffer, int dropBufferSize)
{
void *data = NULL;
unsigned char *tmpBuffer = (unsigned char *)malloc(dropBufferSize + 1);
bool needsFree = true;
/* ensure NULL-terminator */
memcpy(tmpBuffer, dropBuffer, dropBufferSize);
tmpBuffer[dropBufferSize] = 0;
if (dropType == dndTypeURIList) {
m_draggedObjectType = GHOST_kDragnDropTypeFilenames;
data = getURIListGhostData(tmpBuffer, dropBufferSize);
}
else if (dropType == dndTypeURL) {
/* need to be tested */
char *decodedPath = FileUrlDecode((char *)tmpBuffer);
if (decodedPath) {
m_draggedObjectType = GHOST_kDragnDropTypeString;
data = decodedPath;
}
}
else if (dropType == dndTypePlainText || dropType == dndTypeOctetStream) {
m_draggedObjectType = GHOST_kDragnDropTypeString;
data = tmpBuffer;
needsFree = false;
}
else {
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
}
if (needsFree)
free(tmpBuffer);
return data;
}
bool GHOST_DropTargetX11::GHOST_HandleClientMessage(XEvent *event)
{
Atom dropType;
unsigned char *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);
if (data)
m_system->pushDragDropEvent(GHOST_kEventDraggingDropDone, m_draggedObjectType, m_window, dropX, dropY, data);
free(dropBuffer);
m_draggedObjectType = GHOST_kDragnDropTypeUnknown;
return true;
}
return false;
}

@ -0,0 +1,135 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2012 by the Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): Sergey Sharybin.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file ghost/intern/GHOST_DropTargetWin32.h
* \ingroup GHOST
*/
#ifndef _GHOST_DROP_TARGET_X11_H_
#define _GHOST_DROP_TARGET_X11_H_
#include <GHOST_Types.h>
#include "GHOST_WindowX11.h"
#include "GHOST_SystemX11.h"
#include "xdnd.h"
class GHOST_DropTargetX11
{
public:
/**
* Constructor
*
* @param window The window to register as drop target.
* @param system The associated system.
*/
GHOST_DropTargetX11(GHOST_WindowX11 * window, GHOST_SystemX11 * system);
/**
* Destructor
*/
~GHOST_DropTargetX11();
/**
* Handler of ClientMessage X11 event
*/
bool GHOST_HandleClientMessage(XEvent *event);
/**
* Get data to pass in event.
* It checks the type and calls specific functions for each type.
* @param dropType - type of dropped entity.
* @param dropBuffer - buffer returned from source application
* @param dropBufferSize - size of returned buffer
* @return Pointer to data.
*/
void *getGhostData(Atom dropType, unsigned char *dropBuffer, int dropBufferSize);
private:
/* Internal helper functions */
/**
* Initiailize XDND and all related X atoms
*/
void Initialize(void);
/**
* Uninitiailize XDND and all related X atoms
*/
void Uninitialize(void);
/**
* Get data to be passed to event from text/uri-list mime type
* @param dropBuffer - buffer returned from source application
* @param dropBufferSize - size of dropped buffer
* @return pointer to newly created GHOST data
*/
void * getURIListGhostData(unsigned char *dropBuffer, int dropBufferSize);
/**
* Decode URL (i.e. converts "file:///a%20b/test" to "file:///a b/test")
* @param decodedOut - buffer for decoded URL
* @param bufferSize - size of output buffer
* @param encodedIn - input encoded buffer to be decoded
*/
void UrlDecode(char *decodedOut, int bufferSize, const char *encodedIn);
/**
* Fully decode file URL (i.e. converts "file:///a%20b/test" to "/a b/test")
* @param fileUrl - file path URL to be fully decoded
* @return decoded file path (resutl shold be free-d)
*/
char *FileUrlDecode(char *fileUrl);
/* The associated GHOST_WindowWin32. */
GHOST_WindowX11 * m_window;
/* The System. */
GHOST_SystemX11 * m_system;
/* Data type of the dragged object */
GHOST_TDragnDropTypes m_draggedObjectType;
/* is dnd stuff initialzied */
static bool m_xdndInitialized;
/* class holding internal stiff of xdnd library */
static DndClass m_dndClass;
/* list of supported types to eb draggeg into */
static Atom * m_dndTypes;
/* list of supported dran'n'drop actions */
static Atom * m_dndActions;
/* List of supported MIME types to be dragged into */
static const char *m_dndMimeTypes[];
/* counter of references to global XDND structures */
static int m_refCounter;
};
#endif // _GHOST_DROP_TARGET_X11_H_

@ -42,6 +42,8 @@
#include "GHOST_EventButton.h"
#include "GHOST_EventWheel.h"
#include "GHOST_DisplayManagerX11.h"
#include "GHOST_DropTargetX11.h"
#include "GHOST_EventDragnDrop.h"
#ifdef WITH_INPUT_NDOF
#include "GHOST_NDOFManagerX11.h"
#endif
@ -709,8 +711,12 @@ GHOST_SystemX11::processEvent(XEvent *xe)
}
}
} else {
/* try to handle drag event (if there's no such events, GHOST_HandleClientMessage will return zero) */
if (window->getDropTarget()->GHOST_HandleClientMessage(xe) == false) {
/* Unknown client message, ignore */
}
}
break;
}
@ -1478,3 +1484,17 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
fprintf(stderr, "failed to own primary\n");
}
}
GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
GHOST_TDragnDropTypes draggedObjectType,
GHOST_IWindow* window,
int mouseX, int mouseY,
void* data)
{
GHOST_SystemX11* system = ((GHOST_SystemX11*)getSystem());
return system->pushEvent(new GHOST_EventDragnDrop(system->getMilliSeconds(),
eventType,
draggedObjectType,
window,mouseX,mouseY,data)
);
}

@ -235,6 +235,18 @@ public:
*/
void putClipboard(GHOST_TInt8 *buffer, bool selection) const;
/**
* Creates a drag'n'drop event and pushes it immediately onto the event queue.
* Called by GHOST_DropTargetX11 class.
* @param eventType The type of drag'n'drop event
* @param draggedObjectType The type object concerned (currently array of file names, string, ?bitmap)
* @param mouseX x mouse coordinate (in window coordinates)
* @param mouseY y mouse coordinate
* @param window The window on which the event occurred
* @return Indication whether the event was handled.
*/
static GHOST_TSuccess pushDragDropEvent(GHOST_TEventType eventType, GHOST_TDragnDropTypes draggedObjectType,GHOST_IWindow* window, int mouseX, int mouseY, void* data);
/**
* @see GHOST_ISystem
*/

@ -32,6 +32,7 @@
#include "GHOST_WindowX11.h"
#include "GHOST_SystemX11.h"
#include "GHOST_DropTargetX11.h"
#include "STR_String.h"
#include "GHOST_Debug.h"
@ -326,6 +327,10 @@ GHOST_WindowX11(
}
/* initialize drop target for newly created window */
m_dropTarget = new GHOST_DropTargetX11(this, m_system);
GHOST_PRINT("Set drop target\n");
/*
* One of the problem with WM-spec is that can't set a property
* to a window that isn't mapped. That is why we can't "just
@ -1318,6 +1323,7 @@ GHOST_WindowX11::
}
#endif
delete m_dropTarget;
XDestroyWindow(m_display, m_window);
XFree(m_visual);

@ -45,6 +45,7 @@
class STR_String;
class GHOST_SystemX11;
class GHOST_DropTargetX11;
/**
* X11 implementation of GHOST_IWindow.
@ -224,6 +225,9 @@ public:
XIC getX11_XIC() { return m_xic; }
#endif
GHOST_DropTargetX11* getDropTarget()
{ return m_dropTarget; }
/*
* Need this in case that we want start the window
* in FullScree or Maximized state.
@ -361,6 +365,8 @@ private :
/** Cache of XC_* ID's to XCursor structures */
std::map<unsigned int, Cursor> m_standard_cursors;
GHOST_DropTargetX11 * m_dropTarget;
#ifdef WITH_X11_XINPUT
/* Tablet devices */
XTablet m_xtablet;

@ -828,6 +828,7 @@ endif()
extern_minilzo
extern_lzma
extern_colamd
extern_xdnd
ge_logic_ketsji
extern_recastnavigation
ge_phys_common