themes: Workaround for bug where a background color of RGB 0,0,0 in Black color schem...
[ntk.git] / src / fl_dnd_x.cxx
blob12aacf961aa325e96774772ab616ade7bd9951db
1 //
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.
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
21 // USA.
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
28 #include <FL/Fl.H>
29 #include <FL/Fl_Window.H>
30 #include <FL/x.H>
31 #include "flstring.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,
52 unsigned long d0,
53 unsigned long d1=0,
54 unsigned long d2=0,
55 unsigned long d3=0,
56 unsigned long d4=0);
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,
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;
72 static int grabfunc(int event) {
73 if (event == FL_RELEASE) Fl::pushed(0);
74 return 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) {
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;
89 int 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, 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);
113 if (!child) {
114 if (!new_window && (new_version = dnd_aware(root))) new_window = root;
115 break;
117 new_window = child;
118 if ((new_local_window = fl_find(child))) break;
119 if ((new_version = dnd_aware(new_window))) break;
122 if (new_window != target_window) {
123 if (local_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;
131 if (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);
155 } else {
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 )
165 if (local_window) {
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,
170 fl_XdndActionCopy);
173 old_dest_x = dest_x;
174 old_dest_y = dest_y;
176 Fl::wait();
179 if (local_window) {
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,
185 0, fl_event_time);
187 } else if (target_window) {
188 // fake a drop by clicking the middle mouse button:
189 XButtonEvent msg;
190 msg.type = ButtonPress;
191 msg.window = target_window;
192 msg.root = RootWindow(fl_display, fl_screen);
193 msg.subwindow = 0;
194 msg.time = fl_event_time+1;
195 msg.x = dest_x;
196 msg.y = dest_y;
197 msg.x_root = Fl::e_x_root;
198 msg.y_root = Fl::e_y_root;
199 msg.state = 0x0;
200 msg.button = Button2;
201 XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg);
202 msg.time++;
203 msg.state = 0x200;
204 msg.type = ButtonRelease;
205 XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg);
208 if ( !local_window )
210 /* let the source widget know that DND is over */
211 pushed->handle( FL_DND_RELEASE );
212 pushed->handle( FL_RELEASE );
215 fl_local_grab = 0;
216 source_fl_win->cursor(FL_CURSOR_DEFAULT);
217 return 1;
222 // End of "$Id: fl_dnd_x.cxx 7992 2010-12-09 21:52:07Z manolo $".