summaryrefslogtreecommitdiff
path: root/src/Fl_x.cxx
diff options
context:
space:
mode:
authorBill Spitzak <spitzak@gmail.com>2002-03-07 19:22:58 +0000
committerBill Spitzak <spitzak@gmail.com>2002-03-07 19:22:58 +0000
commit5f55e1cd63883c8d48a0e212e8910f6dfd536a50 (patch)
tree2249cb0f557d70a897c8c9939ee8df8d036ed14f /src/Fl_x.cxx
parentcab1dedbd1f7f20d56a7c4bcb781569f03f52422 (diff)
Back-ported cut & paste code from fltk2.0.
This code splits the cut & paste into two buffers. The "SELECTION" is used for the currently highlighted text and for middle-mouse paste and (if possible) for handling drag & drop. The "CLIPBOARD" is for Ctrl+C and Ctrl+V style cut & paste. This matches how Motif, GTK, and KDE 3.0 work. But many older X applications (including KDE 2) can only see SELECTION, this results in cut & paste incompatability that is familiar to X users. However this now moves fltk over to the majority camp. On all systems this eliminates the annoying inability to select a region and replace it with Ctrl+V. On Mac and Win32 the SELECTION is local to the application, so middle-mouse paste only works between fields in the application. There may be tricks (special clipboard data types? use drag & drop?) to make it communicate, but unless there are standards it would be fltk-only. The file Fl_cutpaste.cxx has been deleted, so update the IDE files! The Win32 and Mac versions have NOT BEEN TESTED! I tried to be careful editing them but they may need some work. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@1989 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
Diffstat (limited to 'src/Fl_x.cxx')
-rw-r--r--src/Fl_x.cxx222
1 files changed, 174 insertions, 48 deletions
diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx
index cea27be15..5b6308626 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.12 2002/02/19 20:21:10 easysw Exp $"
+// "$Id: Fl_x.cxx,v 1.24.2.24.2.13 2002/03/07 19:22:57 spitzak Exp $"
//
// X specific code for the Fast Light Tool Kit (FLTK).
//
@@ -260,14 +260,16 @@ int fl_ready() {
////////////////////////////////////////////////////////////////
Display *fl_display;
+Window fl_message_window;
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;
+static Atom WM_DELETE_WINDOW;
+static Atom WM_PROTOCOLS;
+static Atom fl_MOTIF_WM_HINTS;
+static Atom TARGETS;
+static Atom CLIPBOARD;
Atom fl_XdndAware;
Atom fl_XdndSelection;
Atom fl_XdndEnter;
@@ -280,32 +282,6 @@ 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();
@@ -342,10 +318,11 @@ 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);
+ fl_MOTIF_WM_HINTS = XInternAtom(d, "_MOTIF_WM_HINTS", 0);
+ TARGETS = XInternAtom(d, "TARGETS", 0);
+ CLIPBOARD = XInternAtom(d, "CLIPBOARD", 0);
fl_XdndAware = XInternAtom(d, "XdndAware", 0);
fl_XdndSelection = XInternAtom(d, "XdndSelection", 0);
fl_XdndEnter = XInternAtom(d, "XdndEnter", 0);
@@ -360,16 +337,20 @@ void fl_open_display(Display* d) {
Fl::add_fd(ConnectionNumber(d), POLLIN, fd_callback);
- fl_screen = DefaultScreen(fl_display);
+ fl_screen = DefaultScreen(d);
+
+ fl_message_window =
+ XCreateSimpleWindow(d, RootWindow(d,fl_screen), 0,0,1,1,0, 0, 0);
+
// construct an XVisualInfo that matches the default Visual:
XVisualInfo templt; int num;
- templt.visualid = XVisualIDFromVisual(DefaultVisual(fl_display,fl_screen));
- fl_visual = XGetVisualInfo(fl_display, VisualIDMask, &templt, &num);
- fl_colormap = DefaultColormap(fl_display,fl_screen);
+ templt.visualid = XVisualIDFromVisual(DefaultVisual(d, fl_screen));
+ fl_visual = XGetVisualInfo(d, VisualIDMask, &templt, &num);
+ fl_colormap = DefaultColormap(d, fl_screen);
-# if !USE_COLORMAP
+#if !USE_COLORMAP
Fl::visual(FL_RGB);
-# endif
+#endif
}
void fl_close_display() {
@@ -397,6 +378,77 @@ void Fl::get_mouse(int &x, int &y) {
}
////////////////////////////////////////////////////////////////
+// Code used for paste and DnD into the program:
+
+Fl_Widget *fl_selection_requestor;
+static char *selection_buffer[2];
+static int selection_length[2];
+static int selection_buffer_length[2];
+char fl_i_own_selection[2];
+
+// Call this when a "paste" operation happens:
+void Fl::paste(Fl_Widget &receiver, int clipboard) {
+ if (fl_i_own_selection[clipboard]) {
+ // We already have it, do it quickly without window server.
+ // Notice that the text is clobbered if set_selection is
+ // called in response to FL_PASTE!
+ Fl::e_text = selection_buffer[clipboard];
+ Fl::e_length = selection_length[clipboard];
+ receiver.handle(FL_PASTE);
+ return;
+ }
+ // otherwise get the window server to return it:
+ fl_selection_requestor = &receiver;
+ Atom property = clipboard ? CLIPBOARD : XA_PRIMARY;
+ XConvertSelection(fl_display, property, XA_STRING, property,
+ fl_xid(Fl::first_window()), fl_event_time);
+}
+
+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);
+}
+
+////////////////////////////////////////////////////////////////
+// Code for copying to clipboard and DnD out of the program:
+
+void Fl::copy(const char *stuff, int len, int clipboard) {
+ if (!stuff || len<0) return;
+ if (len+1 > selection_buffer_length[clipboard]) {
+ delete[] selection_buffer[clipboard];
+ selection_buffer[clipboard] = new char[len+100];
+ selection_buffer_length[clipboard] = len+100;
+ }
+ memcpy(selection_buffer[clipboard], stuff, len);
+ selection_buffer[clipboard][len] = 0; // needed for direct paste
+ selection_length[clipboard] = len;
+ fl_i_own_selection[clipboard] = 1;
+ Atom property = clipboard ? CLIPBOARD : XA_PRIMARY;
+ XSetSelectionOwner(fl_display, property, fl_message_window, fl_event_time);
+}
+
+////////////////////////////////////////////////////////////////
const XEvent* fl_xevent; // the current x event
ulong fl_event_time; // the last timestamp from an x event
@@ -452,8 +504,6 @@ int fl_handle(const XEvent& xevent)
switch (xevent.type) {
- // events where we don't care about window:
-
case KeymapNotify:
memcpy(fl_key_vector, xevent.xkeymap.key_vector, 32);
return 0;
@@ -462,6 +512,81 @@ int fl_handle(const XEvent& xevent)
XRefreshKeyboardMapping((XMappingEvent*)&xevent.xmapping);
return 0;
+ case SelectionNotify: {
+ if (!fl_selection_requestor) return 0;
+ 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;
+ }
+ 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: {
+ int clipboard = fl_xevent->xselectionclear.selection == CLIPBOARD;
+ fl_i_own_selection[clipboard] = 0;
+ return 1;}
+
+ case SelectionRequest: {
+ XSelectionEvent e;
+ e.type = SelectionNotify;
+ e.requestor = fl_xevent->xselectionrequest.requestor;
+ e.selection = fl_xevent->xselectionrequest.selection;
+ int clipboard = e.selection == CLIPBOARD;
+ e.target = fl_xevent->xselectionrequest.target;
+ e.time = fl_xevent->xselectionrequest.time;
+ e.property = fl_xevent->xselectionrequest.property;
+ if (e.target == TARGETS) {
+ Atom a = XA_STRING;
+ XChangeProperty(fl_display, e.requestor, e.property,
+ XA_ATOM, sizeof(Atom)*8, 0, (unsigned char*)&a,
+ sizeof(Atom));
+ } else if (/*e.target == XA_STRING &&*/ selection_length[clipboard]) {
+ XChangeProperty(fl_display, e.requestor, e.property,
+ e.target, 8, 0,
+ (unsigned char *)selection_buffer[clipboard],
+ selection_length[clipboard]);
+ } else {
+// char* x = XGetAtomName(fl_display,e.target);
+// fprintf(stderr,"selection request of %s\n",x);
+// XFree(x);
+ e.property = 0;
+ }
+ XSendEvent(fl_display, e.requestor, 0, 0, (XEvent *)&e);}
+ return 1;
+
// events where interesting window id is in a different place:
case CirculateNotify:
case CirculateRequest:
@@ -486,7 +611,7 @@ int fl_handle(const XEvent& xevent)
case ClientMessage: {
Atom message = fl_xevent->xclient.message_type;
const long* data = fl_xevent->xclient.data.l;
- if ((Atom)(data[0]) == wm_delete_window) {
+ if ((Atom)(data[0]) == WM_DELETE_WINDOW) {
event = FL_CLOSE;
} else if (message == fl_XdndEnter) {
fl_dnd_source_window = data[0];
@@ -736,6 +861,7 @@ int fl_handle(const XEvent& xevent)
window->resize(X-wX, Y-wY,
xevent.xconfigure.width, xevent.xconfigure.height);
return 1;}
+
}
return Fl::handle(event, window);
@@ -879,8 +1005,8 @@ void Fl_X::make_xid(Fl_Window* w, XVisualInfo *visual, Colormap colormap)
w->label(w->label(), w->iconlabel());
- XChangeProperty(fl_display, x->xid, wm_protocols,
- XA_ATOM, 32, 0, (uchar*)&wm_delete_window, 1);
+ XChangeProperty(fl_display, x->xid, WM_PROTOCOLS,
+ XA_ATOM, 32, 0, (uchar*)&WM_DELETE_WINDOW, 1);
// send size limits and border:
x->sendxjunk();
@@ -1004,7 +1130,7 @@ void Fl_X::sendxjunk() {
XSetWMNormalHints(fl_display, xid, &hints);
XChangeProperty(fl_display, xid,
- _motif_wm_hints, _motif_wm_hints,
+ fl_MOTIF_WM_HINTS, fl_MOTIF_WM_HINTS,
32, 0, (unsigned char *)prop, 5);
}
@@ -1084,5 +1210,5 @@ void Fl_Window::make_current() {
#endif
//
-// End of "$Id: Fl_x.cxx,v 1.24.2.24.2.12 2002/02/19 20:21:10 easysw Exp $".
+// End of "$Id: Fl_x.cxx,v 1.24.2.24.2.13 2002/03/07 19:22:57 spitzak Exp $".
//