2 // "$Id: fl_dnd_x.cxx 7992 2010-12-09 21:52:07Z manolo $"
4 // Drag & Drop code for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
29 #include <FL/Fl_Window.H>
34 extern Atom fl_XdndAware
;
35 extern Atom fl_XdndSelection
;
36 extern Atom fl_XdndEnter
;
37 extern Atom fl_XdndTypeList
;
38 extern Atom fl_XdndPosition
;
39 extern Atom fl_XdndLeave
;
40 extern Atom fl_XdndDrop
;
41 extern Atom fl_XdndStatus
;
42 extern Atom fl_XdndActionCopy
;
43 extern Atom fl_XdndFinished
;
44 //extern Atom fl_XdndProxy;
45 extern Atom fl_XdndURIList
;
46 extern Atom fl_XaUtf8String
;
48 extern char fl_i_own_selection
[2];
49 extern char *fl_selection_buffer
[2];
51 extern void fl_sendClientMessage(Window window
, Atom message
,
58 // return version # of Xdnd this window supports. Also change the
59 // window to the proxy if it uses a proxy:
60 static int dnd_aware(Window
& window
) {
61 Atom actual
; int format
; unsigned long count
, remaining
;
62 unsigned char *data
= 0;
63 XGetWindowProperty(fl_display
, window
, fl_XdndAware
,
66 &count
, &remaining
, &data
);
67 if (actual
== XA_ATOM
&& format
==32 && count
&& data
)
68 return int(*(Atom
*)data
);
72 static int grabfunc(int event
) {
73 if (event
== FL_RELEASE
) Fl::pushed(0);
77 extern int (*fl_local_grab
)(int); // in Fl.cxx
79 // send an event to an fltk window belonging to this program:
80 static int local_handle(int event
, Fl_Window
* window
) {
82 Fl::e_x
= Fl::e_x_root
-window
->x();
83 Fl::e_y
= Fl::e_y_root
-window
->y();
84 int ret
= Fl::handle(event
,window
);
85 fl_local_grab
= grabfunc
;
90 Fl_Window
*source_fl_win
= Fl::first_window();
91 Fl::first_window()->cursor(FL_CURSOR_MOVE
);
92 Window source_window
= fl_xid(Fl::first_window());
93 fl_local_grab
= grabfunc
;
94 Window target_window
= 0;
95 Fl_Window
* local_window
= 0;
96 int dndversion
= 4; int dest_x
, dest_y
, old_dest_x
, old_dest_y
;
98 old_dest_y
= old_dest_x
= -1;
100 XSetSelectionOwner(fl_display
, fl_XdndSelection
, fl_message_window
, fl_event_time
);
102 Fl_Widget
*pushed
= Fl::pushed();
104 while (Fl::pushed()) {
106 // figure out what window we are pointing at:
107 Window new_window
= 0; int new_version
= 0;
108 Fl_Window
* new_local_window
= 0;
109 for (Window child
= RootWindow(fl_display
, fl_screen
);;) {
110 Window root
; unsigned int junk3
;
111 XQueryPointer(fl_display
, child
, &root
, &child
,
112 &e_x_root
, &e_y_root
, &dest_x
, &dest_y
, &junk3
);
114 if (!new_window
&& (new_version
= dnd_aware(root
))) new_window
= root
;
118 if ((new_local_window
= fl_find(child
))) break;
119 if ((new_version
= dnd_aware(new_window
))) break;
122 if (new_window
!= target_window
) {
124 local_handle(FL_DND_LEAVE
, local_window
);
125 } else if (dndversion
) {
126 fl_sendClientMessage(target_window
, fl_XdndLeave
, source_window
);
128 dndversion
= new_version
;
129 target_window
= new_window
;
130 local_window
= new_local_window
;
132 local_handle(FL_DND_ENTER
, local_window
);
133 } else if (dndversion
) {
134 // Send an X-DND message to the target window. In order to
135 // support dragging of files/URLs as well as arbitrary text,
136 // we look at the selection buffer - if the buffer starts
137 // with a common URI scheme, does not contain spaces, and
138 // contains at least one CR LF, then we flag the data as
139 // both a URI list (MIME media type "text/uri-list") and
140 // plain text. Otherwise, we just say it is plain text.
141 if ((!strncmp(fl_selection_buffer
[0], "file:///", 8) ||
142 !strncmp(fl_selection_buffer
[0], "ftp://", 6) ||
143 !strncmp(fl_selection_buffer
[0], "http://", 7) ||
144 !strncmp(fl_selection_buffer
[0], "https://", 8) ||
145 !strncmp(fl_selection_buffer
[0], "ipp://", 6) ||
146 !strncmp(fl_selection_buffer
[0], "ldap:", 5) ||
147 !strncmp(fl_selection_buffer
[0], "mailto:", 7) ||
148 !strncmp(fl_selection_buffer
[0], "news:", 5) ||
149 !strncmp(fl_selection_buffer
[0], "smb://", 6)) &&
150 !strchr(fl_selection_buffer
[0], ' ') &&
151 strstr(fl_selection_buffer
[0], "\r\n")) {
152 // Send file/URI list...
153 fl_sendClientMessage(target_window
, fl_XdndEnter
, source_window
,
154 dndversion
<<24, fl_XdndURIList
, XA_STRING
, 0);
156 // Send plain text...
157 fl_sendClientMessage(target_window
, fl_XdndEnter
, source_window
,
158 dndversion
<<24, fl_XaUtf8String
, 0, 0);
163 if ( old_dest_x
!= dest_x
|| old_dest_y
!= dest_y
)
166 local_handle(FL_DND_DRAG
, local_window
);
167 } else if (dndversion
) {
168 fl_sendClientMessage(target_window
, fl_XdndPosition
, source_window
,
169 0, (e_x_root
<<16)|e_y_root
, fl_event_time
,
180 fl_i_own_selection
[0] = 1;
181 if (local_handle(FL_DND_RELEASE
, local_window
)) paste(*belowmouse(), 0);
182 } else if (dndversion
) {
184 fl_sendClientMessage(target_window
, fl_XdndDrop
, source_window
,
187 } else if (target_window
) {
188 // fake a drop by clicking the middle mouse button:
190 msg
.type
= ButtonPress
;
191 msg
.window
= target_window
;
192 msg
.root
= RootWindow(fl_display
, fl_screen
);
194 msg
.time
= fl_event_time
+1;
197 msg
.x_root
= Fl::e_x_root
;
198 msg
.y_root
= Fl::e_y_root
;
200 msg
.button
= Button2
;
201 XSendEvent(fl_display
, target_window
, False
, 0L, (XEvent
*)&msg
);
204 msg
.type
= ButtonRelease
;
205 XSendEvent(fl_display
, target_window
, False
, 0L, (XEvent
*)&msg
);
210 /* let the source widget know that DND is over */
211 pushed
->handle( FL_DND_RELEASE
);
212 pushed
->handle( FL_RELEASE
);
216 source_fl_win
->cursor(FL_CURSOR_DEFAULT
);
222 // End of "$Id: fl_dnd_x.cxx 7992 2010-12-09 21:52:07Z manolo $".