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)  

fl_dnd_x.cxx

Go to the documentation of this file.
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 //