[vlc-commits] skins2(x11): improve Drag&Drop
Erwan Tulou
git at videolan.org
Sun Jan 21 20:37:35 CET 2018
vlc | branch: master | Erwan Tulou <erwan10 at videolan.org> | Sun Jan 21 13:12:20 2018 +0100| [b4e31d4bc28d99b101838f954fc8378e5cecb2ee] | committer: Erwan Tulou
skins2(x11): improve Drag&Drop
Rely on the XSelectionNotify event to ascertain DragNDrop data are available
instead of blindly querying the property.
This does fix Drag and Drop sometimes non functioning.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=b4e31d4bc28d99b101838f954fc8378e5cecb2ee
---
modules/gui/skins2/x11/x11_dragdrop.cpp | 106 +++++++++++++++++---------------
modules/gui/skins2/x11/x11_dragdrop.hpp | 1 +
modules/gui/skins2/x11/x11_loop.cpp | 20 ++++++
3 files changed, 77 insertions(+), 50 deletions(-)
diff --git a/modules/gui/skins2/x11/x11_dragdrop.cpp b/modules/gui/skins2/x11/x11_dragdrop.cpp
index 9244a2532e..9cfd4e7bbb 100644
--- a/modules/gui/skins2/x11/x11_dragdrop.cpp
+++ b/modules/gui/skins2/x11/x11_dragdrop.cpp
@@ -61,9 +61,10 @@ void X11DragDrop::dndEnter( ldata_t data )
unsigned long nitems, nbytes;
Atom *dataList;
Atom typeListAtom = XInternAtom( XDISPLAY, "XdndTypeList", 0 );
- XGetWindowProperty( XDISPLAY, src, typeListAtom, 0, 65536, False,
- XA_ATOM, &type, &format, &nitems, &nbytes,
- (unsigned char**)&dataList );
+ if( XGetWindowProperty( XDISPLAY, src, typeListAtom, 0, 65536,
+ False, XA_ATOM, &type, &format, &nitems, &nbytes,
+ (unsigned char**)&dataList ) != Success )
+ return;
for( unsigned long i=0; i<nitems; i++ )
{
std::string dataType = XGetAtomName( XDISPLAY, dataList[i] );
@@ -88,20 +89,28 @@ void X11DragDrop::dndEnter( ldata_t data )
for( it = dataTypes.begin(); it != dataTypes.end(); ++it )
msg_Dbg( getIntf(), "D&D data type: %s", (*it).c_str() );
- // Find the right target
+ // data formats we accept sorted by preference
+ static const char* preferred[] = {
+ "text/uri-list",
+ "text/plain;charset=utf-8",
+ "text/plain",
+ "UTF8_STRING",
+ "STRING",
+ };
m_target = None;
- for( it = dataTypes.begin(); it != dataTypes.end(); ++it )
+ for( unsigned i = 0; i < sizeof(preferred)/sizeof(preferred[0]); i++ )
{
- if( *it == "text/uri-list" ||
- *it == "text/plain" ||
- *it == "text/plain;charset=utf-8" ||
- *it == "STRING" ||
- *it == "UTF8_STRING" )
+ for( it = dataTypes.begin(); it != dataTypes.end(); ++it )
{
- m_target = XInternAtom( XDISPLAY, (*it).c_str(), 0 );
- msg_Dbg( getIntf(), "D&D data type chosen: %s", (*it).c_str() );
- break;
+ if( *it == preferred[i] )
+ {
+ m_target = XInternAtom( XDISPLAY, (*it).c_str(), 0 );
+ msg_Dbg( getIntf(), "Selected type: %s", (*it).c_str() );
+ break;
+ }
}
+ if( m_target != None )
+ break;
}
// transmit DragEnter event
@@ -162,32 +171,44 @@ void X11DragDrop::dndDrop( ldata_t data )
Window src = data[0];
Time time = data[2];
+ // Convert the selection into the given target
Atom selectionAtom = XInternAtom( XDISPLAY, "XdndSelection", 0 );
Atom propAtom = XInternAtom( XDISPLAY, "VLC_SELECTION", 0 );
- // Convert the selection into the given target
- XConvertSelection( XDISPLAY, selectionAtom, m_target, propAtom, src,
- time );
- // Needed to ensure XGetWindowProperty returns something
- XSync( XDISPLAY, False );
+ XConvertSelection( XDISPLAY, selectionAtom, m_target, propAtom,
+ m_wnd, time );
+
+
+ // Tell the source we accepted the drop
+ Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
+ Atom typeAtom = XInternAtom( XDISPLAY, "XdndFinished", 0 );
+ XEvent event;
+ event.type = ClientMessage;
+ event.xclient.window = src;
+ event.xclient.display = XDISPLAY;
+ event.xclient.message_type = typeAtom;
+ event.xclient.format = 32;
+ event.xclient.data.l[0] = m_wnd;
+ event.xclient.data.l[1] = 1; // drop accepted
+ event.xclient.data.l[2] = actionAtom;
+ XSendEvent( XDISPLAY, src, False, 0, &event );
+}
+
+
+void X11DragDrop::dndSelectionNotify( )
+{
+ std::list<std::string> files;
// Read the selection
Atom type;
int format;
unsigned long nitems, nbytes_after_return;
char *buffer;
- long length_max = 1024;
- XGetWindowProperty( XDISPLAY, src, propAtom, 0, length_max, False,
- AnyPropertyType, &type, &format, &nitems,
- &nbytes_after_return, (unsigned char**)&buffer );
- if( buffer && nbytes_after_return > 0 )
- {
- XFree( buffer );
- length_max += nbytes_after_return;
- XGetWindowProperty( XDISPLAY, src, propAtom, 0, length_max, False,
- AnyPropertyType, &type, &format, &nitems,
- &nbytes_after_return, (unsigned char**)&buffer );
- }
- if( buffer != NULL )
+ Atom propAtom = XInternAtom( XDISPLAY, "VLC_SELECTION", 0 );
+ int ret = XGetWindowProperty( XDISPLAY, m_wnd, propAtom, 0, 65536, True,
+ AnyPropertyType, &type, &format, &nitems,
+ &nbytes_after_return,
+ (unsigned char**)&buffer );
+ if( ret == Success && buffer != NULL )
{
msg_Dbg( getIntf(), "buffer received: %s", buffer );
char* psz_dup = strdup( buffer );
@@ -214,26 +235,11 @@ void X11DragDrop::dndDrop( ldata_t data )
}
free( psz_dup );
XFree( buffer );
- }
-
- Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
- Atom typeAtom = XInternAtom( XDISPLAY, "XdndFinished", 0 );
- // Tell the source we accepted the drop
- XEvent event;
- event.type = ClientMessage;
- event.xclient.window = src;
- event.xclient.display = XDISPLAY;
- event.xclient.message_type = typeAtom;
- event.xclient.format = 32;
- event.xclient.data.l[0] = m_wnd;
- event.xclient.data.l[1] = 1; // drop accepted
- event.xclient.data.l[2] = actionAtom;
- XSendEvent( XDISPLAY, src, False, 0, &event );
-
- // transmit DragDrop event
- EvtDragDrop evt( getIntf(), m_xPos, m_yPos, files );
- m_pWin->processEvent( evt );
+ // transmit DragDrop event
+ EvtDragDrop evt( getIntf(), m_xPos, m_yPos, files );
+ m_pWin->processEvent( evt );
+ }
}
#endif
diff --git a/modules/gui/skins2/x11/x11_dragdrop.hpp b/modules/gui/skins2/x11/x11_dragdrop.hpp
index a4fbbd67a0..968c2c1a04 100644
--- a/modules/gui/skins2/x11/x11_dragdrop.hpp
+++ b/modules/gui/skins2/x11/x11_dragdrop.hpp
@@ -45,6 +45,7 @@ public:
void dndPosition( ldata_t data );
void dndLeave( ldata_t data );
void dndDrop( ldata_t data );
+ void dndSelectionNotify( );
private:
/// X11 display
diff --git a/modules/gui/skins2/x11/x11_loop.cpp b/modules/gui/skins2/x11/x11_loop.cpp
index 4355c9f232..54e4102aa2 100644
--- a/modules/gui/skins2/x11/x11_loop.cpp
+++ b/modules/gui/skins2/x11/x11_loop.cpp
@@ -360,6 +360,26 @@ void X11Loop::handleX11Event()
pDnd->dndDrop( event.xclient.data.l );
break;
}
+
+ case SelectionNotify:
+ {
+ // Check XConvertSelection completion
+ if( event.xselection.property == None )
+ {
+ msg_Err( getIntf(), "Convertion failed for Drag&Drop" );
+ return;
+ }
+
+ // Find the DnD object for this window
+ X11DragDrop *pDnd = pFactory->m_dndMap[event.xselection.requestor];
+ if( !pDnd )
+ {
+ msg_Err( getIntf(), "no associated D&D object" );
+ return;
+ }
+ pDnd->dndSelectionNotify( );
+ }
+
}
}
More information about the vlc-commits
mailing list