forked from bartvdbraak/blender
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:
parent
7c15fb4f2c
commit
e8a1daaf9b
4
extern/CMakeLists.txt
vendored
4
extern/CMakeLists.txt
vendored
@ -71,3 +71,7 @@ endif()
|
|||||||
if(WITH_CARVE)
|
if(WITH_CARVE)
|
||||||
add_subdirectory(carve)
|
add_subdirectory(carve)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
add_subdirectory(xdnd)
|
||||||
|
endif()
|
||||||
|
3
extern/SConscript
vendored
3
extern/SConscript
vendored
@ -34,3 +34,6 @@ if env['WITH_BF_LIBMV']:
|
|||||||
|
|
||||||
if env['WITH_BF_CARVE']:
|
if env['WITH_BF_CARVE']:
|
||||||
SConscript(['carve/SConscript'])
|
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
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
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
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
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_SystemX11.cpp
|
||||||
intern/GHOST_SystemPathsX11.cpp
|
intern/GHOST_SystemPathsX11.cpp
|
||||||
intern/GHOST_WindowX11.cpp
|
intern/GHOST_WindowX11.cpp
|
||||||
|
intern/GHOST_DropTargetX11.cpp
|
||||||
|
|
||||||
intern/GHOST_DisplayManagerX11.h
|
intern/GHOST_DisplayManagerX11.h
|
||||||
intern/GHOST_SystemX11.h
|
intern/GHOST_SystemX11.h
|
||||||
intern/GHOST_SystemPathsX11.h
|
intern/GHOST_SystemPathsX11.h
|
||||||
intern/GHOST_WindowX11.h
|
intern/GHOST_WindowX11.h
|
||||||
|
intern/GHOST_DropTargetX11.h
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND INC
|
||||||
|
../../extern/xdnd
|
||||||
)
|
)
|
||||||
|
|
||||||
if(X11_XF86keysym_INCLUDE_PATH)
|
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 += ['PREFIX=\\"/usr/local/\\"'] # XXX, make an option
|
||||||
defs += ['WITH_X11_XINPUT'] # 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'):
|
elif window_system in ('win32-vc', 'win32-mingw', 'cygwin', 'linuxcross', 'win64-vc'):
|
||||||
for f in pf:
|
for f in pf:
|
||||||
try:
|
try:
|
||||||
|
310
intern/ghost/intern/GHOST_DropTargetX11.cpp
Normal file
310
intern/ghost/intern/GHOST_DropTargetX11.cpp
Normal file
@ -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;
|
||||||
|
}
|
135
intern/ghost/intern/GHOST_DropTargetX11.h
Normal file
135
intern/ghost/intern/GHOST_DropTargetX11.h
Normal file
@ -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_EventButton.h"
|
||||||
#include "GHOST_EventWheel.h"
|
#include "GHOST_EventWheel.h"
|
||||||
#include "GHOST_DisplayManagerX11.h"
|
#include "GHOST_DisplayManagerX11.h"
|
||||||
|
#include "GHOST_DropTargetX11.h"
|
||||||
|
#include "GHOST_EventDragnDrop.h"
|
||||||
#ifdef WITH_INPUT_NDOF
|
#ifdef WITH_INPUT_NDOF
|
||||||
#include "GHOST_NDOFManagerX11.h"
|
#include "GHOST_NDOFManagerX11.h"
|
||||||
#endif
|
#endif
|
||||||
@ -709,8 +711,12 @@ GHOST_SystemX11::processEvent(XEvent *xe)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Unknown client message, ignore */
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1478,3 +1484,17 @@ void GHOST_SystemX11::putClipboard(GHOST_TInt8 *buffer, bool selection) const
|
|||||||
fprintf(stderr, "failed to own primary\n");
|
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;
|
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
|
* @see GHOST_ISystem
|
||||||
*/
|
*/
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
#include "GHOST_WindowX11.h"
|
#include "GHOST_WindowX11.h"
|
||||||
#include "GHOST_SystemX11.h"
|
#include "GHOST_SystemX11.h"
|
||||||
|
#include "GHOST_DropTargetX11.h"
|
||||||
#include "STR_String.h"
|
#include "STR_String.h"
|
||||||
#include "GHOST_Debug.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
|
* 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
|
* to a window that isn't mapped. That is why we can't "just
|
||||||
@ -1318,6 +1323,7 @@ GHOST_WindowX11::
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
delete m_dropTarget;
|
||||||
|
|
||||||
XDestroyWindow(m_display, m_window);
|
XDestroyWindow(m_display, m_window);
|
||||||
XFree(m_visual);
|
XFree(m_visual);
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
|
|
||||||
class STR_String;
|
class STR_String;
|
||||||
class GHOST_SystemX11;
|
class GHOST_SystemX11;
|
||||||
|
class GHOST_DropTargetX11;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* X11 implementation of GHOST_IWindow.
|
* X11 implementation of GHOST_IWindow.
|
||||||
@ -224,6 +225,9 @@ public:
|
|||||||
XIC getX11_XIC() { return m_xic; }
|
XIC getX11_XIC() { return m_xic; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GHOST_DropTargetX11* getDropTarget()
|
||||||
|
{ return m_dropTarget; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need this in case that we want start the window
|
* Need this in case that we want start the window
|
||||||
* in FullScree or Maximized state.
|
* in FullScree or Maximized state.
|
||||||
@ -361,6 +365,8 @@ private :
|
|||||||
/** Cache of XC_* ID's to XCursor structures */
|
/** Cache of XC_* ID's to XCursor structures */
|
||||||
std::map<unsigned int, Cursor> m_standard_cursors;
|
std::map<unsigned int, Cursor> m_standard_cursors;
|
||||||
|
|
||||||
|
GHOST_DropTargetX11 * m_dropTarget;
|
||||||
|
|
||||||
#ifdef WITH_X11_XINPUT
|
#ifdef WITH_X11_XINPUT
|
||||||
/* Tablet devices */
|
/* Tablet devices */
|
||||||
XTablet m_xtablet;
|
XTablet m_xtablet;
|
||||||
|
@ -828,6 +828,7 @@ endif()
|
|||||||
extern_minilzo
|
extern_minilzo
|
||||||
extern_lzma
|
extern_lzma
|
||||||
extern_colamd
|
extern_colamd
|
||||||
|
extern_xdnd
|
||||||
ge_logic_ketsji
|
ge_logic_ketsji
|
||||||
extern_recastnavigation
|
extern_recastnavigation
|
||||||
ge_phys_common
|
ge_phys_common
|
||||||
|
Loading…
Reference in New Issue
Block a user