mirror of
				https://github.com/glfw/glfw.git
				synced 2025-11-04 06:15:07 +00:00 
			
		
		
		
	Initial drag and drop support.
This commit is contained in:
		
							parent
							
								
									0548c713e8
								
							
						
					
					
						commit
						89d0723ba3
					
				@ -773,6 +773,20 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int);
 | 
			
		||||
 */
 | 
			
		||||
typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*! @brief The function signature for drop callbacks.
 | 
			
		||||
 *
 | 
			
		||||
 *  This is the function signature for drop callbacks.
 | 
			
		||||
 *
 | 
			
		||||
 *  @param[in] window The window that received the event.
 | 
			
		||||
 *  @param[in] string The string descriptor for the dropped object.
 | 
			
		||||
 *
 | 
			
		||||
 *  @sa glfwSetDropCallback
 | 
			
		||||
 *
 | 
			
		||||
 *  @ingroup input
 | 
			
		||||
 */
 | 
			
		||||
typedef void (* GLFWdropfun)(GLFWwindow*,const char*);
 | 
			
		||||
 | 
			
		||||
/*! @brief The function signature for monitor configuration callbacks.
 | 
			
		||||
 *
 | 
			
		||||
 *  This is the function signature for monitor configuration callback functions.
 | 
			
		||||
@ -2014,6 +2028,22 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu
 | 
			
		||||
 */
 | 
			
		||||
GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun);
 | 
			
		||||
 | 
			
		||||
/*! @brief Sets the drop callback.
 | 
			
		||||
 *
 | 
			
		||||
 *  This function sets the drop callback of the specified window, which is
 | 
			
		||||
 *  called when an object is dropped over the window.
 | 
			
		||||
 *
 | 
			
		||||
 *
 | 
			
		||||
 *  @param[in] window The window whose callback to set.
 | 
			
		||||
 *  @param[in] cbfun The new drop callback, or `NULL` to remove the currently
 | 
			
		||||
 *  set callback.
 | 
			
		||||
 *  @return The previously set callback, or `NULL` if no callback was set or an
 | 
			
		||||
 *  error occurred.
 | 
			
		||||
 *
 | 
			
		||||
 *  @ingroup input
 | 
			
		||||
 */
 | 
			
		||||
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun);
 | 
			
		||||
 | 
			
		||||
