From 6eff9b3b146ec35f7bf0eaf89924d9f052ba4bb9 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Wed, 9 Jan 2002 21:50:02 +0000 Subject: First round of DND additions to 1.1 - just X11 code, and I haven't added the support in widgets yet. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1925 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- CHANGES | 5 ++ FL/Enumerations.H | 10 ++-- FL/Fl.H | 5 +- src/Fl.cxx | 6 ++- src/Fl_cutpaste.cxx | 81 ++++++++++++++++++++++------ src/Fl_x.cxx | 146 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/fl_dnd.cxx | 16 +++--- src/fl_dnd_win32.cxx | 15 +++--- src/fl_dnd_x.cxx | 27 +++++----- 9 files changed, 252 insertions(+), 59 deletions(-) diff --git a/CHANGES b/CHANGES index e44450152..3cc2e9104 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +CHANGES IN FLTK 1.1.0b11 + + - Initial port of FLTK 2.0 drag-and-drop support. + + CHANGES IN FLTK 1.1.0b10 - Fixed the new WIN32 TrackMouseEvent code. diff --git a/FL/Enumerations.H b/FL/Enumerations.H index f71c7050e..16d527695 100644 --- a/FL/Enumerations.H +++ b/FL/Enumerations.H @@ -1,5 +1,5 @@ // -// "$Id: Enumerations.H,v 1.18.2.14.2.18 2002/01/01 15:11:27 easysw Exp $" +// "$Id: Enumerations.H,v 1.18.2.14.2.19 2002/01/09 21:50:02 easysw Exp $" // // Enumerations for the Fast Light Tool Kit (FLTK). // @@ -73,7 +73,11 @@ enum Fl_Event { // events FL_SHOW = 16, FL_PASTE = 17, FL_SELECTIONCLEAR = 18, - FL_MOUSEWHEEL = 19 + FL_MOUSEWHEEL = 19, + FL_DND_ENTER = 20, + FL_DND_DRAG = 21, + FL_DND_LEAVE = 22, + FL_DND_RELEASE = 23 }; #define FL_KEYBOARD FL_KEYDOWN @@ -373,5 +377,5 @@ enum Fl_Damage { #endif // -// End of "$Id: Enumerations.H,v 1.18.2.14.2.18 2002/01/01 15:11:27 easysw Exp $". +// End of "$Id: Enumerations.H,v 1.18.2.14.2.19 2002/01/09 21:50:02 easysw Exp $". // diff --git a/FL/Fl.H b/FL/Fl.H index 2011ab677..e387af6ed 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -1,5 +1,5 @@ // -// "$Id: Fl.H,v 1.8.2.11.2.12 2002/01/01 15:11:27 easysw Exp $" +// "$Id: Fl.H,v 1.8.2.11.2.13 2002/01/09 21:50:02 easysw Exp $" // // Main header file for the Fast Light Tool Kit (FLTK). // @@ -173,6 +173,7 @@ public: static FL_EXPORT void selection_owner(Fl_Widget*); static FL_EXPORT void selection(Fl_Widget &owner, const char* stuff, int len); static FL_EXPORT void paste(Fl_Widget &receiver); + static FL_EXPORT int dnd(); // screen size: #if defined(WIN32) || defined(__APPLE__) @@ -243,5 +244,5 @@ public: #endif // !Fl_H // -// End of "$Id: Fl.H,v 1.8.2.11.2.12 2002/01/01 15:11:27 easysw Exp $". +// End of "$Id: Fl.H,v 1.8.2.11.2.13 2002/01/09 21:50:02 easysw Exp $". // diff --git a/src/Fl.cxx b/src/Fl.cxx index 6278ec4c5..c4915666d 100644 --- a/src/Fl.cxx +++ b/src/Fl.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl.cxx,v 1.24.2.41.2.17 2002/01/07 18:47:27 easysw Exp $" +// "$Id: Fl.cxx,v 1.24.2.41.2.18 2002/01/09 21:50:02 easysw Exp $" // // Main event handling code for the Fast Light Tool Kit (FLTK). // @@ -390,6 +390,8 @@ void Fl::add_handler(int (*h)(int)) { handlers = l; } +int (*fl_local_grab)(int); // used by fl_dnd.cxx + static int send_handlers(int event) { for (const handler_link *h = handlers; h; h = h->next) if (h->handle(event)) return 1; @@ -853,5 +855,5 @@ void Fl_Window::flush() { } // -// End of "$Id: Fl.cxx,v 1.24.2.41.2.17 2002/01/07 18:47:27 easysw Exp $". +// End of "$Id: Fl.cxx,v 1.24.2.41.2.18 2002/01/09 21:50:02 easysw Exp $". // diff --git a/src/Fl_cutpaste.cxx b/src/Fl_cutpaste.cxx index 303370c67..80ca75b7f 100644 --- a/src/Fl_cutpaste.cxx +++ b/src/Fl_cutpaste.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_cutpaste.cxx,v 1.6.2.4.2.3 2002/01/01 15:11:31 easysw Exp $" +// "$Id: Fl_cutpaste.cxx,v 1.6.2.4.2.4 2002/01/09 21:50:02 easysw Exp $" // // Cut/paste code for the Fast Light Tool Kit (FLTK). // @@ -39,6 +39,7 @@ # include # include # include +# include static char *selection_buffer; static int selection_length; @@ -47,6 +48,30 @@ static char beenhere; static Atom TARGETS; extern Fl_Widget *fl_selection_requestor; // widget doing request_paste() +extern Atom fl_XdndAware; +extern Atom fl_XdndSelection; +extern Atom fl_XdndEnter; +extern Atom fl_XdndTypeList; +extern Atom fl_XdndPosition; +extern Atom fl_XdndLeave; +extern Atom fl_XdndDrop; +extern Atom fl_XdndStatus; +extern Atom fl_XdndActionCopy; +extern Atom fl_XdndFinished; +//extern Atom fl_XdndProxy; + +extern Window fl_dnd_source_window; +extern Atom *fl_dnd_source_types; // null-terminated list of data types being supplied +extern Atom fl_dnd_type; +extern Atom fl_dnd_source_action; +extern Atom fl_dnd_action; + +extern void fl_sendClientMessage(Window window, Atom message, + unsigned long d0, + unsigned long d1=0, + unsigned long d2=0, + unsigned long d3=0, + unsigned long d4=0); static int selection_xevent_handler(int) { @@ -54,21 +79,45 @@ static int selection_xevent_handler(int) { case SelectionNotify: { if (!fl_selection_requestor) return 0; - static char *pastebuffer; - if (pastebuffer) {XFree(pastebuffer); pastebuffer = 0;} - if (fl_xevent->xselection.property != 0) { - Atom a; int f; unsigned long n,b; - if (!XGetWindowProperty(fl_display, - fl_xevent->xselection.requestor, - fl_xevent->xselection.property, - 0,100000,1,0,&a,&f,&n,&b, - (unsigned char**)&pastebuffer)) { - Fl::e_text = pastebuffer; - Fl::e_length = int(n); - fl_selection_requestor->handle(FL_PASTE); + static unsigned char* buffer; + if (buffer) {XFree(buffer); buffer = 0;} + long read = 0; + if (fl_xevent->xselection.property) for (;;) { + // The Xdnd code pastes 64K chunks together, possibly to avoid + // bugs in X servers, or maybe to avoid an extra round-trip to + // get the property length. I copy this here: + Atom actual; int format; unsigned long count, remaining; + unsigned char* portion; + if (XGetWindowProperty(fl_display, + fl_xevent->xselection.requestor, + fl_xevent->xselection.property, + read/4, 65536, 1, 0, + &actual, &format, &count, &remaining, + &portion)) break; // quit on error + if (read) { // append to the accumulated buffer + buffer = (unsigned char*)realloc(buffer, read+count*format/8+remaining); + memcpy(buffer+read, portion, count*format/8); + XFree(portion); + } else { // Use the first section without moving the memory: + buffer = portion; } - }} - return 1; + read += count*format/8; + if (!remaining) break; + } + Fl::e_text = (char*)buffer; + Fl::e_length = read; + fl_selection_requestor->handle(FL_PASTE); + // Detect if this paste is due to Xdnd by the property name (I use + // XA_SECONDARY for that) and send an XdndFinished message. It is not + // clear if this has to be delayed until now or if it can be done + // immediatly after calling XConvertSelection. + if (fl_xevent->xselection.property == XA_SECONDARY && + fl_dnd_source_window) { + fl_sendClientMessage(fl_dnd_source_window, fl_XdndFinished, + fl_xevent->xselection.requestor); + fl_dnd_source_window = 0; // don't send a second time + } + return 1;} case SelectionClear: Fl::selection_owner(0); @@ -160,5 +209,5 @@ void Fl::selection(Fl_Widget &owner, const char *stuff, int len) { #endif // -// End of "$Id: Fl_cutpaste.cxx,v 1.6.2.4.2.3 2002/01/01 15:11:31 easysw Exp $". +// End of "$Id: Fl_cutpaste.cxx,v 1.6.2.4.2.4 2002/01/09 21:50:02 easysw Exp $". // diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index f287eed8b..faa6a90c1 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -1,5 +1,5 @@ // -// "$Id: Fl_x.cxx,v 1.24.2.24.2.10 2002/01/03 18:28:37 easysw Exp $" +// "$Id: Fl_x.cxx,v 1.24.2.24.2.11 2002/01/09 21:50:02 easysw Exp $" // // X specific code for the Fast Light Tool Kit (FLTK). // @@ -263,10 +263,49 @@ Display *fl_display; int fl_screen; XVisualInfo *fl_visual; Colormap fl_colormap; +extern Fl_Widget *fl_selection_requestor; // widget doing request_paste() static Atom wm_delete_window; static Atom wm_protocols; static Atom _motif_wm_hints; +Atom fl_XdndAware; +Atom fl_XdndSelection; +Atom fl_XdndEnter; +Atom fl_XdndTypeList; +Atom fl_XdndPosition; +Atom fl_XdndLeave; +Atom fl_XdndDrop; +Atom fl_XdndStatus; +Atom fl_XdndActionCopy; +Atom fl_XdndFinished; +//Atom fl_XdndProxy; + +Window fl_dnd_source_window; +Atom *fl_dnd_source_types; // null-terminated list of data types being supplied +Atom fl_dnd_type; +Atom fl_dnd_source_action; +Atom fl_dnd_action; + +void fl_sendClientMessage(Window window, Atom message, + unsigned long d0, + unsigned long d1=0, + unsigned long d2=0, + unsigned long d3=0, + unsigned long d4=0) +{ + XEvent e; + e.xany.type = ClientMessage; + e.xany.window = window; + e.xclient.message_type = message; + e.xclient.format = 32; + e.xclient.data.l[0] = (long)d0; + e.xclient.data.l[1] = (long)d1; + e.xclient.data.l[2] = (long)d2; + e.xclient.data.l[3] = (long)d3; + e.xclient.data.l[4] = (long)d4; + XSendEvent(fl_display, window, 0, 0, &e); +} + static void fd_callback(int,void *) { do_queued_events(); @@ -303,9 +342,22 @@ void fl_open_display() { void fl_open_display(Display* d) { fl_display = d; - wm_delete_window = XInternAtom(d,"WM_DELETE_WINDOW",0); - wm_protocols = XInternAtom(d,"WM_PROTOCOLS",0); - _motif_wm_hints = XInternAtom(d,"_MOTIF_WM_HINTS",0); + wm_delete_window = XInternAtom(d,"WM_DELETE_WINDOW",0); + wm_protocols = XInternAtom(d,"WM_PROTOCOLS",0); + _motif_wm_hints = XInternAtom(d,"_MOTIF_WM_HINTS",0); + + fl_XdndAware = XInternAtom(d, "XdndAware", 0); + fl_XdndSelection = XInternAtom(d, "XdndSelection", 0); + fl_XdndEnter = XInternAtom(d, "XdndEnter", 0); + fl_XdndTypeList = XInternAtom(d, "XdndTypeList", 0); + fl_XdndPosition = XInternAtom(d, "XdndPosition", 0); + fl_XdndLeave = XInternAtom(d, "XdndLeave", 0); + fl_XdndDrop = XInternAtom(d, "XdndDrop", 0); + fl_XdndStatus = XInternAtom(d, "XdndStatus", 0); + fl_XdndActionCopy = XInternAtom(d, "XdndActionCopy", 0); + fl_XdndFinished = XInternAtom(d, "XdndFinished", 0); + //fl_XdndProxy = XInternAtom(d, "XdndProxy", 0); + Fl::add_fd(ConnectionNumber(d), POLLIN, fd_callback); fl_screen = DefaultScreen(fl_display); @@ -431,9 +483,87 @@ int fl_handle(const XEvent& xevent) if (window) switch (xevent.type) { - case ClientMessage: - if ((Atom)(xevent.xclient.data.l[0]) == wm_delete_window) event = FL_CLOSE; - break; + case ClientMessage: { + Atom message = fl_xevent->xclient.message_type; + const long* data = fl_xevent->xclient.data.l; + if ((Atom)(data[0]) == wm_delete_window) { + event = FL_CLOSE; + } else if (message == fl_XdndEnter) { + fl_dnd_source_window = data[0]; + // version number is data[1]>>24 + if (data[1]&1) { + // get list of data types: + Atom actual; int format; unsigned long count, remaining; + unsigned char *buffer = 0; + XGetWindowProperty(fl_display, fl_dnd_source_window, fl_XdndTypeList, + 0, 0x8000000L, False, XA_ATOM, &actual, &format, + &count, &remaining, &buffer); + if (actual != XA_ATOM || format != 32 || count<4 || !buffer) + goto FAILED; + delete [] fl_dnd_source_types; + fl_dnd_source_types = new Atom[count+1]; + for (unsigned i = 0; i < count; i++) + fl_dnd_source_types[i] = ((Atom*)buffer)[i]; + fl_dnd_source_types[count] = 0; + } else { + FAILED: + // less than four data types, or if the above messes up: + if (!fl_dnd_source_types) fl_dnd_source_types = new Atom[4]; + fl_dnd_source_types[0] = data[2]; + fl_dnd_source_types[1] = data[3]; + fl_dnd_source_types[2] = data[4]; + fl_dnd_source_types[3] = 0; + } + fl_dnd_type = fl_dnd_source_types[0]; // should pick text or url + event = FL_DND_ENTER; + break; + + } else if (message == fl_XdndPosition) { + fl_dnd_source_window = data[0]; + Fl::e_x_root = data[2]>>16; + Fl::e_y_root = data[2]&0xFFFF; + if (window) { + Fl::e_x = Fl::e_x_root-window->x(); + Fl::e_y = Fl::e_y_root-window->y(); + } + fl_event_time = data[3]; + fl_dnd_source_action = data[4]; + fl_dnd_action = fl_XdndActionCopy; + int accept = Fl::handle(FL_DND_DRAG, window); + fl_sendClientMessage(data[0], fl_XdndStatus, + fl_xevent->xclient.window, + accept ? 1 : 0, + 0, // used for xy rectangle to not send position inside + 0, // used for width+height of rectangle + accept ? fl_dnd_action : None); + return true; + + } else if (message == fl_XdndLeave) { + fl_dnd_source_window = 0; // don't send a finished message to it + event = FL_DND_LEAVE; + break; + + } else if (message == fl_XdndDrop) { + fl_dnd_source_window = data[0]; + fl_event_time = data[2]; + Window to_window = fl_xevent->xclient.window; + if (Fl::handle(FL_DND_RELEASE, window)) { + fl_selection_requestor = Fl::belowmouse(); + XConvertSelection(fl_display, fl_XdndSelection, + fl_dnd_type, XA_SECONDARY, + to_window, fl_event_time); + } else { + // Send the finished message if I refuse the drop. + // It is not clear whether I can just send finished always, + // or if I have to wait for the SelectionNotify event as the + // code is currently doing. + fl_sendClientMessage(fl_dnd_source_window, fl_XdndFinished, to_window); + fl_dnd_source_window = 0; + } + return true; + + } + break;} case MapNotify: event = FL_SHOW; @@ -954,5 +1084,5 @@ void Fl_Window::make_current() { #endif // -// End of "$Id: Fl_x.cxx,v 1.24.2.24.2.10 2002/01/03 18:28:37 easysw Exp $". +// End of "$Id: Fl_x.cxx,v 1.24.2.24.2.11 2002/01/09 21:50:02 easysw Exp $". // diff --git a/src/fl_dnd.cxx b/src/fl_dnd.cxx index 9390a272a..7f961c602 100644 --- a/src/fl_dnd.cxx +++ b/src/fl_dnd.cxx @@ -1,9 +1,9 @@ // -// "$Id: fl_dnd.cxx,v 1.3 2001/07/29 22:04:44 spitzak Exp $" +// "$Id: fl_dnd.cxx,v 1.3.2.1 2002/01/09 21:50:02 easysw Exp $" // // Drag & Drop code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-1999 by Bill Spitzak and others. +// Copyright 1998-2002 by Bill Spitzak and others. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -20,15 +20,17 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // -// Please report all bugs and problems to "fltk-bugs@easysw.com". +// Please report all bugs and problems to "fltk-bugs@fltk.org". // -#ifdef _WIN32 -#include "fl_dnd_win32.cxx" +#ifdef WIN32 +# include "fl_dnd_win32.cxx" +//#elif defined(__APPLE__) +//# include "fl_dnd_mac.cxx" #else -#include "fl_dnd_x.cxx" +# include "fl_dnd_x.cxx" #endif // -// End of "$Id: fl_dnd.cxx,v 1.3 2001/07/29 22:04:44 spitzak Exp $". +// End of "$Id: fl_dnd.cxx,v 1.3.2.1 2002/01/09 21:50:02 easysw Exp $". // diff --git a/src/fl_dnd_win32.cxx b/src/fl_dnd_win32.cxx index 6d4b5ab48..128fb6ec8 100644 --- a/src/fl_dnd_win32.cxx +++ b/src/fl_dnd_win32.cxx @@ -1,9 +1,9 @@ // -// "$Id: fl_dnd_win32.cxx,v 1.5 2001/09/10 01:16:17 spitzak Exp $" +// "$Id: fl_dnd_win32.cxx,v 1.5.2.1 2002/01/09 21:50:02 easysw Exp $" // // Drag & Drop code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-1999 by Bill Spitzak and others. +// Copyright 1998-2002 by Bill Spitzak and others. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -20,8 +20,7 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // -// Please report all bugs and problems to "fltk-bugs@easysw.com". -// +// Please report all bugs and problems to "fltk-bugs@fltk.org // Dummy version of dnd for now, it waits until the FL_RELEASE and @@ -34,14 +33,14 @@ #include #include -static bool grabfunc(int event) { +static int grabfunc(int event) { if (event == FL_RELEASE) Fl::pushed(0); return false; } -extern bool (*fl_local_grab)(int); // in Fl.cxx +extern int (*fl_local_grab)(int); // in Fl.cxx -bool Fl::dnd() { +int Fl::dnd() { Fl::first_window()->cursor(FL_CURSOR_HAND); fl_local_grab = grabfunc; while (Fl::pushed()) Fl::wait(); @@ -52,5 +51,5 @@ bool Fl::dnd() { // -// End of "$Id: fl_dnd_win32.cxx,v 1.5 2001/09/10 01:16:17 spitzak Exp $". +// End of "$Id: fl_dnd_win32.cxx,v 1.5.2.1 2002/01/09 21:50:02 easysw Exp $". // diff --git a/src/fl_dnd_x.cxx b/src/fl_dnd_x.cxx index 5c1a3a832..7ac02e722 100644 --- a/src/fl_dnd_x.cxx +++ b/src/fl_dnd_x.cxx @@ -1,9 +1,9 @@ // -// "$Id: fl_dnd_x.cxx,v 1.5 2001/07/23 09:50:05 spitzak Exp $" +// "$Id: fl_dnd_x.cxx,v 1.5.2.1 2002/01/09 21:50:02 easysw Exp $" // // Drag & Drop code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-1999 by Bill Spitzak and others. +// Copyright 1998-2002 by Bill Spitzak and others. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -20,12 +20,13 @@ // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA. // -// Please report all bugs and problems to "fltk-bugs@easysw.com". +// Please report all bugs and problems to "fltk-bugs@fltk.org". // -#include -#include -#include +#include +#include +#include + extern Atom fl_XdndAware; extern Atom fl_XdndSelection; @@ -41,7 +42,7 @@ extern Atom fl_XdndFinished; extern char fl_i_own_selection; -void fl_sendClientMessage(Window window, Atom message, +extern void fl_sendClientMessage(Window window, Atom message, unsigned long d0, unsigned long d1=0, unsigned long d2=0, @@ -49,7 +50,7 @@ void fl_sendClientMessage(Window window, Atom message, unsigned long d4=0); // return version # of Xdnd this window supports. Also change the -// window the the proxy if it uses a proxy: +// window to the proxy if it uses a proxy: static int dnd_aware(Window& window) { Atom actual; int format; unsigned long count, remaining; unsigned char *data = 0; @@ -62,15 +63,15 @@ static int dnd_aware(Window& window) { return 0; } -static bool grabfunc(int event) { +static int grabfunc(int event) { if (event == FL_RELEASE) Fl::pushed(0); return false; } -extern bool (*fl_local_grab)(int); // in Fl.cxx +extern int (*fl_local_grab)(int); // in Fl.cxx // send an event to an fltk window belonging to this program: -static bool local_handle(int event, Fl_Window* window) { +static int local_handle(int event, Fl_Window* window) { fl_local_grab = 0; Fl::e_x = Fl::e_x_root-window->x(); Fl::e_y = Fl::e_y_root-window->y(); @@ -79,7 +80,7 @@ static bool local_handle(int event, Fl_Window* window) { return ret; } -bool Fl::dnd() { +int Fl::dnd() { Fl::first_window()->cursor((Fl_Cursor)21); Window source_window = fl_xid(Fl::first_window()); fl_local_grab = grabfunc; @@ -166,5 +167,5 @@ bool Fl::dnd() { // -// End of "$Id: fl_dnd_x.cxx,v 1.5 2001/07/23 09:50:05 spitzak Exp $". +// End of "$Id: fl_dnd_x.cxx,v 1.5.2.1 2002/01/09 21:50:02 easysw Exp $". // -- cgit v1.2.3