blob: 4062875243e15960644dfdfaaa326e61943dd2b5 [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: fl_dnd_x.cxx 7992 2010-12-09 21:52:07Z manolo $"
3//
4// Drag & Drop code for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2010 by Bill Spitzak and others.
7//
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.
12//
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.
17//
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
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25// http://www.fltk.org/str.php
26//
27
28#include <FL/Fl.H>
29#include <FL/Fl_Window.H>
30#include <FL/x.H>
31#include "flstring.h"
32
33
34extern Atom fl_XdndAware;
35extern Atom fl_XdndSelection;
36extern Atom fl_XdndEnter;
37extern Atom fl_XdndTypeList;
38extern Atom fl_XdndPosition;
39extern Atom fl_XdndLeave;
40extern Atom fl_XdndDrop;
41extern Atom fl_XdndStatus;
42extern Atom fl_XdndActionCopy;
43extern Atom fl_XdndFinished;
44//extern Atom fl_XdndProxy;
45extern Atom fl_XdndURIList;
46extern Atom fl_XaUtf8String;
47
48extern char fl_i_own_selection[2];
49extern char *fl_selection_buffer[2];
50
51extern void fl_sendClientMessage(Window window, Atom message,
52 unsigned long d0,
53 unsigned long d1=0,
54 unsigned long d2=0,
55 unsigned long d3=0,
56 unsigned long d4=0);
57
58// return version # of Xdnd this window supports. Also change the
59// window to the proxy if it uses a proxy:
60static 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,
64 0, 4, False, XA_ATOM,
65 &actual, &format,
66 &count, &remaining, &data);
67 if (actual == XA_ATOM && format==32 && count && data)
68 return int(*(Atom*)data);
69 return 0;
70}
71
72static int grabfunc(int event) {
73 if (event == FL_RELEASE) Fl::pushed(0);
74 return 0;
75}
76
77extern int (*fl_local_grab)(int); // in Fl.cxx
78
79// send an event to an fltk window belonging to this program:
80static int local_handle(int event, Fl_Window* window) {
81 fl_local_grab = 0;
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;
86 return ret;
87}
88
89int Fl::dnd() {
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;
97 XSetSelectionOwner(fl_display, fl_XdndSelection, fl_message_window, fl_event_time);
98
99 while (Fl::pushed()) {
100
101 // figure out what window we are pointing at:
102 Window new_window = 0; int new_version = 0;
103 Fl_Window* new_local_window = 0;
104 for (Window child = RootWindow(fl_display, fl_screen);;) {
105 Window root; unsigned int junk3;
106 XQueryPointer(fl_display, child, &root, &child,
107 &e_x_root, &e_y_root, &dest_x, &dest_y, &junk3);
108 if (!child) {
109 if (!new_window && (new_version = dnd_aware(root))) new_window = root;
110 break;
111 }
112 new_window = child;
113 if ((new_local_window = fl_find(child))) break;
114 if ((new_version = dnd_aware(new_window))) break;
115 }
116
117 if (new_window != target_window) {
118 if (local_window) {
119 local_handle(FL_DND_LEAVE, local_window);
120 } else if (dndversion) {
121 fl_sendClientMessage(target_window, fl_XdndLeave, source_window);
122 }
123 dndversion = new_version;
124 target_window = new_window;
125 local_window = new_local_window;
126 if (local_window) {
127 local_handle(FL_DND_ENTER, local_window);
128 } else if (dndversion) {
129 // Send an X-DND message to the target window. In order to
130 // support dragging of files/URLs as well as arbitrary text,
131 // we look at the selection buffer - if the buffer starts
132 // with a common URI scheme, does not contain spaces, and
133 // contains at least one CR LF, then we flag the data as
134 // both a URI list (MIME media type "text/uri-list") and
135 // plain text. Otherwise, we just say it is plain text.
136 if ((!strncmp(fl_selection_buffer[0], "file:///", 8) ||
137 !strncmp(fl_selection_buffer[0], "ftp://", 6) ||
138 !strncmp(fl_selection_buffer[0], "http://", 7) ||
139 !strncmp(fl_selection_buffer[0], "https://", 8) ||
140 !strncmp(fl_selection_buffer[0], "ipp://", 6) ||
141 !strncmp(fl_selection_buffer[0], "ldap:", 5) ||
142 !strncmp(fl_selection_buffer[0], "mailto:", 7) ||
143 !strncmp(fl_selection_buffer[0], "news:", 5) ||
144 !strncmp(fl_selection_buffer[0], "smb://", 6)) &&
145 !strchr(fl_selection_buffer[0], ' ') &&
146 strstr(fl_selection_buffer[0], "\r\n")) {
147 // Send file/URI list...
148 fl_sendClientMessage(target_window, fl_XdndEnter, source_window,
149 dndversion<<24, fl_XdndURIList, XA_STRING, 0);
150 } else {
151 // Send plain text...
152 fl_sendClientMessage(target_window, fl_XdndEnter, source_window,
153 dndversion<<24, fl_XaUtf8String, 0, 0);
154 }
155 }
156 }
157 if (local_window) {
158 local_handle(FL_DND_DRAG, local_window);
159 } else if (dndversion) {
160 fl_sendClientMessage(target_window, fl_XdndPosition, source_window,
161 0, (e_x_root<<16)|e_y_root, fl_event_time,
162 fl_XdndActionCopy);
163 }
164 Fl::wait();
165 }
166
167 if (local_window) {
168 fl_i_own_selection[0] = 1;
169 if (local_handle(FL_DND_RELEASE, local_window)) paste(*belowmouse(), 0);
170 } else if (dndversion) {
171 fl_sendClientMessage(target_window, fl_XdndDrop, source_window,
172 0, fl_event_time);
173 } else if (target_window) {
174 // fake a drop by clicking the middle mouse button:
175 XButtonEvent msg;
176 msg.type = ButtonPress;
177 msg.window = target_window;
178 msg.root = RootWindow(fl_display, fl_screen);
179 msg.subwindow = 0;
180 msg.time = fl_event_time+1;
181 msg.x = dest_x;
182 msg.y = dest_y;
183 msg.x_root = Fl::e_x_root;
184 msg.y_root = Fl::e_y_root;
185 msg.state = 0x0;
186 msg.button = Button2;
187 XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg);
188 msg.time++;
189 msg.state = 0x200;
190 msg.type = ButtonRelease;
191 XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg);
192 }
193
194 fl_local_grab = 0;
195 source_fl_win->cursor(FL_CURSOR_DEFAULT);
196 return 1;
197}
198
199
200//
201// End of "$Id: fl_dnd_x.cxx 7992 2010-12-09 21:52:07Z manolo $".
202//