[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