]> git.sesse.net Git - vlc/blob - modules/gui/skins2/x11/x11_dragdrop.cpp
skins2: drap&drop enhancement
[vlc] / modules / gui / skins2 / x11 / x11_dragdrop.cpp
1 /*****************************************************************************
2  * x11_dragdrop.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet     <asmax@via.ecp.fr>
8  *          Olivier Teulière <ipkiss@via.ecp.fr>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #ifdef X11_SKINS
26
27 #include <X11/Xlib.h>
28 #include <X11/Xatom.h>
29
30 #include "x11_dragdrop.hpp"
31 #include "x11_display.hpp"
32 #include "x11_factory.hpp"
33 #include "../commands/cmd_add_item.hpp"
34 #include "../events/evt_dragndrop.hpp"
35
36 #include <string>
37 #include <list>
38
39
40 X11DragDrop::X11DragDrop( intf_thread_t *pIntf, X11Display &rDisplay,
41                           Window win, bool playOnDrop, GenericWindow *pWin ):
42     SkinObject( pIntf ), m_rDisplay( rDisplay ), m_wnd( win ),
43     m_playOnDrop( playOnDrop ), m_pWin( pWin ), m_xPos( -1 ), m_yPos( -1 )
44 {
45 }
46
47
48 void X11DragDrop::dndEnter( ldata_t data )
49 {
50     Window src = data[0];
51     m_xPos = m_yPos = -1;
52
53     // Retrieve available data types
54     list<string> dataTypes;
55     if( data[1] & 1 )   // More than 3 data types ?
56     {
57         Atom type;
58         int format;
59         unsigned long nitems, nbytes;
60         Atom *dataList;
61         Atom typeListAtom = XInternAtom( XDISPLAY, "XdndTypeList", 0 );
62         XGetWindowProperty( XDISPLAY, src, typeListAtom, 0, 65536, False,
63                             XA_ATOM, &type, &format, &nitems, &nbytes,
64                             (unsigned char**)&dataList );
65         for( unsigned long i=0; i<nitems; i++ )
66         {
67             string dataType = XGetAtomName( XDISPLAY, dataList[i] );
68             dataTypes.push_back( dataType );
69         }
70         XFree( (void*)dataList );
71     }
72     else
73     {
74         for( int i = 2; i < 5; i++ )
75         {
76             if( data[i] != None )
77             {
78                 string dataType = XGetAtomName( XDISPLAY, data[i] );
79                 dataTypes.push_back( dataType );
80             }
81         }
82     }
83
84     // Find the right target
85     m_target = None;
86     list<string>::iterator it;
87     for( it = dataTypes.begin(); it != dataTypes.end(); ++it )
88     {
89         if( *it == "text/uri-list" ||
90             *it == "text/plain" ||
91             *it == "STRING" )
92         {
93             m_target = XInternAtom( XDISPLAY, (*it).c_str(), 0 );
94             break;
95         }
96     }
97
98     // transmit DragEnter event
99     EvtDragEnter evt( getIntf() );
100     m_pWin->processEvent( evt );
101 }
102
103
104 void X11DragDrop::dndPosition( ldata_t data )
105 {
106     Window src = data[0];
107     //Time time = data[3];
108     m_xPos = data[2] >> 16;
109     m_yPos = data[2] & 0xffff;
110
111     Atom selectionAtom = XInternAtom( XDISPLAY, "XdndSelection", 0 );
112     //Atom targetAtom = XInternAtom( XDISPLAY, "text/plain", 0 );
113     Atom targetAtom = XInternAtom( XDISPLAY, "text/uri-list", 0 );
114     Atom propAtom = XInternAtom( XDISPLAY, "VLC_SELECTION", 0 );
115
116     Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
117     Atom typeAtom = XInternAtom( XDISPLAY, "XdndFinished", 0 );
118
119     // Convert the selection into the given target
120     // NEEDED or it doesn't work!
121     XConvertSelection( XDISPLAY, selectionAtom, targetAtom, propAtom, src,
122                        CurrentTime );
123
124     actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
125     typeAtom = XInternAtom( XDISPLAY, "XdndStatus", 0 );
126
127     XEvent event;
128     event.type = ClientMessage;
129     event.xclient.window = src;
130     event.xclient.display = XDISPLAY;
131     event.xclient.message_type = typeAtom;
132     event.xclient.format = 32;
133     event.xclient.data.l[0] = m_wnd;
134     // Accept the drop (1), or not (0).
135     event.xclient.data.l[1] = m_target != None ? 1 : 0;
136     event.xclient.data.l[2] = 0;
137     event.xclient.data.l[3] = 0;
138     event.xclient.data.l[4] = actionAtom;
139
140     // Tell the source whether we accept the drop
141     XSendEvent( XDISPLAY, src, False, 0, &event );
142
143     // transmit DragOver event
144     EvtDragOver evt( getIntf(), m_xPos, m_yPos );
145     m_pWin->processEvent( evt );
146 }
147
148
149 void X11DragDrop::dndLeave( ldata_t data )
150 {
151     (void)data;
152     // transmit DragLeave event
153     EvtDragLeave evt( getIntf() );
154     m_pWin->processEvent( evt );
155 }
156
157
158 void X11DragDrop::dndDrop( ldata_t data )
159 {
160     list<string> files;
161
162     Window src = data[0];
163     Time time = data[2];
164
165     Atom selectionAtom = XInternAtom( XDISPLAY, "XdndSelection", 0 );
166     Atom targetAtom = XInternAtom( XDISPLAY, "text/uri-list", 0 );
167     Atom propAtom = XInternAtom( XDISPLAY, "VLC_SELECTION", 0 );
168
169     Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
170     Atom typeAtom = XInternAtom( XDISPLAY, "XdndFinished", 0 );
171
172     // Convert the selection into the given target
173     XConvertSelection( XDISPLAY, selectionAtom, targetAtom, propAtom, src,
174                        time );
175
176     // Read the selection
177     Atom type;
178     int format;
179     unsigned long nitems, nbytes;
180     char *buffer;
181     XGetWindowProperty( XDISPLAY, src, propAtom, 0, 1024, False,
182                         AnyPropertyType, &type, &format, &nitems, &nbytes,
183                         (unsigned char**)&buffer );
184     if( buffer != NULL )
185     {
186         char* psz_dup = strdup( buffer );
187         char* psz_new = psz_dup;
188         while( psz_new && *psz_new )
189         {
190             int skip = 0;
191             const char* sep[] = { "\r\n", "\n", NULL };
192             for( int i = 0; sep[i]; i++ )
193             {
194                 char* psz_end = strstr( psz_new, sep[i] );
195                 if( !psz_end )
196                     continue;
197                 *psz_end = '\0';
198                 skip = strlen( sep[i] );
199                 break;
200             }
201             if( *psz_new )
202             {
203                 files.push_back( psz_new );
204             }
205
206             psz_new += strlen( psz_new ) + skip;
207         }
208         free( psz_dup );
209         XFree( buffer );
210     }
211
212     // Tell the source we accepted the drop
213     XEvent event;
214     event.type = ClientMessage;
215     event.xclient.window = src;
216     event.xclient.display = XDISPLAY;
217     event.xclient.message_type = typeAtom;
218     event.xclient.format = 32;
219     event.xclient.data.l[0] = m_wnd;
220     event.xclient.data.l[1] = 1;            // drop accepted
221     event.xclient.data.l[2] = actionAtom;
222     XSendEvent( XDISPLAY, src, False, 0, &event );
223
224     // transmit DragDrop event
225     EvtDragDrop evt( getIntf(), m_xPos, m_yPos, files );
226     m_pWin->processEvent( evt );
227 }
228
229 #endif