|
fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation) ![]() |
00001 // 00002 // "$Id: fl_dnd_x.cxx 7992 2010-12-09 21:52:07Z manolo $" 00003 // 00004 // Drag & Drop code for the Fast Light Tool Kit (FLTK). 00005 // 00006 // Copyright 1998-2010 by Bill Spitzak and others. 00007 // 00008 // This library is free software; you can redistribute it and/or 00009 // modify it under the terms of the GNU Library General Public 00010 // License as published by the Free Software Foundation; either 00011 // version 2 of the License, or (at your option) any later version. 00012 // 00013 // This library is distributed in the hope that it will be useful, 00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 // Library General Public License for more details. 00017 // 00018 // You should have received a copy of the GNU Library General Public 00019 // License along with this library; if not, write to the Free Software 00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 00021 // USA. 00022 // 00023 // Please report all bugs and problems on the following page: 00024 // 00025 // http://www.fltk.org/str.php 00026 // 00027 00028 #include <FL/Fl.H> 00029 #include <FL/Fl_Window.H> 00030 #include <FL/x.H> 00031 #include "flstring.h" 00032 00033 00034 extern Atom fl_XdndAware; 00035 extern Atom fl_XdndSelection; 00036 extern Atom fl_XdndEnter; 00037 extern Atom fl_XdndTypeList; 00038 extern Atom fl_XdndPosition; 00039 extern Atom fl_XdndLeave; 00040 extern Atom fl_XdndDrop; 00041 extern Atom fl_XdndStatus; 00042 extern Atom fl_XdndActionCopy; 00043 extern Atom fl_XdndFinished; 00044 //extern Atom fl_XdndProxy; 00045 extern Atom fl_XdndURIList; 00046 extern Atom fl_XaUtf8String; 00047 00048 extern char fl_i_own_selection[2]; 00049 extern char *fl_selection_buffer[2]; 00050 00051 extern void fl_sendClientMessage(Window window, Atom message, 00052 unsigned long d0, 00053 unsigned long d1=0, 00054 unsigned long d2=0, 00055 unsigned long d3=0, 00056 unsigned long d4=0); 00057 00058 // return version # of Xdnd this window supports. Also change the 00059 // window to the proxy if it uses a proxy: 00060 static int dnd_aware(Window& window) { 00061 Atom actual; int format; unsigned long count, remaining; 00062 unsigned char *data = 0; 00063 XGetWindowProperty(fl_display, window, fl_XdndAware, 00064 0, 4, False, XA_ATOM, 00065 &actual, &format, 00066 &count, &remaining, &data); 00067 if (actual == XA_ATOM && format==32 && count && data) 00068 return int(*(Atom*)data); 00069 return 0; 00070 } 00071 00072 static int grabfunc(int event) { 00073 if (event == FL_RELEASE) Fl::pushed(0); 00074 return 0; 00075 } 00076 00077 extern int (*fl_local_grab)(int); // in Fl.cxx 00078 00079 // send an event to an fltk window belonging to this program: 00080 static int local_handle(int event, Fl_Window* window) { 00081 fl_local_grab = 0; 00082 Fl::e_x = Fl::e_x_root-window->x(); 00083 Fl::e_y = Fl::e_y_root-window->y(); 00084 int ret = Fl::handle(event,window); 00085 fl_local_grab = grabfunc; 00086 return ret; 00087 } 00088 00089 int Fl::dnd() { 00090 Fl_Window *source_fl_win = Fl::first_window(); 00091 Fl::first_window()->cursor(FL_CURSOR_MOVE); 00092 Window source_window = fl_xid(Fl::first_window()); 00093 fl_local_grab = grabfunc; 00094 Window target_window = 0; 00095 Fl_Window* local_window = 0; 00096 int dndversion = 4; int dest_x, dest_y; 00097 XSetSelectionOwner(fl_display, fl_XdndSelection, fl_message_window, fl_event_time); 00098 00099 while (Fl::pushed()) { 00100 00101 // figure out what window we are pointing at: 00102 Window new_window = 0; int new_version = 0; 00103 Fl_Window* new_local_window = 0; 00104 for (Window child = RootWindow(fl_display, fl_screen);;) { 00105 Window root; unsigned int junk3; 00106 XQueryPointer(fl_display, child, &root, &child, 00107 &e_x_root, &e_y_root, &dest_x, &dest_y, &junk3); 00108 if (!child) { 00109 if (!new_window && (new_version = dnd_aware(root))) new_window = root; 00110 break; 00111 } 00112 new_window = child; 00113 if ((new_local_window = fl_find(child))) break; 00114 if ((new_version = dnd_aware(new_window))) break; 00115 } 00116 00117 if (new_window != target_window) { 00118 if (local_window) { 00119 local_handle(FL_DND_LEAVE, local_window); 00120 } else if (dndversion) { 00121 fl_sendClientMessage(target_window, fl_XdndLeave, source_window); 00122 } 00123 dndversion = new_version; 00124 target_window = new_window; 00125 local_window = new_local_window; 00126 if (local_window) { 00127 local_handle(FL_DND_ENTER, local_window); 00128 } else if (dndversion) { 00129 // Send an X-DND message to the target window. In order to 00130 // support dragging of files/URLs as well as arbitrary text, 00131 // we look at the selection buffer - if the buffer starts 00132 // with a common URI scheme, does not contain spaces, and 00133 // contains at least one CR LF, then we flag the data as 00134 // both a URI list (MIME media type "text/uri-list") and 00135 // plain text. Otherwise, we just say it is plain text. 00136 if ((!strncmp(fl_selection_buffer[0], "file:///", 8) || 00137 !strncmp(fl_selection_buffer[0], "ftp://", 6) || 00138 !strncmp(fl_selection_buffer[0], "http://", 7) || 00139 !strncmp(fl_selection_buffer[0], "https://", 8) || 00140 !strncmp(fl_selection_buffer[0], "ipp://", 6) || 00141 !strncmp(fl_selection_buffer[0], "ldap:", 5) || 00142 !strncmp(fl_selection_buffer[0], "mailto:", 7) || 00143 !strncmp(fl_selection_buffer[0], "news:", 5) || 00144 !strncmp(fl_selection_buffer[0], "smb://", 6)) && 00145 !strchr(fl_selection_buffer[0], ' ') && 00146 strstr(fl_selection_buffer[0], "\r\n")) { 00147 // Send file/URI list... 00148 fl_sendClientMessage(target_window, fl_XdndEnter, source_window, 00149 dndversion<<24, fl_XdndURIList, XA_STRING, 0); 00150 } else { 00151 // Send plain text... 00152 fl_sendClientMessage(target_window, fl_XdndEnter, source_window, 00153 dndversion<<24, fl_XaUtf8String, 0, 0); 00154 } 00155 } 00156 } 00157 if (local_window) { 00158 local_handle(FL_DND_DRAG, local_window); 00159 } else if (dndversion) { 00160 fl_sendClientMessage(target_window, fl_XdndPosition, source_window, 00161 0, (e_x_root<<16)|e_y_root, fl_event_time, 00162 fl_XdndActionCopy); 00163 } 00164 Fl::wait(); 00165 } 00166 00167 if (local_window) { 00168 fl_i_own_selection[0] = 1; 00169 if (local_handle(FL_DND_RELEASE, local_window)) paste(*belowmouse(), 0); 00170 } else if (dndversion) { 00171 fl_sendClientMessage(target_window, fl_XdndDrop, source_window, 00172 0, fl_event_time); 00173 } else if (target_window) { 00174 // fake a drop by clicking the middle mouse button: 00175 XButtonEvent msg; 00176 msg.type = ButtonPress; 00177 msg.window = target_window; 00178 msg.root = RootWindow(fl_display, fl_screen); 00179 msg.subwindow = 0; 00180 msg.time = fl_event_time+1; 00181 msg.x = dest_x; 00182 msg.y = dest_y; 00183 msg.x_root = Fl::e_x_root; 00184 msg.y_root = Fl::e_y_root; 00185 msg.state = 0x0; 00186 msg.button = Button2; 00187 XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg); 00188 msg.time++; 00189 msg.state = 0x200; 00190 msg.type = ButtonRelease; 00191 XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg); 00192 } 00193 00194 fl_local_grab = 0; 00195 source_fl_win->cursor(FL_CURSOR_DEFAULT); 00196 return 1; 00197 } 00198 00199 00200 // 00201 // End of "$Id: fl_dnd_x.cxx 7992 2010-12-09 21:52:07Z manolo $". 00202 //