1 /*****************************************************************************
2 * x11_dragdrop.cpp
3 *****************************************************************************
4 * Copyright (C) 2003 the VideoLAN team
5 * $Id: 9244a2532e9c167023384abeba9489e187e83f1f $
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
X11DragDrop(intf_thread_t * pIntf,X11Display & rDisplay,Window win,bool playOnDrop,GenericWindow * pWin)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
dndEnter(ldata_t data)48 void X11DragDrop::dndEnter( ldata_t data )
49 {
50 Window src = data[0];
51 int version = data[1]>>24;
52 m_xPos = m_yPos = -1;
53 (void)version;
54
55 // Retrieve available data types
56 std::list<std::string> dataTypes;
57 if( data[1] & 1 ) // More than 3 data types ?
58 {
59 Atom type;
60 int format;
61 unsigned long nitems, nbytes;
62 Atom *dataList;
63 Atom typeListAtom = XInternAtom( XDISPLAY, "XdndTypeList", 0 );
64 XGetWindowProperty( XDISPLAY, src, typeListAtom, 0, 65536, False,
65 XA_ATOM, &type, &format, &nitems, &nbytes,
66 (unsigned char**)&dataList );
67 for( unsigned long i=0; i<nitems; i++ )
68 {
69 std::string dataType = XGetAtomName( XDISPLAY, dataList[i] );
70 dataTypes.push_back( dataType );
71 }
72 XFree( (void*)dataList );
73 }
74 else
75 {
76 for( int i = 2; i < 5; i++ )
77 {
78 if( data[i] != None )
79 {
80 std::string dataType = XGetAtomName( XDISPLAY, data[i] );
81 dataTypes.push_back( dataType );
82 }
83 }
84 }
85
86 // list all data types available
87 std::list<std::string>::iterator it;
88 for( it = dataTypes.begin(); it != dataTypes.end(); ++it )
89 msg_Dbg( getIntf(), "D&D data type: %s", (*it).c_str() );
90
91 // Find the right target
92 m_target = None;
93 for( it = dataTypes.begin(); it != dataTypes.end(); ++it )
94 {
95 if( *it == "text/uri-list" ||
96 *it == "text/plain" ||
97 *it == "text/plain;charset=utf-8" ||
98 *it == "STRING" ||
99 *it == "UTF8_STRING" )
100 {
101 m_target = XInternAtom( XDISPLAY, (*it).c_str(), 0 );
102 msg_Dbg( getIntf(), "D&D data type chosen: %s", (*it).c_str() );
103 break;
104 }
105 }
106
107 // transmit DragEnter event
108 EvtDragEnter evt( getIntf() );
109 m_pWin->processEvent( evt );
110 }
111
112
dndPosition(ldata_t data)113 void X11DragDrop::dndPosition( ldata_t data )
114 {
115 Window src = data[0];
116 m_xPos = data[2] >> 16;
117 m_yPos = data[2] & 0xffff;
118 Time time = data[3];
119 Atom action = data[4];
120 (void)time; (void)action;
121
122 Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
123 Atom typeAtom = XInternAtom( XDISPLAY, "XdndStatus", 0 );
124
125 XEvent event;
126 event.type = ClientMessage;
127 event.xclient.window = src;
128 event.xclient.display = XDISPLAY;
129 event.xclient.message_type = typeAtom;
130 event.xclient.format = 32;
131 event.xclient.data.l[0] = m_wnd;
132 // Accept the drop (1), or not (0).
133 event.xclient.data.l[1] = m_target != None ? 1 : 0;
134 event.xclient.data.l[2] = 0;
135 event.xclient.data.l[3] = 0;
136 event.xclient.data.l[4] = actionAtom;
137
138 // Tell the source whether we accept the drop
139 XSendEvent( XDISPLAY, src, False, 0, &event );
140
141 // transmit DragOver event
142 EvtDragOver evt( getIntf(), m_xPos, m_yPos );
143 m_pWin->processEvent( evt );
144 }
145
146
dndLeave(ldata_t data)147 void X11DragDrop::dndLeave( ldata_t data )
148 {
149 (void)data;
150 m_target = None;
151
152 // transmit DragLeave event
153 EvtDragLeave evt( getIntf() );
154 m_pWin->processEvent( evt );
155 }
156
157
dndDrop(ldata_t data)158 void X11DragDrop::dndDrop( ldata_t data )
159 {
160 std::list<std::string> files;
161
162 Window src = data[0];
163 Time time = data[2];
164
165 Atom selectionAtom = XInternAtom( XDISPLAY, "XdndSelection", 0 );
166 Atom propAtom = XInternAtom( XDISPLAY, "VLC_SELECTION", 0 );
167 // Convert the selection into the given target
168 XConvertSelection( XDISPLAY, selectionAtom, m_target, propAtom, src,
169 time );
170 // Needed to ensure XGetWindowProperty returns something
171 XSync( XDISPLAY, False );
172
173 // Read the selection
174 Atom type;
175 int format;
176 unsigned long nitems, nbytes_after_return;
177 char *buffer;
178 long length_max = 1024;
179 XGetWindowProperty( XDISPLAY, src, propAtom, 0, length_max, False,
180 AnyPropertyType, &type, &format, &nitems,
181 &nbytes_after_return, (unsigned char**)&buffer );
182 if( buffer && nbytes_after_return > 0 )
183 {
184 XFree( buffer );
185 length_max += nbytes_after_return;
186 XGetWindowProperty( XDISPLAY, src, propAtom, 0, length_max, False,
187 AnyPropertyType, &type, &format, &nitems,
188 &nbytes_after_return, (unsigned char**)&buffer );
189 }
190 if( buffer != NULL )
191 {
192 msg_Dbg( getIntf(), "buffer received: %s", buffer );
193 char* psz_dup = strdup( buffer );
194 char* psz_new = psz_dup;
195 while( psz_new && *psz_new )
196 {
197 int skip = 0;
198 const char* sep[] = { "\r\n", "\n", NULL };
199 for( int i = 0; sep[i]; i++ )
200 {
201 char* psz_end = strstr( psz_new, sep[i] );
202 if( !psz_end )
203 continue;
204 *psz_end = '\0';
205 skip = strlen( sep[i] );
206 break;
207 }
208 if( *psz_new && strstr( psz_new, "://" ) )
209 {
210 files.push_back( psz_new );
211 }
212
213 psz_new += strlen( psz_new ) + skip;
214 }
215 free( psz_dup );
216 XFree( buffer );
217 }
218
219 Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
220 Atom typeAtom = XInternAtom( XDISPLAY, "XdndFinished", 0 );
221
222 // Tell the source we accepted the drop
223 XEvent event;
224 event.type = ClientMessage;
225 event.xclient.window = src;
226 event.xclient.display = XDISPLAY;
227 event.xclient.message_type = typeAtom;
228 event.xclient.format = 32;
229 event.xclient.data.l[0] = m_wnd;
230 event.xclient.data.l[1] = 1; // drop accepted
231 event.xclient.data.l[2] = actionAtom;
232 XSendEvent( XDISPLAY, src, False, 0, &event );
233
234 // transmit DragDrop event
235 EvtDragDrop evt( getIntf(), m_xPos, m_yPos, files );
236 m_pWin->processEvent( evt );
237 }
238
239 #endif
240