/*! @brief Returns whether the specified joystick is present.
 | 
			
		||||
 *
 | 
			
		||||
 *  This function returns whether the specified joystick is present.
 | 
			
		||||
 | 
			
		||||
@ -413,6 +413,8 @@ static int translateKey(unsigned int key)
 | 
			
		||||
@interface GLFWContentView : NSView
 | 
			
		||||
{
 | 
			
		||||
    _GLFWwindow* window;
 | 
			
		||||
    char * fileNamesForDrag;
 | 
			
		||||
    int fileNamesSize;
 | 
			
		||||
    NSTrackingArea* trackingArea;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -444,7 +446,14 @@ static int translateKey(unsigned int key)
 | 
			
		||||
        window = initWindow;
 | 
			
		||||
        trackingArea = nil;
 | 
			
		||||
        
 | 
			
		||||
        fileNamesForDrag = (char*)malloc(1024);
 | 
			
		||||
        fileNamesSize = 1024;
 | 
			
		||||
        
 | 
			
		||||
        [self updateTrackingAreas];
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        [self registerForDraggedTypes:[NSArray arrayWithObjects:
 | 
			
		||||
                                       NSFilenamesPboardType, nil]];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return self;
 | 
			
		||||
@ -453,6 +462,7 @@ static int translateKey(unsigned int key)
 | 
			
		||||
-(void)dealloc
 | 
			
		||||
{
 | 
			
		||||
    [trackingArea release];
 | 
			
		||||
    free(fileNamesForDrag);
 | 
			
		||||
    [super dealloc];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -657,6 +667,72 @@ static int translateKey(unsigned int key)
 | 
			
		||||
        _glfwInputScroll(window, deltaX, deltaY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// arturoc: this makes the cursor dissapear when the window is
 | 
			
		||||
// resized or received a drag operation
 | 
			
		||||
/*- (void)resetCursorRects
 | 
			
		||||
{
 | 
			
		||||
    [self discardCursorRects];
 | 
			
		||||
    [self addCursorRect:[self bounds] cursor:_glfw.ns.cursor];
 | 
			
		||||
}*/
 | 
			
		||||
 | 
			
		||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
 | 
			
		||||
{
 | 
			
		||||
    if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) 
 | 
			
		||||
		== NSDragOperationGeneric) {
 | 
			
		||||
        
 | 
			
		||||
		[self setNeedsDisplay:YES];
 | 
			
		||||
        
 | 
			
		||||
        return NSDragOperationGeneric;
 | 
			
		||||
		
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
	return NSDragOperationNone;	
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender {
 | 
			
		||||
    [self setNeedsDisplay:YES];
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender {
 | 
			
		||||
	NSPasteboard *zPasteboard = [sender draggingPasteboard];
 | 
			
		||||
	NSArray *files = [zPasteboard propertyListForType:NSFilenamesPboardType];
 | 
			
		||||
	
 | 
			
		||||
    // set the first char to 0 so strcat
 | 
			
		||||
    // starts to add from the beginning
 | 
			
		||||
	fileNamesForDrag[0] = 0;
 | 
			
		||||
 | 
			
		||||
	int dragX = [sender draggingLocation].x;
 | 
			
		||||
	int dragY = [sender draggingLocation].y;
 | 
			
		||||
	
 | 
			
		||||
	int dragSize = 1;
 | 
			
		||||
	if ([files count]) {
 | 
			
		||||
		NSEnumerator *filenameEnum = [files objectEnumerator]; 
 | 
			
		||||
        NSString *name;
 | 
			
		||||
		while (name = [filenameEnum nextObject]) {
 | 
			
		||||
            dragSize += [name length]+1;
 | 
			
		||||
			if (dragSize > fileNamesSize){
 | 
			
		||||
                fileNamesSize *= 2;
 | 
			
		||||
                fileNamesForDrag = realloc(fileNamesForDrag, fileNamesSize);
 | 
			
		||||
            }
 | 
			
		||||
            strcat(fileNamesForDrag, [name UTF8String]);
 | 
			
		||||
            strcat(fileNamesForDrag, "\n");
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
    int height;
 | 
			
		||||
	_glfwPlatformGetWindowSize(window, NULL, &height);
 | 
			
		||||
    _glfwInputCursorMotion(window, dragX,  height-dragY);
 | 
			
		||||
    _glfwInputDrop(window, fileNamesForDrag);
 | 
			
		||||
    
 | 
			
		||||
	return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)concludeDragOperation:(id <NSDraggingInfo>)sender {
 | 
			
		||||
    [self setNeedsDisplay:YES];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										17
									
								
								src/input.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								src/input.c
									
									
									
									
									
								
							@ -211,6 +211,12 @@ void _glfwInputCursorEnter(_GLFWwindow* window, int entered)
 | 
			
		||||
        window->callbacks.cursorEnter((GLFWwindow*) window, entered);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _glfwInputDrop(_GLFWwindow* window, const char* dropString){
 | 
			
		||||
 | 
			
		||||
    if (window->callbacks.drop)
 | 
			
		||||
        window->callbacks.drop((GLFWwindow*) window, dropString);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//////////////////////////////////////////////////////////////////////////
 | 
			
		||||
//////                        GLFW public API                       //////
 | 
			
		||||
@ -394,3 +400,14 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
 | 
			
		||||
    return cbfun;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
 | 
			
		||||
{
 | 
			
		||||
    _GLFWwindow* window = (_GLFWwindow*) handle;
 | 
			
		||||
    GLFWdropfun previous;
 | 
			
		||||
 | 
			
		||||
    _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
 | 
			
		||||
 | 
			
		||||
    previous = window->callbacks.drop;
 | 
			
		||||
    window->callbacks.drop = cbfun;
 | 
			
		||||
    return previous;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -239,6 +239,7 @@ struct _GLFWwindow
 | 
			
		||||
        GLFWscrollfun           scroll;
 | 
			
		||||
        GLFWkeyfun              key;
 | 
			
		||||
        GLFWcharfun             character;
 | 
			
		||||
        GLFWdropfun             drop;
 | 
			
		||||
    } callbacks;
 | 
			
		||||
 | 
			
		||||
    // This is defined in the window API's platform.h
 | 
			
		||||
@ -678,6 +679,14 @@ void _glfwInputMonitorChange(void);
 | 
			
		||||
 */
 | 
			
		||||
void _glfwInputError(int error, const char* format, ...);
 | 
			
		||||
 | 
			
		||||
/*! @brief Notifies dropped object over window.
 | 
			
		||||
 *  @param[in] window The window that received the event.
 | 
			
		||||
 *  @param[in] dropString The string descriptor of the dropped object
 | 
			
		||||
 *  description.
 | 
			
		||||
 *  @ingroup event
 | 
			
		||||
 */
 | 
			
		||||
void _glfwInputDrop(_GLFWwindow* window, const char* dropString);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//========================================================================
 | 
			
		||||
// Utility functions
 | 
			
		||||
 | 
			
		||||
@ -215,6 +215,9 @@ int _glfwPlatformInit(void)
 | 
			
		||||
    if (!_glfwInitContextAPI())
 | 
			
		||||
        return GL_FALSE;
 | 
			
		||||
	
 | 
			
		||||
	_glfw.win32.dropString = (char*)malloc(1000);
 | 
			
		||||
	_glfw.win32.dropStringSize = 1000;
 | 
			
		||||
 | 
			
		||||
    _glfwInitTimer();
 | 
			
		||||
    _glfwInitJoysticks();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -169,6 +169,8 @@ typedef struct _GLFWlibraryWin32
 | 
			
		||||
    ATOM                classAtom;
 | 
			
		||||
    DWORD               foregroundLockTimeout;
 | 
			
		||||
    char*               clipboardString;
 | 
			
		||||
    char*				dropString;
 | 
			
		||||
	int					dropStringSize;
 | 
			
		||||
 | 
			
		||||
    // Timer data
 | 
			
		||||
    struct {
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,9 @@
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <malloc.h>
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#include <windowsx.h>
 | 
			
		||||
#include <Shellapi.h>
 | 
			
		||||
 | 
			
		||||
#define _GLFW_KEY_INVALID -2
 | 
			
		||||
 | 
			
		||||
@ -747,6 +749,39 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
 | 
			
		||||
            // TODO: Restore vsync if compositing was disabled
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case WM_DROPFILES:
 | 
			
		||||
        {
 | 
			
		||||
			TCHAR szName[MAX_PATH];
 | 
			
		||||
			HDROP hDrop = (HDROP)wParam;
 | 
			
		||||
			POINT pt;
 | 
			
		||||
			int numFiles = DragQueryFile(hDrop, 0xFFFFFFFF, szName, MAX_PATH);
 | 
			
		||||
			int currentSize = 1;
 | 
			
		||||
			int i;
 | 
			
		||||
			char* utf8str;
 | 
			
		||||
			DragQueryPoint(hDrop, &pt);
 | 
			
		||||
 | 
			
		||||
			// Move the mouse to the position of the drop
 | 
			
		||||
			_glfwInputCursorMotion(window,pt.x,pt.y);
 | 
			
		||||
			
 | 
			
		||||
			memset(_glfw.win32.dropString, 0, _glfw.win32.dropStringSize);
 | 
			
		||||
			for(i = 0; i < numFiles; i++)
 | 
			
		||||
			{
 | 
			
		||||
				DragQueryFile(hDrop, i, szName, MAX_PATH);
 | 
			
		||||
				utf8str = _glfwCreateUTF8FromWideString((const wchar_t*)szName);
 | 
			
		||||
				currentSize += strlen(utf8str);
 | 
			
		||||
				if(_glfw.win32.dropStringSize < currentSize){
 | 
			
		||||
					_glfw.win32.dropStringSize *= 2;
 | 
			
		||||
					_glfw.win32.dropString = (char*)realloc(_glfw.win32.dropString,_glfw.win32.dropStringSize);
 | 
			
		||||
				}
 | 
			
		||||
				strcat(_glfw.win32.dropString, utf8str);
 | 
			
		||||
				strcat(_glfw.win32.dropString, "\n");
 | 
			
		||||
				free(utf8str);
 | 
			
		||||
			}
 | 
			
		||||
			
 | 
			
		||||
			_glfwInputDrop(window,_glfw.win32.dropString);
 | 
			
		||||
			DragFinish(hDrop);
 | 
			
		||||
			break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
 | 
			
		||||
@ -866,6 +901,8 @@ static int createWindow(_GLFWwindow* window,
 | 
			
		||||
 | 
			
		||||
    free(wideTitle);
 | 
			
		||||
	
 | 
			
		||||
	DragAcceptFiles(window->win32.handle, TRUE);
 | 
			
		||||
 | 
			
		||||
    if (!window->win32.handle)
 | 
			
		||||
    {
 | 
			
		||||
        _glfwInputError(GLFW_PLATFORM_ERROR, "Win32: Failed to create window");
 | 
			
		||||
 | 
			
		||||
@ -32,6 +32,7 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Translate an X11 key code to a GLFW key code.
 | 
			
		||||
@ -394,7 +395,6 @@ static void detectEWMH(void)
 | 
			
		||||
                                       (unsigned char**) &supportedAtoms);
 | 
			
		||||
 | 
			
		||||
    // See which of the atoms we support that are supported by the WM
 | 
			
		||||
 | 
			
		||||
    _glfw.x11.NET_WM_STATE =
 | 
			
		||||
        getSupportedAtom(supportedAtoms, atomCount, "_NET_WM_STATE");
 | 
			
		||||
    _glfw.x11.NET_WM_STATE_FULLSCREEN =
 | 
			
		||||
@ -539,6 +539,21 @@ static GLboolean initExtensions(void)
 | 
			
		||||
    _glfw.x11.SAVE_TARGETS =
 | 
			
		||||
        XInternAtom(_glfw.x11.display, "SAVE_TARGETS", False);
 | 
			
		||||
 | 
			
		||||
    // Find or create drag and drop atoms
 | 
			
		||||
 | 
			
		||||
	//Atoms for Xdnd
 | 
			
		||||
    _glfw.x11.XdndAware = XInternAtom(_glfw.x11.display, "XdndAware", True);
 | 
			
		||||
    _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", True);
 | 
			
		||||
    _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", True);
 | 
			
		||||
    _glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", True);
 | 
			
		||||
    _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", True);
 | 
			
		||||
    _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", True);
 | 
			
		||||
    _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", True);
 | 
			
		||||
    _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", True);
 | 
			
		||||
    _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", True);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return GL_TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -119,6 +119,24 @@ typedef struct _GLFWlibraryX11
 | 
			
		||||
    Atom            NET_ACTIVE_WINDOW;
 | 
			
		||||
    Atom            MOTIF_WM_HINTS;
 | 
			
		||||
 | 
			
		||||
	// Atoms for Xdnd
 | 
			
		||||
    Atom			XdndAware;
 | 
			
		||||
	Atom 			XdndEnter;
 | 
			
		||||
	Atom 			XdndPosition;
 | 
			
		||||
	Atom 			XdndStatus;
 | 
			
		||||
	Atom 			XdndActionCopy;
 | 
			
		||||
	Atom 			XdndDrop;
 | 
			
		||||
	Atom 			XdndLeave;
 | 
			
		||||
	Atom 			XdndFinished;
 | 
			
		||||
	Atom 			XdndSelection;
 | 
			
		||||
	struct{
 | 
			
		||||
		Window 			sourceWindow;
 | 
			
		||||
		char*			string;
 | 
			
		||||
		char*			type1;
 | 
			
		||||
		char*			type2;
 | 
			
		||||
		char*			type3;
 | 
			
		||||
	} xdnd;
 | 
			
		||||
 | 
			
		||||
    // Selection atoms
 | 
			
		||||
    Atom            TARGETS;
 | 
			
		||||
    Atom            MULTIPLE;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										130
									
								
								src/x11_window.c
									
									
									
									
									
								
							
							
						
						
									
										130
									
								
								src/x11_window.c
									
									
									
									
									
								
							@ -306,6 +306,14 @@ static GLboolean createWindow(_GLFWwindow* window,
 | 
			
		||||
        XISelectEvents(_glfw.x11.display, window->x11.handle, &eventmask, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Enable Xdnd
 | 
			
		||||
    if(_glfw.x11.XdndAware!=None)
 | 
			
		||||
    {
 | 
			
		||||
    	//Announce XDND support
 | 
			
		||||
		Atom version=5;
 | 
			
		||||
		XChangeProperty(_glfw.x11.display, window->x11.handle, _glfw.x11.XdndAware, XA_ATOM, 32, PropModeReplace, (unsigned char*)&version, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _glfwPlatformSetWindowTitle(window, wndconfig->title);
 | 
			
		||||
 | 
			
		||||
    XRRSelectInput(_glfw.x11.display, window->x11.handle,
 | 
			
		||||
@ -494,6 +502,7 @@ static void leaveFullscreenMode(_GLFWwindow* window)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Process the specified X event
 | 
			
		||||
//
 | 
			
		||||
static void processEvent(XEvent *event)
 | 
			
		||||
@ -703,10 +712,128 @@ static void processEvent(XEvent *event)
 | 
			
		||||
                           False,
 | 
			
		||||
                           SubstructureNotifyMask | SubstructureRedirectMask,
 | 
			
		||||
                           event);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            else if(event->xclient.message_type == _glfw.x11.XdndEnter)
 | 
			
		||||
            {
 | 
			
		||||
            	// Xdnd Enter: the drag&drop event has started in the window,
 | 
			
		||||
            	// we could be getting the type and possible conversions here
 | 
			
		||||
            	// but since we use always string conversion we don't need
 | 
			
		||||
            	// it
 | 
			
		||||
            }
 | 
			
		||||
            else if(event->xclient.message_type == _glfw.x11.XdndDrop)
 | 
			
		||||
            {
 | 
			
		||||
            	// Xdnd Drop: The drag&drop event has finished dropping on
 | 
			
		||||
            	// the window, ask to convert the selection
 | 
			
		||||
            	_glfw.x11.xdnd.sourceWindow = event->xclient.data.l[0];
 | 
			
		||||
				XConvertSelection(_glfw.x11.display,
 | 
			
		||||
								  _glfw.x11.XdndSelection,
 | 
			
		||||
								  _glfw.x11.UTF8_STRING,
 | 
			
		||||
								  _glfw.x11.XdndSelection,
 | 
			
		||||
								  window->x11.handle, CurrentTime);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            else if(event->xclient.message_type == _glfw.x11.XdndLeave)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            else if(event->xclient.message_type == _glfw.x11.XdndPosition)
 | 
			
		||||
            {
 | 
			
		||||
            	// Xdnd Position: get coordinates of the mouse inside the window
 | 
			
		||||
            	// and update the mouse position
 | 
			
		||||
            	int absX = (event->xclient.data.l[2]>>16) & 0xFFFF;
 | 
			
		||||
            	int absY = (event->xclient.data.l[2]) & 0xFFFF;
 | 
			
		||||
            	int x;
 | 
			
		||||
            	int y;
 | 
			
		||||
 | 
			
		||||
            	_glfwPlatformGetWindowPos(window,&x,&y);
 | 
			
		||||
 | 
			
		||||
            	_glfwInputCursorMotion(window,absX-x,absY-y);
 | 
			
		||||
 | 
			
		||||
				// Xdnd: reply with an XDND status message
 | 
			
		||||
				XClientMessageEvent m;
 | 
			
		||||
				memset(&m, sizeof(m), 0);
 | 
			
		||||
				m.type = ClientMessage;
 | 
			
		||||
				m.display = event->xclient.display;
 | 
			
		||||
				m.window = event->xclient.data.l[0];
 | 
			
		||||
				m.message_type = _glfw.x11.XdndStatus;
 | 
			
		||||
				m.format=32;
 | 
			
		||||
				m.data.l[0] = window->x11.handle;
 | 
			
		||||
				m.data.l[1] = 1; // Always accept the dnd with no rectangle
 | 
			
		||||
				m.data.l[2] = 0; // Specify an empty rectangle
 | 
			
		||||
				m.data.l[3] = 0;
 | 
			
		||||
				m.data.l[4] = _glfw.x11.XdndActionCopy; // We only accept copying
 | 
			
		||||
 | 
			
		||||
				XSendEvent(_glfw.x11.display, event->xclient.data.l[0], False, NoEventMask, (XEvent*)&m);
 | 
			
		||||
				XFlush(_glfw.x11.display);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        case SelectionNotify:
 | 
			
		||||
		{
 | 
			
		||||
			if(event->xselection.property != None)
 | 
			
		||||
			{
 | 
			
		||||
				// Xdnd: got a selection notification from the conversion
 | 
			
		||||
				// we asked for, get the data and finish the d&d event
 | 
			
		||||
				char* data;
 | 
			
		||||
				free(_glfw.x11.xdnd.string);
 | 
			
		||||
				_glfw.x11.xdnd.string = NULL;
 | 
			
		||||
				int result = _glfwGetWindowProperty(event->xselection.requestor,
 | 
			
		||||
				                                   event->xselection.property,
 | 
			
		||||
				                                   event->xselection.target,
 | 
			
		||||
				                                   (unsigned char**) &data);
 | 
			
		||||
 | 
			
		||||
				if(result){
 | 
			
		||||
					// nautilus seems to add a \r at the end of the paths
 | 
			
		||||
					// remove it so paths can be directly used
 | 
			
		||||
					_glfw.x11.xdnd.string = malloc(strlen(data));
 | 
			
		||||
					char *to = _glfw.x11.xdnd.string;
 | 
			
		||||
					const char *from = data;
 | 
			
		||||
					const char *current = strchr(from, '\r');
 | 
			
		||||
					while(current)
 | 
			
		||||
					{
 | 
			
		||||
						int charsToCopy = current - from;
 | 
			
		||||
						memcpy(to, from, (size_t)charsToCopy);
 | 
			
		||||
						to += charsToCopy;
 | 
			
		||||
 | 
			
		||||
						from = current+1;
 | 
			
		||||
						current = strchr(from, '\r');
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					size_t remaining = strlen(from);
 | 
			
		||||
 | 
			
		||||
					memcpy(to, from, remaining);
 | 
			
		||||
					to += remaining;
 | 
			
		||||
					*to = 0;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				XClientMessageEvent m;
 | 
			
		||||
				memset(&m, sizeof(m), 0);
 | 
			
		||||
				m.type = ClientMessage;
 | 
			
		||||
				m.display = _glfw.x11.display;
 | 
			
		||||
				m.window = _glfw.x11.xdnd.sourceWindow;
 | 
			
		||||
				m.message_type = _glfw.x11.XdndFinished;
 | 
			
		||||
				m.format=32;
 | 
			
		||||
				m.data.l[0] = window->x11.handle;
 | 
			
		||||
				m.data.l[1] = result;
 | 
			
		||||
				m.data.l[2] = _glfw.x11.XdndActionCopy; //We only ever copy.
 | 
			
		||||
 | 
			
		||||
				// Reply that all is well.
 | 
			
		||||
				XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.sourceWindow, False, NoEventMask, (XEvent*)&m);
 | 
			
		||||
 | 
			
		||||
				XSync(_glfw.x11.display, False);
 | 
			
		||||
 | 
			
		||||
				XFree(data);
 | 
			
		||||
 | 
			
		||||
				if(result)
 | 
			
		||||
				{
 | 
			
		||||
					_glfwInputDrop(window,_glfw.x11.xdnd.string);
 | 
			
		||||
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
        case MapNotify:
 | 
			
		||||
        {
 | 
			
		||||
@ -897,7 +1024,7 @@ unsigned long _glfwGetWindowProperty(Window window,
 | 
			
		||||
                       &bytesAfter,
 | 
			
		||||
                       value);
 | 
			
		||||
 | 
			
		||||
    if (actualType != type)
 | 
			
		||||
    if (type != AnyPropertyType && actualType != type)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    return itemCount;
 | 
			
		||||
@ -1001,7 +1128,6 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos)
 | 
			
		||||
    if (child)
 | 
			
		||||
    {
 | 
			
		||||
        int left, top;
 | 
			
		||||
 | 
			
		||||
        XTranslateCoordinates(_glfw.x11.display, window->x11.handle, child,
 | 
			
		||||
                              0, 0, &left, &top, &child);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user