]> git.sesse.net Git - vlc/blob - modules/gui/skins2/x11/x11_dragdrop.cpp
e060cfff2bb373ab9b75759ff390f1b271bcf5bf
[vlc] / modules / gui / skins2 / x11 / x11_dragdrop.cpp
1 /*****************************************************************************
2  * x11_dragdrop.cpp
3  *****************************************************************************
4  * Copyright (C) 2003 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, 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
35 #include <string>
36 #include <list>
37
38
39 X11DragDrop::X11DragDrop( intf_thread_t *pIntf, X11Display &rDisplay,
40                           Window win, bool playOnDrop ):
41     SkinObject( pIntf ), m_rDisplay( rDisplay ), m_wnd( win ),
42     m_playOnDrop( playOnDrop )
43 {
44 }
45
46
47 void X11DragDrop::dndEnter( ldata_t data )
48 {
49     Window src = data[0];
50
51     // Retrieve available data types
52     list<string> dataTypes;
53     if( data[1] & 1 )   // More than 3 data types ?
54     {
55         Atom type;
56         int format;
57         unsigned long nitems, nbytes;
58         Atom *dataList;
59         Atom typeListAtom = XInternAtom( XDISPLAY, "XdndTypeList", 0 );
60         XGetWindowProperty( XDISPLAY, src, typeListAtom, 0, 65536, False,
61                             XA_ATOM, &type, &format, &nitems, &nbytes,
62                             (unsigned char**)&dataList );
63         for( unsigned long i=0; i<nitems; i++ )
64         {
65             string dataType = XGetAtomName( XDISPLAY, dataList[i] );
66             dataTypes.push_back( dataType );
67         }
68         XFree( (void*)dataList );
69     }
70     else
71     {
72         for( int i = 2; i < 5; i++ )
73         {
74             if( data[i] != None )
75             {
76                 string dataType = XGetAtomName( XDISPLAY, data[i] );
77                 dataTypes.push_back( dataType );
78             }
79         }
80     }
81
82     // Find the right target
83     m_target = None;
84     list<string>::iterator it;
85     for( it = dataTypes.begin(); it != dataTypes.end(); it++ )
86     {
87         if( *it == "text/plain" || *it == "STRING" )
88         {
89             m_target = XInternAtom( XDISPLAY, (*it).c_str(), 0 );
90             break;
91         }
92     }
93 }
94
95
96 void X11DragDrop::dndPosition( ldata_t data )
97 {
98     Window src = data[0];
99     Time time = data[2];
100
101     Atom selectionAtom = XInternAtom( XDISPLAY, "XdndSelection", 0 );
102     Atom targetAtom = XInternAtom( XDISPLAY, "text/plain", 0 );
103     Atom propAtom = XInternAtom( XDISPLAY, "VLC_SELECTION", 0 );
104
105     Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
106     Atom typeAtom = XInternAtom( XDISPLAY, "XdndFinished", 0 );
107
108     // Convert the selection into the given target
109     // NEEDED or it doesn't work!
110     XConvertSelection( XDISPLAY, selectionAtom, targetAtom, propAtom, src,
111                        time );
112
113     actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
114     typeAtom = XInternAtom( XDISPLAY, "XdndStatus", 0 );
115
116     XEvent event;
117     event.type = ClientMessage;
118     event.xclient.window = src;
119     event.xclient.display = XDISPLAY;
120     event.xclient.message_type = typeAtom;
121     event.xclient.format = 32;
122     event.xclient.data.l[0] = m_wnd;
123     if( m_target != None )
124     {
125         // Accept the drop
126         event.xclient.data.l[1] = 1;
127     }
128     else
129     {
130         // Do not accept the drop
131         event.xclient.data.l[1] = 0;
132     }
133     int w = X11Factory::instance( getIntf() )->getScreenWidth();
134     int h = X11Factory::instance( getIntf() )->getScreenHeight();
135     event.xclient.data.l[2] = 0;
136     event.xclient.data.l[3] = (w << 16) | h;
137     event.xclient.data.l[4] = actionAtom;
138
139     // Tell the source whether we accept the drop
140     XSendEvent( XDISPLAY, src, False, 0, &event );
141 }
142
143
144 void X11DragDrop::dndLeave( ldata_t data )
145 {
146 }
147
148
149 void X11DragDrop::dndDrop( ldata_t data )
150 {
151     Window src = data[0];
152     Time time = data[2];
153
154     Atom selectionAtom = XInternAtom( XDISPLAY, "XdndSelection", 0 );
155     Atom targetAtom = XInternAtom( XDISPLAY, "text/plain", 0 );
156     Atom propAtom = XInternAtom( XDISPLAY, "VLC_SELECTION", 0 );
157
158     Atom actionAtom = XInternAtom( XDISPLAY, "XdndActionCopy", 0 );
159     Atom typeAtom = XInternAtom( XDISPLAY, "XdndFinished", 0 );
160
161     // Convert the selection into the given target
162     XConvertSelection( XDISPLAY, selectionAtom, targetAtom, propAtom, src,
163                        time );
164
165     // Read the selection
166     Atom type;
167     int format;
168     unsigned long nitems, nbytes;
169     char *buffer;
170     XGetWindowProperty( XDISPLAY, src, propAtom, 0, 1024, False,
171                         AnyPropertyType, &type, &format, &nitems, &nbytes,
172                         (unsigned char**)&buffer );
173     string selection = "";
174     if( buffer != NULL )
175     {
176         selection = buffer;
177     }
178     XFree( buffer );
179
180     if( selection != "" )
181     {
182         // TODO: multiple files handling
183         string::size_type end = selection.find( "\n", 0 );
184         selection = selection.substr( 0, end - 1 );
185         end = selection.find( "\r", 0 );
186         selection = selection.substr( 0, end - 1 );
187
188         // Find the protocol, if any
189         string::size_type pos = selection.find( ":", 0 );
190         if( selection.find( "///", pos + 1 ) == pos + 1 )
191         {
192             selection.erase( pos + 1, 2 );
193         }
194
195         char *psz_fileName = new char[selection.size() + 1];
196         strncpy( psz_fileName, selection.c_str(), selection.size() + 1 );
197
198         // Add the file
199         CmdAddItem cmd( getIntf(), psz_fileName, m_playOnDrop );
200         cmd.execute();
201
202         delete[] psz_fileName;
203     }
204
205     // Tell the source we accepted the drop
206     XEvent event;
207     event.type = ClientMessage;
208     event.xclient.window = src;
209     event.xclient.display = XDISPLAY;
210     event.xclient.message_type = typeAtom;
211     event.xclient.format = 32;
212     event.xclient.data.l[0] = m_wnd;
213     event.xclient.data.l[1] = 1;            // drop accepted
214     event.xclient.data.l[2] = actionAtom;
215     XSendEvent( XDISPLAY, src, False, 0, &event );
216 }
217
218 #endif