@ -48,6 +48,8 @@
# define Button6 6
# define Button7 7
# define _GLFW_XDND_VERSION 5
// Wait for data to arrive using select
// This avoids blocking other threads via the per-display Xlib lock that also
@ -415,7 +417,12 @@ static char** parseUriList(char* text, int* count)
continue ;
if ( strncmp ( line , prefix , strlen ( prefix ) ) = = 0 )
{
line + = strlen ( prefix ) ;
// TODO: Validate hostname
while ( * line ! = ' / ' )
line + + ;
}
( * count ) + + ;
@ -619,10 +626,9 @@ static GLFWbool createNativeWindow(_GLFWwindow* window,
XFree ( hint ) ;
}
if ( _glfw . x11 . XdndAware )
// Announce support for Xdnd (drag and drop)
{
// Announce support for Xdnd (drag and drop)
const Atom version = 5 ;
const Atom version = _GLFW_XDND_VERSION ;
XChangeProperty ( _glfw . x11 . display , window - > x11 . handle ,
_glfw . x11 . XdndAware , XA_ATOM , 32 ,
PropModeReplace , ( unsigned char * ) & version , 1 ) ;
@ -1307,44 +1313,121 @@ static void processEvent(XEvent *event)
else if ( event - > xclient . message_type = = _glfw . x11 . XdndEnter )
{
// A drag operation has entered the window
// TODO: Check if UTF-8 string is supported by the source
unsigned long i , count ;
Atom * formats = NULL ;
const GLFWbool list = event - > xclient . data . l [ 1 ] & 1 ;
_glfw . x11 . xdnd . source = event - > xclient . data . l [ 0 ] ;
_glfw . x11 . xdnd . version = event - > xclient . data . l [ 1 ] > > 24 ;
_glfw . x11 . xdnd . format = None ;
if ( _glfw . x11 . xdnd . version > _GLFW_XDND_VERSION )
return ;
if ( list )
{
count = _glfwGetWindowPropertyX11 ( _glfw . x11 . xdnd . source ,
_glfw . x11 . XdndTypeList ,
XA_ATOM ,
( unsigned char * * ) & formats ) ;
}
else
{
count = 3 ;
formats = ( Atom * ) event - > xclient . data . l + 2 ;
}
for ( i = 0 ; i < count ; i + + )
{
if ( formats [ i ] = = _glfw . x11 . text_uri_list )
{
_glfw . x11 . xdnd . format = _glfw . x11 . text_uri_list ;
break ;
}
}
if ( list & & formats )
XFree ( formats ) ;
}
else if ( event - > xclient . message_type = = _glfw . x11 . XdndDrop )
{
// The drag operation has finished dropping on
// the window, ask to convert it to a UTF-8 string
_glfw . x11 . xdnd . source = event - > xclient . data . l [ 0 ] ;
XConvertSelection ( _glfw . x11 . display ,
_glfw . x11 . XdndSelection ,
_glfw . x11 . UTF8_STRING ,
_glfw . x11 . XdndSelection ,
window - > x11 . handle , CurrentTime ) ;
// The drag operation has finished by dropping on the window
Time time = CurrentTime ;
if ( _glfw . x11 . xdnd . version > _GLFW_XDND_VERSION )
return ;
if ( _glfw . x11 . xdnd . format )
{
if ( _glfw . x11 . xdnd . version > = 1 )
time = event - > xclient . data . l [ 2 ] ;
// Request the chosen format from the source window
XConvertSelection ( _glfw . x11 . display ,
_glfw . x11 . XdndSelection ,
_glfw . x11 . xdnd . format ,
_glfw . x11 . XdndSelection ,
window - > x11 . handle ,
time ) ;
}
else if ( _glfw . x11 . xdnd . version > = 2 )
{
XEvent reply ;
memset ( & reply , 0 , sizeof ( reply ) ) ;
reply . type = ClientMessage ;
reply . xclient . window = _glfw . x11 . xdnd . source ;
reply . xclient . message_type = _glfw . x11 . XdndFinished ;
reply . xclient . format = 32 ;
reply . xclient . data . l [ 0 ] = window - > x11 . handle ;
reply . xclient . data . l [ 1 ] = 0 ; // The drag was rejected
reply . xclient . data . l [ 2 ] = None ;
XSendEvent ( _glfw . x11 . display , _glfw . x11 . xdnd . source ,
False , NoEventMask , & reply ) ;
XFlush ( _glfw . x11 . display ) ;
}
}
else if ( event - > xclient . message_type = = _glfw . x11 . XdndPosition )
{
// The drag operation has moved over the window
const int absX = ( event - > xclient . data . l [ 2 ] > > 16 ) & 0xFFFF ;
const int absY = ( event - > xclient . data . l [ 2 ] ) & 0xFFFF ;
int x , y ;
const int xabs = ( event - > xclient . data . l [ 2 ] > > 16 ) & 0xffff ;
const int yabs = ( event - > xclient . data . l [ 2 ] ) & 0xffff ;
Window dummy ;
int xpos , ypos ;
if ( _glfw . x11 . xdnd . version > _GLFW_XDND_VERSION )
return ;
XTranslateCoordinates ( _glfw . x11 . display ,
window - > x11 . handle ,
_glfw . x11 . root ,
xabs , yabs ,
& xpos , & ypos ,
& dummy ) ;
_glfwPlatformGetWindowPos ( window , & x , & y ) ;
_glfwInputCursorPos ( window , absX - x , absY - y ) ;
_glfwInputCursorPos ( window , xpos , ypos ) ;
// Reply that we are ready to copy the dragged data
XEvent reply ;
memset ( & reply , 0 , sizeof ( reply ) ) ;
reply . type = ClientMessage ;
reply . xclient . window = event - > xclient . data . l [ 0 ] ;
reply . xclient . window = _glfw . x11 . xdnd . source ;
reply . xclient . message_type = _glfw . x11 . XdndStatus ;
reply . xclient . format = 32 ;
reply . xclient . data . l [ 0 ] = window - > x11 . handle ;
reply . xclient . data . l [ 1 ] = 1 ; // Always accept the dnd with no rectangle
reply . xclient . data . l [ 2 ] = 0 ; // Specify an empty rectangle
reply . xclient . data . l [ 3 ] = 0 ;
reply . xclient . data . l [ 4 ] = _glfw . x11 . XdndActionCopy ;
XSendEvent ( _glfw . x11 . display , event - > xclient . data . l [ 0 ] ,
if ( _glfw . x11 . xdnd . format )
{
// Reply that we are ready to copy the dragged data
reply . xclient . data . l [ 1 ] = 1 ; // Accept with no rectangle
if ( _glfw . x11 . xdnd . version > = 2 )
reply . xclient . data . l [ 4 ] = _glfw . x11 . XdndActionCopy ;
}
XSendEvent ( _glfw . x11 . display , _glfw . x11 . xdnd . source ,
False , NoEventMask , & reply ) ;
XFlush ( _glfw . x11 . display ) ;
}
@ -1354,11 +1437,11 @@ static void processEvent(XEvent *event)
case SelectionNotify :
{
if ( event - > xselection . property )
if ( event - > xselection . property = = _glfw . x11 . XdndSelection )
{
// The converted data from the drag operation has arrived
char * data ;
const int result =
const uns ig ned long result =
_glfwGetWindowPropertyX11 ( event - > xselection . requestor ,
event - > xselection . property ,
event - > xselection . target ,
@ -1379,21 +1462,23 @@ static void processEvent(XEvent *event)
if ( data )
XFree ( data ) ;
XEvent reply ;
memset ( & reply , 0 , sizeof ( reply ) ) ;
reply . type = ClientMessage ;
reply . xclient . window = _glfw . x11 . xdnd . source ;
reply . xclient . message_type = _glfw . x11 . XdndFinished ;
reply . xclient . format = 32 ;
reply . xclient . data . l [ 0 ] = window - > x11 . handle ;
reply . xclient . data . l [ 1 ] = result ;
reply . xclient . data . l [ 2 ] = _glfw . x11 . XdndActionCopy ;
// Reply that all is well
XSendEvent ( _glfw . x11 . display , _glfw . x11 . xdnd . source ,
False , NoEventMask , & reply ) ;
XFlush ( _glfw . x11 . display ) ;
if ( _glfw . x11 . xdnd . version > = 2 )
{
XEvent reply ;
memset ( & reply , 0 , sizeof ( reply ) ) ;
reply . type = ClientMessage ;
reply . xclient . window = _glfw . x11 . xdnd . source ;
reply . xclient . message_type = _glfw . x11 . XdndFinished ;
reply . xclient . format = 32 ;
reply . xclient . data . l [ 0 ] = window - > x11 . handle ;
reply . xclient . data . l [ 1 ] = result ;
reply . xclient . data . l [ 2 ] = _glfw . x11 . XdndActionCopy ;
XSendEvent ( _glfw . x11 . display , _glfw . x11 . xdnd . source ,
False , NoEventMask , & reply ) ;
XFlush ( _glfw . x11 . display ) ;
}
}
return ;