summaryrefslogtreecommitdiffstats
path: root/unix
diff options
context:
space:
mode:
authorpetasis <petasis@f3661a36-4baa-549a-d6c7-40e0ffef350e>2012-04-12 22:23:37 (GMT)
committerpetasis <petasis@f3661a36-4baa-549a-d6c7-40e0ffef350e>2012-04-12 22:23:37 (GMT)
commit464ef134f2b3db104391c1953a0200594fabcd12 (patch)
tree29b26d2f4ab4950429fc71b575af3727b5aa44ed /unix
parentebe368b5e180e079b8aa7acf04968ddd4cbba3c8 (diff)
downloadtkdnd-464ef134f2b3db104391c1953a0200594fabcd12.zip
tkdnd-464ef134f2b3db104391c1953a0200594fabcd12.tar.gz
tkdnd-464ef134f2b3db104391c1953a0200594fabcd12.tar.bz2
TkDND 2.4 released
Diffstat (limited to 'unix')
-rw-r--r--unix/TkDND_XDND.c462
-rw-r--r--unix/tkSelect.h167
-rw-r--r--unix/tkUnixSelect.c380
3 files changed, 864 insertions, 145 deletions
diff --git a/unix/TkDND_XDND.c b/unix/TkDND_XDND.c
index f2faab8..5bd877c 100644
--- a/unix/TkDND_XDND.c
+++ b/unix/TkDND_XDND.c
@@ -37,6 +37,7 @@
*/
#include "tcl.h"
#include "tk.h"
+#include <string.h>
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xatom.h>
@@ -48,7 +49,18 @@
#define LONG_MAX 0x7FFFFFFFL
#endif
-#define XDND_VERSION 5
+/*
+#define TKDND_SET_XDND_PROPERTY_ON_TARGET
+#define TKDND_SET_XDND_PROPERTY_ON_WRAPPER
+#define DEBUG_CLIENTMESSAGE_HANDLER
+ */
+#define TKDND_SET_XDND_PROPERTY_ON_TOPLEVEL
+
+#define TkDND_TkWindowChildren(tkwin) \
+ ((Tk_Window) (((Tk_FakeWin *) (tkwin))->dummy2))
+
+#define TkDND_TkWindowLastChild(tkwin) \
+ ((Tk_Window) (((Tk_FakeWin *) (tkwin))->dummy3))
#define TkDND_TkWin(x) \
(Tk_NameToWindow(interp, Tcl_GetString(x), Tk_MainWindow(interp)))
@@ -80,70 +92,158 @@ Tcl_Interp * TkDND_Interp(Tk_Window tkwin) {
#define Tk_Interp TkDND_Interp
#endif /* Tk_Interp */
+/*
+ * XDND Section
+ */
+#define XDND_VERSION 5
+
+/* XdndEnter */
+#define XDND_THREE 3
+#define XDND_ENTER_SOURCE_WIN(e) ((e)->xclient.data.l[0])
+#define XDND_ENTER_THREE_TYPES(e) (((e)->xclient.data.l[1] & 0x1UL) == 0)
+#define XDND_ENTER_THREE_TYPES_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
+#define XDND_ENTER_VERSION(e) ((e)->xclient.data.l[1] >> 24)
+#define XDND_ENTER_VERSION_SET(e,v) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24)
+#define XDND_ENTER_TYPE(e,i) ((e)->xclient.data.l[2 + i]) /* i => (0, 1, 2) */
+
+/* XdndPosition */
+#define XDND_POSITION_SOURCE_WIN(e) ((e)->xclient.data.l[0])
+#define XDND_POSITION_ROOT_X(e) ((e)->xclient.data.l[2] >> 16)
+#define XDND_POSITION_ROOT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFUL)
+#define XDND_POSITION_ROOT_SET(e,x,y) (e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL)
+#define XDND_POSITION_TIME(e) ((e)->xclient.data.l[3])
+#define XDND_POSITION_ACTION(e) ((e)->xclient.data.l[4])
+
+/* XdndStatus */
+#define XDND_STATUS_TARGET_WIN(e) ((e)->xclient.data.l[0])
+#define XDND_STATUS_WILL_ACCEPT(e) ((e)->xclient.data.l[1] & 0x1L)
+#define XDND_STATUS_WILL_ACCEPT_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
+#define XDND_STATUS_WANT_POSITION(e) ((e)->xclient.data.l[1] & 0x2UL)
+#define XDND_STATUS_WANT_POSITION_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x2UL) | (((b) == 0) ? 0 : 0x2UL)
+#define XDND_STATUS_RECT_X(e) ((e)->xclient.data.l[2] >> 16)
+#define XDND_STATUS_RECT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFL)
+#define XDND_STATUS_RECT_WIDTH(e) ((e)->xclient.data.l[3] >> 16)
+#define XDND_STATUS_RECT_HEIGHT(e) ((e)->xclient.data.l[3] & 0xFFFFL)
+#define XDND_STATUS_RECT_SET(e,x,y,w,h) {(e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL); (e)->xclient.data.l[3] = ((w) << 16) | ((h) & 0xFFFFUL); }
+#define XDND_STATUS_ACTION(e) ((e)->xclient.data.l[4])
+
+/* XdndLeave */
+#define XDND_LEAVE_SOURCE_WIN(e) ((e)->xclient.data.l[0])
+
+/* XdndDrop */
+#define XDND_DROP_SOURCE_WIN(e) ((e)->xclient.data.l[0])
+#define XDND_DROP_TIME(e) ((e)->xclient.data.l[2])
+
+/* XdndFinished */
+#define XDND_FINISHED_TARGET_WIN(e) ((e)->xclient.data.l[0])
+#define XDND_FINISHED_ACCEPTED(e) ((e)->xclient.data.l[1] & 0x1L)
+#define XDND_FINISHED_ACCEPTED_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
+#define XDND_FINISHED_ACTION(e) ((e)->xclient.data.l[2])
+
+
+/*
+ * Support for getting the wrapper window for our top-level...
+ */
+
int TkDND_RegisterTypesObjCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]) {
Atom version = XDND_VERSION;
- Tk_Window path = TkDND_TkWin(objv[1]);
+ Tk_Window path = NULL;
+ Tk_Window toplevel = NULL;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 1, objv, "path toplevel types-list");
return TCL_ERROR;
}
+ path = TkDND_TkWin(objv[1]);
+ Tk_MakeWindowExist(path);
+
+#if defined(TKDND_SET_XDND_PROPERTY_ON_WRAPPER) || \
+ defined(TKDND_SET_XDND_PROPERTY_ON_TOPLEVEL)
+ toplevel = TkDND_TkWin(objv[2]);
+ if (!Tk_IsTopLevel(toplevel)) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "path \"", Tcl_GetString(objv[2]),
+ "\" is not a toplevel window!", (char *) NULL);
+ return TCL_ERROR;
+ }
+ Tk_MakeWindowExist(toplevel);
+ Tk_MapWindow(toplevel);
+#endif
+
/*
* We must make the toplevel that holds this widget XDND aware. This means
* that we have to set the XdndAware property on our toplevel.
*/
- Tk_MakeWindowExist(path);
+#ifdef TKDND_SET_XDND_PROPERTY_ON_TARGET
XChangeProperty(Tk_Display(path), Tk_WindowId(path),
Tk_InternAtom(path, "XdndAware"),
XA_ATOM, 32, PropModeReplace,
(unsigned char *) &version, 1);
- return TCL_OK;
-#if 0
- int status;
+#endif /* TKDND_SET_XDND_PROPERTY_ON_TARGET */
+
+#ifdef TKDND_SET_XDND_PROPERTY_ON_WRAPPER
+ if (Tk_HasWrapper(toplevel)) {
+ }
+#endif /* TKDND_SET_XDND_PROPERTY_ON_WRAPPER */
+
+#ifdef TKDND_SET_XDND_PROPERTY_ON_TOPLEVEL
Window root_return, parent, *children_return = 0;
unsigned int nchildren_return;
- Tk_Window toplevel = TkDND_TkWin(objv[2]);
- if (!Tk_IsTopLevel(toplevel)) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "path \"", Tcl_GetString(objv[2]),
- "\" is not a toplevel window!", (char *) NULL);
- return TCL_ERROR;
- }
- Tk_MakeWindowExist(toplevel);
- Tk_MapWindow(toplevel);
- status = XQueryTree(Tk_Display(toplevel), Tk_WindowId(toplevel),
- &root_return, &parent,
- &children_return, &nchildren_return);
+ XQueryTree(Tk_Display(toplevel), Tk_WindowId(toplevel),
+ &root_return, &parent,
+ &children_return, &nchildren_return);
if (children_return) XFree(children_return);
XChangeProperty(Tk_Display(toplevel), parent,
Tk_InternAtom(toplevel, "XdndAware"),
XA_ATOM, 32, PropModeReplace,
(unsigned char *) &version, 1);
+#endif /* TKDND_SET_XDND_PROPERTY_ON_TOPLEVEL */
return TCL_OK;
-#endif
} /* TkDND_RegisterTypesObjCmd */
-int TkDND_HandleXdndEnter(Tk_Window tkwin, XClientMessageEvent cm) {
+int TkDND_HandleXdndEnter(Tk_Window tkwin, XEvent *xevent) {
Tcl_Interp *interp = Tk_Interp(tkwin);
- Atom *typelist;
- const long *l = cm.data.l;
- int i, version = (int)(((unsigned long)(l[1])) >> 24);
+ Atom *typelist = NULL;
+ int i, version = (int) XDND_ENTER_VERSION(xevent);
Window drag_source;
+ // Window drop_toplevel, drop_window;
Tcl_Obj* objv[4], *element;
- if (interp == NULL) return False;
+ if (interp == NULL) return False;
if (version > XDND_VERSION) return False;
- drag_source = l[0];
- if (l[1] & 0x1UL) {
+#if XDND_VERSION >= 3
+ if (version < 3) return False;
+#endif
+
+//#if XDND_VERSION >= 3
+// /* XdndEnter is delivered to the toplevel window, which is the wrapper
+// * window for the Tk toplevel. We don't yet know the sub-window the mouse
+// * is in... */
+// drop_toplevel = xevent->xany.window;
+// drop_window = 0;
+//#else
+// drop_toplevel = 0
+// drop_window = xevent->xany.window;
+//#endif
+ drag_source = XDND_ENTER_SOURCE_WIN(xevent);
+
+ if (XDND_ENTER_THREE_TYPES(xevent)) {
+ typelist = (Atom *) Tcl_Alloc(sizeof(Atom)*4);
+ if (typelist == NULL) return False;
+ typelist[0] = xevent->xclient.data.l[2];
+ typelist[1] = xevent->xclient.data.l[3];
+ typelist[2] = xevent->xclient.data.l[4];
+ typelist[3] = None;
+ } else {
/* Get the types from XdndTypeList property. */
Atom actualType = None;
int actualFormat;
unsigned long itemCount, remainingBytes;
Atom *data;
- XGetWindowProperty(cm.display, drag_source,
+ XGetWindowProperty(xevent->xclient.display, drag_source,
Tk_InternAtom(tkwin, "XdndTypeList"), 0,
LONG_MAX, False, XA_ATOM, &actualType, &actualFormat,
&itemCount, &remainingBytes, (unsigned char **) &data);
@@ -152,13 +252,6 @@ int TkDND_HandleXdndEnter(Tk_Window tkwin, XClientMessageEvent cm) {
for (i=0; i<itemCount; i++) { typelist[i] = data[i]; }
typelist[itemCount] = None;
if (data) XFree((unsigned char*)data);
- } else {
- typelist = (Atom *) Tcl_Alloc(sizeof(Atom)*4);
- if (typelist == NULL) return False;
- typelist[0] = cm.data.l[2];
- typelist[1] = cm.data.l[3];
- typelist[2] = cm.data.l[4];
- typelist[3] = None;
}
/* We have all the information we need. Its time to pass it at the Tcl
* level.*/
@@ -175,14 +268,13 @@ int TkDND_HandleXdndEnter(Tk_Window tkwin, XClientMessageEvent cm) {
return True;
} /* TkDND_HandleXdndEnter */
-int TkDND_HandleXdndPosition(Tk_Window tkwin, XClientMessageEvent cm) {
+int TkDND_HandleXdndPosition(Tk_Window tkwin, XEvent *xevent) {
Tcl_Interp *interp = Tk_Interp(tkwin);
Tk_Window mouse_tkwin;
Tcl_Obj* result;
Tcl_Obj* objv[4];
- const unsigned long *l = (const unsigned long *) cm.data.l;
- int rootX, rootY, i, index, status;
- XClientMessageEvent response;
+ int rootX, rootY, dx, dy, i, index, status;
+ XEvent response;
int width = 1, height = 1;
static char *DropActions[] = {
"copy", "move", "link", "ask", "private", "refuse_drop", "default",
@@ -192,36 +284,31 @@ int TkDND_HandleXdndPosition(Tk_Window tkwin, XClientMessageEvent cm) {
ActionCopy, ActionMove, ActionLink, ActionAsk, ActionPrivate,
refuse_drop, ActionDefault
};
+ Time time;
+ Atom action;
if (interp == NULL) return False;
- rootX = (l[2] & 0xffff0000) >> 16;
- rootY = l[2] & 0x0000ffff;
+ /* Get the coordinates from the event... */
+ rootX = XDND_POSITION_ROOT_X(xevent);
+ rootY = XDND_POSITION_ROOT_Y(xevent);
+ /* Get the time from the event... */
+ time = XDND_POSITION_TIME(xevent);
+ /* Get the user action from the event... */
+ action = XDND_POSITION_ACTION(xevent);
+
+ /* Find the Tk widget under the mouse... */
+ Tk_GetRootCoords(tkwin, &dx, &dy);
mouse_tkwin = Tk_CoordsToWindow(rootX, rootY, tkwin);
if (mouse_tkwin == NULL) {
- /* We received the client message, but we cannot find a window? Strange...*/
- /* A last attemp: execute wm containing x, y */
- objv[0] = Tcl_NewStringObj("update", -1);
- TkDND_Eval(1);
- objv[0] = Tcl_NewStringObj("winfo", -1);
- objv[1] = Tcl_NewStringObj("containing", -1);
- objv[2] = Tcl_NewIntObj(rootX);
- objv[3] = Tcl_NewIntObj(rootY);
- TkDND_Status_Eval(4);
- if (status == TCL_OK) {
- result = Tcl_GetObjResult(interp); Tcl_IncrRefCount(result);
- mouse_tkwin = Tk_NameToWindow(interp, Tcl_GetString(result),
- Tk_MainWindow(interp));
- Tcl_DecrRefCount(result);
- }
+ mouse_tkwin = Tk_CoordsToWindow(rootX + dx, rootY + dy, tkwin);
}
- /* Get the drag source. */
- objv[0] = Tcl_NewStringObj("tkdnd::xdnd::_GetDragSource", -1);
- TkDND_Status_Eval(1); if (status != TCL_OK) return False;
- if (Tcl_GetLongFromObj(interp, Tcl_GetObjResult(interp),
- (long *)&response.window) != TCL_OK) return False;
- /* Now that we have found the containing widget, ask it whether it will accept
- * the drop... */
+#if 0
+ printf("mouse_win: %p (%s) (%d, %d %p %s) i=%p\n", mouse_tkwin,
+ mouse_tkwin?Tk_PathName(mouse_tkwin):"",
+ rootX, rootY, tkwin, Tk_PathName(tkwin), interp);
+#endif
+ /* Ask the Tk widget whether it will accept the drop... */
index = refuse_drop;
if (mouse_tkwin != NULL) {
objv[0] = Tcl_NewStringObj("tkdnd::xdnd::_HandleXdndPosition", -1);
@@ -238,37 +325,48 @@ int TkDND_HandleXdndPosition(Tk_Window tkwin, XClientMessageEvent cm) {
if (status != TCL_OK) index = refuse_drop;
}
}
- /* Sent */
- response.type = ClientMessage;
- response.format = 32;
- response.message_type = Tk_InternAtom(tkwin, "XdndStatus");
- response.data.l[0] = (mouse_tkwin!=NULL) ? Tk_WindowId(mouse_tkwin) : 0;
- response.data.l[1] = 1; /* yes */
- response.data.l[2] = ((rootX) << 16) | ((rootY) & 0xFFFFUL); /* x, y */
- response.data.l[3] = ((width) << 16) | ((height) & 0xFFFFUL); /* w, h */
- response.data.l[4] = 0; /* action */
+ /* Sent a XdndStatus event, to notify the drag source */
+ memset (&response, 0, sizeof(xevent));
+ response.xany.type = ClientMessage;
+ response.xany.display = xevent->xclient.display;
+ response.xclient.window = XDND_POSITION_SOURCE_WIN(xevent);
+ response.xclient.message_type = Tk_InternAtom(tkwin, "XdndStatus");
+ response.xclient.format = 32;
+ XDND_STATUS_WILL_ACCEPT_SET(&response, 1);
+ XDND_STATUS_WANT_POSITION_SET(&response, 1);
+ XDND_STATUS_RECT_SET(&response, rootX, rootY, width, height);
+#if XDND_VERSION >= 3
+ XDND_STATUS_TARGET_WIN(&response) = Tk_WindowId(tkwin);
+#else
+ XDND_STATUS_TARGET_WIN(&response) = xevent->xany.window;
+#endif
switch ((enum dropactions) index) {
case ActionDefault:
case ActionCopy:
- response.data.l[4] = Tk_InternAtom(tkwin, "XdndActionCopy"); break;
+ XDND_STATUS_ACTION(&response) = Tk_InternAtom(tkwin, "XdndActionCopy");
+ break;
case ActionMove:
- response.data.l[4] = Tk_InternAtom(tkwin, "XdndActionMove"); break;
+ XDND_STATUS_ACTION(&response) = Tk_InternAtom(tkwin, "XdndActionMove");
+ break;
case ActionLink:
- response.data.l[4] = Tk_InternAtom(tkwin, "XdndActionLink"); break;
+ XDND_STATUS_ACTION(&response) = Tk_InternAtom(tkwin, "XdndActionLink");
+ break;
case ActionAsk:
- response.data.l[4] = Tk_InternAtom(tkwin, "XdndActionAsk"); break;
+ XDND_STATUS_ACTION(&response) = Tk_InternAtom(tkwin, "XdndActionAsk");
+ break;
case ActionPrivate:
- response.data.l[4] = Tk_InternAtom(tkwin, "XdndActionPrivate"); break;
+ XDND_STATUS_ACTION(&response) = Tk_InternAtom(tkwin, "XdndActionPrivate");
+ break;
case refuse_drop: {
- response.data.l[1] = 0; /* Refuse drop. */
+ XDND_STATUS_WILL_ACCEPT_SET(&response, 0); /* Refuse drop. */
}
}
- XSendEvent(cm.display, response.window, False, NoEventMask,
- (XEvent*)&response);
+ XSendEvent(response.xany.display, response.xclient.window,
+ False, NoEventMask, (XEvent*)&response);
return True;
} /* TkDND_HandleXdndPosition */
-int TkDND_HandleXdndLeave(Tk_Window tkwin, XClientMessageEvent cm) {
+int TkDND_HandleXdndLeave(Tk_Window tkwin, XEvent *xevent) {
Tcl_Interp *interp = Tk_Interp(tkwin);
Tcl_Obj* objv[1];
int i;
@@ -278,12 +376,12 @@ int TkDND_HandleXdndLeave(Tk_Window tkwin, XClientMessageEvent cm) {
return True;
} /* TkDND_HandleXdndLeave */
-int TkDND_HandleXdndDrop(Tk_Window tkwin, XClientMessageEvent cm) {
- XClientMessageEvent finished;
+int TkDND_HandleXdndDrop(Tk_Window tkwin, XEvent *xevent) {
+ XEvent finished;
Tcl_Interp *interp = Tk_Interp(tkwin);
Tcl_Obj* objv[2], *result;
int status, i, index;
- Time time = cm.data.l[2];
+ Time time = XDND_DROP_TIME(xevent);
static char *DropActions[] = {
"copy", "move", "link", "ask", "private", "refuse_drop", "default",
(char *) NULL
@@ -295,25 +393,23 @@ int TkDND_HandleXdndDrop(Tk_Window tkwin, XClientMessageEvent cm) {
if (interp == NULL) return False;
- /* Get the drag source. */
- objv[0] = Tcl_NewStringObj("tkdnd::xdnd::_GetDragSource", -1);
- TkDND_Status_Eval(1); if (status != TCL_OK) return False;
- if (Tcl_GetLongFromObj(interp, Tcl_GetObjResult(interp),
- (long *) &finished.window) != TCL_OK) return False;
-
- /* Get the drop target. */
- objv[0] = Tcl_NewStringObj("tkdnd::xdnd::_GetDropTarget", -1);
- TkDND_Status_Eval(1);
- if (Tcl_GetLongFromObj(interp,
- Tcl_GetObjResult(interp), &finished.data.l[0]) != TCL_OK) {
- finished.data.l[0] = None;
- }
+ memset(&finished, 0, sizeof(XEvent));
+ finished.xany.type = ClientMessage;
+ finished.xany.display = xevent->xclient.display;
+ finished.xclient.window = XDND_DROP_SOURCE_WIN(xevent);
+ finished.xclient.message_type = Tk_InternAtom(tkwin, "XdndFinished");
+ finished.xclient.format = 32;
+#if XDND_VERSION >= 3
+ XDND_FINISHED_TARGET_WIN(&finished) = Tk_WindowId(tkwin);
+#else
+ XDND_FINISHED_TARGET_WIN(&finished) = xevent->xany.window;
+#endif
+ XDND_FINISHED_ACCEPTED_SET(&finished, 1);
/* Call out Tcl callback. */
objv[0] = Tcl_NewStringObj("tkdnd::xdnd::_HandleXdndDrop", -1);
- objv[1] = Tcl_NewWideIntObj(time);
+ objv[1] = Tcl_NewLongObj(time);
TkDND_Status_Eval(2);
- finished.data.l[1] = 1; /* Accept drop. */
if (status == TCL_OK) {
/* Get the returned action... */
result = Tcl_GetObjResult(interp); Tcl_IncrRefCount(result);
@@ -324,105 +420,176 @@ int TkDND_HandleXdndDrop(Tk_Window tkwin, XClientMessageEvent cm) {
switch ((enum dropactions) index) {
case ActionDefault:
case ActionCopy:
- finished.data.l[2] = Tk_InternAtom(tkwin, "XdndActionCopy"); break;
+ XDND_FINISHED_ACTION(&finished) =
+ Tk_InternAtom(tkwin, "XdndActionCopy"); break;
case ActionMove:
- finished.data.l[2] = Tk_InternAtom(tkwin, "XdndActionMove"); break;
+ XDND_FINISHED_ACTION(&finished) =
+ Tk_InternAtom(tkwin, "XdndActionMove"); break;
case ActionLink:
- finished.data.l[2] = Tk_InternAtom(tkwin, "XdndActionLink"); break;
+ XDND_FINISHED_ACTION(&finished) =
+ Tk_InternAtom(tkwin, "XdndActionLink"); break;
case ActionAsk:
- finished.data.l[2] = Tk_InternAtom(tkwin, "XdndActionAsk"); break;
+ XDND_FINISHED_ACTION(&finished) =
+ Tk_InternAtom(tkwin, "XdndActionAsk"); break;
case ActionPrivate:
- finished.data.l[2] = Tk_InternAtom(tkwin, "XdndActionPrivate"); break;
+ XDND_FINISHED_ACTION(&finished) =
+ Tk_InternAtom(tkwin, "XdndActionPrivate"); break;
case refuse_drop: {
- finished.data.l[1] = 0; /* Drop canceled. */
+ XDND_FINISHED_ACCEPTED_SET(&finished, 0); /* Drop canceled. */
}
}
} else {
- finished.data.l[1] = 0;
+ XDND_FINISHED_ACCEPTED_SET(&finished, 0);
}
/* Send XdndFinished. */
- finished.type = ClientMessage;
- finished.format = 32;
- finished.message_type = Tk_InternAtom(tkwin, "XdndFinished");
- XSendEvent(cm.display, finished.window, False, NoEventMask,
- (XEvent*)&finished);
+ XSendEvent(finished.xany.display, finished.xclient.window,
+ False, NoEventMask, (XEvent*)&finished);
return True;
} /* TkDND_HandleXdndDrop */
-int TkDND_HandleXdndStatus(Tk_Window tkwin, XClientMessageEvent cm) {
+int TkDND_HandleXdndStatus(Tk_Window tkwin, XEvent *xevent) {
return False;
} /* TkDND_HandleXdndStatus */
-int TkDND_HandleXdndFinished(Tk_Window tkwin, XClientMessageEvent cm) {
+int TkDND_HandleXdndFinished(Tk_Window tkwin, XEvent *xevent) {
return False;
} /* TkDND_HandleXdndFinished */
static int TkDND_XDNDHandler(Tk_Window tkwin, XEvent *xevent) {
- XClientMessageEvent clientMessage;
if (xevent->type != ClientMessage) return False;
- clientMessage = xevent->xclient;
- if (clientMessage.message_type == Tk_InternAtom(tkwin, "XdndPosition")) {
+ if (xevent->xclient.message_type == Tk_InternAtom(tkwin, "XdndPosition")) {
#ifdef DEBUG_CLIENTMESSAGE_HANDLER
printf("XDND_HandleClientMessage: Received XdndPosition\n");
#endif /* DEBUG_CLIENTMESSAGE_HANDLER */
- return TkDND_HandleXdndPosition(tkwin, clientMessage);
- } else if (clientMessage.message_type == Tk_InternAtom(tkwin, "XdndEnter")) {
+ return TkDND_HandleXdndPosition(tkwin, xevent);
+ } else if (xevent->xclient.message_type== Tk_InternAtom(tkwin, "XdndEnter")) {
#ifdef DEBUG_CLIENTMESSAGE_HANDLER
printf("XDND_HandleClientMessage: Received XdndEnter\n");
#endif /* DEBUG_CLIENTMESSAGE_HANDLER */
- return TkDND_HandleXdndEnter(tkwin, clientMessage);
- } else if (clientMessage.message_type == Tk_InternAtom(tkwin, "XdndStatus")) {
+ return TkDND_HandleXdndEnter(tkwin, xevent);
+ } else if (xevent->xclient.message_type==Tk_InternAtom(tkwin, "XdndStatus")) {
#ifdef DEBUG_CLIENTMESSAGE_HANDLER
printf("XDND_HandleClientMessage: Received XdndStatus\n");
#endif /* DEBUG_CLIENTMESSAGE_HANDLER */
- return TkDND_HandleXdndStatus(tkwin, clientMessage);
- } else if (clientMessage.message_type == Tk_InternAtom(tkwin, "XdndLeave")) {
+ return TkDND_HandleXdndStatus(tkwin, xevent);
+ } else if (xevent->xclient.message_type== Tk_InternAtom(tkwin, "XdndLeave")) {
#ifdef DEBUG_CLIENTMESSAGE_HANDLER
printf("XDND_HandleClientMessage: Received XdndLeave\n");
#endif /* DEBUG_CLIENTMESSAGE_HANDLER */
- return TkDND_HandleXdndLeave(tkwin, clientMessage);
- } else if (clientMessage.message_type == Tk_InternAtom(tkwin, "XdndDrop")) {
+ return TkDND_HandleXdndLeave(tkwin, xevent);
+ } else if (xevent->xclient.message_type == Tk_InternAtom(tkwin, "XdndDrop")) {
#ifdef DEBUG_CLIENTMESSAGE_HANDLER
printf("XDND_HandleClientMessage: Received XdndDrop\n");
#endif /* DEBUG_CLIENTMESSAGE_HANDLER */
- return TkDND_HandleXdndDrop(tkwin, clientMessage);
- } else if (clientMessage.message_type ==
+ return TkDND_HandleXdndDrop(tkwin, xevent);
+ } else if (xevent->xclient.message_type ==
Tk_InternAtom(tkwin, "XdndFinished")) {
#ifdef DEBUG_CLIENTMESSAGE_HANDLER
printf("XDND_HandleClientMessage: Received XdndFinished\n");
#endif /* DEBUG_CLIENTMESSAGE_HANDLER */
- return TkDND_HandleXdndFinished(tkwin, clientMessage);
+ return TkDND_HandleXdndFinished(tkwin, xevent);
} else {
#ifdef TKDND_ENABLE_MOTIF_DROPS
- if (MotifDND_HandleClientMessage(dnd, *xevent)) return True;
+ if (MotifDND_HandleClientMessage(dnd, xevent)) return True;
#endif /* TKDND_ENABLE_MOTIF_DROPS */
}
return False;
} /* TkDND_XDNDHandler */
+/*
+ * The following two functions were copied from tkSelect.c
+ * If TIP 370 gets implemented, they will not be required.
+ */
+static int TkDND_SelGetProc(ClientData clientData,
+ Tcl_Interp *interp, const char *portion) {
+ Tcl_DStringAppend(clientData, portion, -1);
+ return TCL_OK;
+}; /* TkDND_SelGetProc */
+
int TkDND_GetSelectionObjCmd(ClientData clientData, Tcl_Interp *interp,
int objc, Tcl_Obj *CONST objv[]) {
- Time time;
- Tk_Window path;
+ Tk_Window tkwin = Tk_MainWindow(interp);
+ Atom target;
Atom selection;
-
- if (objc != 4) {
- Tcl_WrongNumArgs(interp, 1, objv, "path time type");
- return TCL_ERROR;
+ Time time = CurrentTime;
+ const char *targetName = NULL;
+ Tcl_DString selBytes;
+ int result;
+ static const char *const getOptionStrings[] = {
+ "-displayof", "-selection", "-time", "-type", NULL
+ };
+ enum getOptions { GET_DISPLAYOF, GET_SELECTION, GET_TIME, GET_TYPE };
+ int getIndex;
+ int count;
+ Tcl_Obj **objs;
+ const char *string;
+ const char *path = NULL;
+ const char *selName = NULL;
+
+ for (count = objc-1, objs = ((Tcl_Obj **)objv)+1; count>0;
+ count-=2, objs+=2) {
+ string = Tcl_GetString(objs[0]);
+ if (string[0] != '-') {
+ break;
+ }
+ if (count < 2) {
+ Tcl_AppendResult(interp, "value for \"", string,
+ "\" missing", NULL);
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetIndexFromObj(interp, objs[0], getOptionStrings,
+ "option", 0, &getIndex) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ switch ((enum getOptions) getIndex) {
+ case GET_DISPLAYOF:
+ path = Tcl_GetString(objs[1]);
+ break;
+ case GET_SELECTION:
+ selName = Tcl_GetString(objs[1]);
+ break;
+ case GET_TYPE:
+ targetName = Tcl_GetString(objs[1]);
+ break;
+ case GET_TIME:
+ if (Tcl_GetLongFromObj(interp, objs[1], (long *) &time) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ break;
+ }
}
-
- if (Tcl_GetLongFromObj(interp, objv[2], (long *) &time) != TCL_OK) {
- return TCL_ERROR;
+ if (path != NULL) {
+ tkwin = Tk_NameToWindow(interp, path, tkwin);
}
-
- path = TkDND_TkWin(objv[1]);
- selection = Tk_InternAtom(path, "XdndSelection");
-
- XConvertSelection(Tk_Display(path), selection,
- Tk_InternAtom(path, Tcl_GetString(objv[3])),
- selection, Tk_WindowId(path), time);
- return TCL_OK;
+ if (tkwin == NULL) {
+ return TCL_ERROR;
+ }
+ if (selName != NULL) {
+ selection = Tk_InternAtom(tkwin, selName);
+ } else {
+ selection = XA_PRIMARY;
+ }
+ if (count > 1) {
+ Tcl_WrongNumArgs(interp, 1, objv, "?-option value ...?");
+ return TCL_ERROR;
+ } else if (count == 1) {
+ target = Tk_InternAtom(tkwin, Tcl_GetString(objs[0]));
+ } else if (targetName != NULL) {
+ target = Tk_InternAtom(tkwin, targetName);
+ } else {
+ target = XA_STRING;
+ }
+ Tcl_DStringInit(&selBytes);
+ result = TkDND_GetSelection(interp, tkwin, selection, target, time,
+ TkDND_SelGetProc, &selBytes);
+ if (1 ||result == TCL_OK) {
+ Tcl_DStringResult(interp, &selBytes);
+ }
+ Tcl_DStringFree(&selBytes);
+ return result;
} /* TkDND_GetSelectionObjCmd */
/*
@@ -439,6 +606,7 @@ DLLEXPORT int Tkdnd_SafeInit(Tcl_Interp *interp);
int DLLEXPORT Tkdnd_Init(Tcl_Interp *interp) {
int major, minor, patchlevel;
+ Tcl_CmdInfo info;
if (
#ifdef USE_TCL_STUBS
@@ -468,6 +636,10 @@ int DLLEXPORT Tkdnd_Init(Tcl_Interp *interp) {
return TCL_ERROR;
}
+ if (Tcl_GetCommandInfo(interp, "selection", &info) == 0) {
+ Tcl_SetResult(interp, "selection Tk command not found", TCL_STATIC);
+ return TCL_ERROR;
+ }
/* Register the various commands */
if (Tcl_CreateObjCommand(interp, "_register_types",
@@ -476,7 +648,7 @@ int DLLEXPORT Tkdnd_Init(Tcl_Interp *interp) {
return TCL_ERROR;
}
- if (Tcl_CreateObjCommand(interp, "_get_selection",
+ if (Tcl_CreateObjCommand(interp, "_selection_get",
(Tcl_ObjCmdProc*) TkDND_GetSelectionObjCmd,
(ClientData) NULL, (Tcl_CmdDeleteProc *) NULL) == NULL) {
return TCL_ERROR;
diff --git a/unix/tkSelect.h b/unix/tkSelect.h
new file mode 100644
index 0000000..74326d0
--- /dev/null
+++ b/unix/tkSelect.h
@@ -0,0 +1,167 @@
+/*
+ * tkSelect.h --
+ *
+ * Declarations of types shared among the files that implement selection
+ * support.
+ *
+ * Copyright (c) 1995 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#ifndef _TKSELECT
+#define _TKSELECT
+
+/*
+ * When a selection is owned by a window on a given display, one of the
+ * following structures is present on a list of current selections in the
+ * display structure. The structure is used to record the current owner of a
+ * selection for use in later retrieval requests. There is a list of such
+ * structures because a display can have multiple different selections active
+ * at the same time.
+ */
+
+typedef struct TkSelectionInfo {
+ Atom selection; /* Selection name, e.g. XA_PRIMARY. */
+ Tk_Window owner; /* Current owner of this selection. */
+ int serial; /* Serial number of last XSelectionSetOwner
+ * request made to server for this selection
+ * (used to filter out redundant
+ * SelectionClear events). */
+ Time time; /* Timestamp used to acquire selection. */
+ Tk_LostSelProc *clearProc; /* Procedure to call when owner loses
+ * selection. */
+ ClientData clearData; /* Info to pass to clearProc. */
+ struct TkSelectionInfo *nextPtr;
+ /* Next in list of current selections on this
+ * display. NULL means end of list. */
+} TkSelectionInfo;
+
+/*
+ * One of the following structures exists for each selection handler created
+ * for a window by calling Tk_CreateSelHandler. The handlers are linked in a
+ * list rooted in the TkWindow structure.
+ */
+
+typedef struct TkSelHandler {
+ Atom selection; /* Selection name, e.g. XA_PRIMARY. */
+ Atom target; /* Target type for selection conversion, such
+ * as TARGETS or STRING. */
+ Atom format; /* Format in which selection info will be
+ * returned, such as STRING or ATOM. */
+ Tk_SelectionProc *proc; /* Procedure to generate selection in this
+ * format. */
+ ClientData clientData; /* Argument to pass to proc. */
+ int size; /* Size of units returned by proc (8 for
+ * STRING, 32 for almost anything else). */
+ struct TkSelHandler *nextPtr;
+ /* Next selection handler associated with same
+ * window (NULL for end of list). */
+} TkSelHandler;
+
+/*
+ * When the selection is being retrieved, one of the following structures is
+ * present on a list of pending selection retrievals. The structure is used to
+ * communicate between the background procedure that requests the selection
+ * and the foreground event handler that processes the events in which the
+ * selection is returned. There is a list of such structures so that there can
+ * be multiple simultaneous selection retrievals (e.g. on different displays).
+ */
+
+typedef struct TkSelRetrievalInfo {
+ Tcl_Interp *interp; /* Interpreter for error reporting. */
+ TkWindow *winPtr; /* Window used as requestor for selection. */
+ Atom selection; /* Selection being requested. */
+ Atom property; /* Property where selection will appear. */
+ Atom target; /* Desired form for selection. */
+ Tk_GetSelProc *proc; /* Procedure to call to handle pieces of
+ * selection. */
+ ClientData clientData; /* Argument for proc. */
+ int result; /* Initially -1. Set to a Tcl return value
+ * once the selection has been retrieved. */
+ Tcl_TimerToken timeout; /* Token for current timeout procedure. */
+ int idleTime; /* Number of seconds that have gone by without
+ * hearing anything from the selection
+ * owner. */
+ Tcl_EncodingState encState; /* Holds intermediate state during translations
+ * of data that cross buffer boundaries. */
+ int encFlags; /* Encoding translation state flags. */
+ Tcl_DString buf; /* Buffer to hold translation data. */
+ struct TkSelRetrievalInfo *nextPtr;
+ /* Next in list of all pending selection
+ * retrievals. NULL means end of list. */
+} TkSelRetrievalInfo;
+
+/*
+ * The clipboard contains a list of buffers of various types and formats. All
+ * of the buffers of a given type will be returned in sequence when the
+ * CLIPBOARD selection is retrieved. All buffers of a given type on the same
+ * clipboard must have the same format. The TkClipboardTarget structure is
+ * used to record the information about a chain of buffers of the same type.
+ */
+
+typedef struct TkClipboardBuffer {
+ char *buffer; /* Null terminated data buffer. */
+ long length; /* Length of string in buffer. */
+ struct TkClipboardBuffer *nextPtr;
+ /* Next in list of buffers. NULL means end of
+ * list . */
+} TkClipboardBuffer;
+
+typedef struct TkClipboardTarget {
+ Atom type; /* Type conversion supported. */
+ Atom format; /* Representation used for data. */
+ TkClipboardBuffer *firstBufferPtr;
+ /* First in list of data buffers. */
+ TkClipboardBuffer *lastBufferPtr;
+ /* Last in list of clipboard buffers. Used to
+ * speed up appends. */
+ struct TkClipboardTarget *nextPtr;
+ /* Next in list of targets on clipboard. NULL
+ * means end of list. */
+} TkClipboardTarget;
+
+/*
+ * It is possible for a Tk_SelectionProc to delete the handler that it
+ * represents. If this happens, the code that is retrieving the selection
+ * needs to know about it so it doesn't use the now-defunct handler structure.
+ * One structure of the following form is created for each retrieval in
+ * progress, so that the retriever can find out if its handler is deleted. All
+ * of the pending retrievals (if there are more than one) are linked into a
+ * list.
+ */
+
+typedef struct TkSelInProgress {
+ TkSelHandler *selPtr; /* Handler being executed. If this handler is
+ * deleted, the field is set to NULL. */
+ struct TkSelInProgress *nextPtr;
+ /* Next higher nested search. */
+} TkSelInProgress;
+
+/*
+ * Chunk size for retrieving selection. It's defined both in words and in
+ * bytes; the word size is used to allocate buffer space that's guaranteed to
+ * be word-aligned and that has an extra character for the terminating NULL.
+ */
+
+#define TK_SEL_BYTES_AT_ONCE 4000
+#define TK_SEL_WORDS_AT_ONCE 1001
+
+/*
+ * Declarations for procedures that are used by the selection-related files
+ * but shouldn't be used anywhere else in Tk (or by Tk clients):
+ */
+
+MODULE_SCOPE TkSelInProgress *TkSelGetInProgress(void);
+MODULE_SCOPE void TkSelSetInProgress(TkSelInProgress *pendingPtr);
+MODULE_SCOPE void TkSelClearSelection(Tk_Window tkwin, XEvent *eventPtr);
+MODULE_SCOPE int TkSelDefaultSelection(TkSelectionInfo *infoPtr,
+ Atom target, char *buffer, int maxBytes,
+ Atom *typePtr);
+#ifndef TkSelUpdateClipboard
+MODULE_SCOPE void TkSelUpdateClipboard(TkWindow *winPtr,
+ TkClipboardTarget *targetPtr);
+#endif
+
+#endif /* _TKSELECT */
diff --git a/unix/tkUnixSelect.c b/unix/tkUnixSelect.c
new file mode 100644
index 0000000..5d08d4e
--- /dev/null
+++ b/unix/tkUnixSelect.c
@@ -0,0 +1,380 @@
+/*
+ * tkUnixSelect.c --
+ *
+ * This file contains X specific routines for manipulating selections.
+ *
+ * Copyright (c) 1995-1997 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution of
+ * this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#include "tk.h"
+#include "tkInt.h"
+#include "tkSelect.h"
+
+static TkSelRetrievalInfo *pendingRetrievals = NULL;
+ /* List of all retrievals currently being
+ * waited for. */
+
+/*
+ * Forward declarations for functions defined in this file:
+ */
+
+static void TkDND_SelTimeoutProc(ClientData clientData);
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkDNDSelGetSelection --
+ *
+ * Retrieve the specified selection from another process.
+ *
+ * Results:
+ * The return value is a standard Tcl return value. If an error occurs
+ * (such as no selection exists) then an error message is left in the
+ * interp's result.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkDNDSelGetSelection(
+ Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
+ Tk_Window tkwin, /* Window on whose behalf to retrieve the
+ * selection (determines display from which to
+ * retrieve). */
+ Atom selection, /* Selection to retrieve. */
+ Atom target, /* Desired form in which selection is to be
+ * returned. */
+ Time time,
+ Tk_GetSelProc *proc, /* Function to call to process the selection,
+ * once it has been retrieved. */
+ ClientData clientData) /* Arbitrary value to pass to proc. */
+{
+ TkSelRetrievalInfo retr;
+ TkWindow *winPtr = (TkWindow *) tkwin;
+ TkDisplay *dispPtr = winPtr->dispPtr;
+
+ /*
+ * The selection is owned by some other process. To retrieve it, first
+ * record information about the retrieval in progress. Use an internal
+ * window as the requestor.
+ */
+
+ retr.interp = interp;
+ if (dispPtr->clipWindow == NULL) {
+ int result;
+
+ result = TkClipInit(interp, dispPtr);
+ if (result != TCL_OK) {
+printf("1\n");
+ return result;
+ }
+ }
+ retr.winPtr = (TkWindow *) dispPtr->clipWindow;
+ retr.selection = selection;
+ retr.property = selection;
+ retr.target = target;
+ retr.proc = proc;
+ retr.clientData = clientData;
+ retr.result = -1;
+ retr.idleTime = 0;
+ retr.encFlags = TCL_ENCODING_START;
+ retr.nextPtr = pendingRetrievals;
+ Tcl_DStringInit(&retr.buf);
+ pendingRetrievals = &retr;
+
+ /*
+ * Initiate the request for the selection. Note: can't use TkCurrentTime
+ * for the time. If we do, and this application hasn't received any X
+ * events in a long time, the current time will be way in the past and
+ * could even predate the time when the selection was made; if this
+ * happens, the request will be rejected.
+ */
+
+ XConvertSelection(winPtr->display, retr.selection, retr.target,
+ retr.property, retr.winPtr->window, time);
+
+ /*
+ * Enter a loop processing X events until the selection has been retrieved
+ * and processed. If no response is received within a few seconds, then
+ * timeout.
+ */
+
+ retr.timeout = Tcl_CreateTimerHandler(1000, TkDND_SelTimeoutProc,
+ &retr);
+ while (retr.result == -1) {
+ Tcl_DoOneEvent(0);
+ }
+ Tcl_DeleteTimerHandler(retr.timeout);
+
+ /*
+ * Unregister the information about the selection retrieval in progress.
+ */
+
+ if (pendingRetrievals == &retr) {
+ pendingRetrievals = retr.nextPtr;
+ } else {
+ TkSelRetrievalInfo *retrPtr;
+
+ for (retrPtr = pendingRetrievals; retrPtr != NULL;
+ retrPtr = retrPtr->nextPtr) {
+ if (retrPtr->nextPtr == &retr) {
+ retrPtr->nextPtr = retr.nextPtr;
+ break;
+ }
+ }
+ }
+ Tcl_DStringFree(&retr.buf);
+ return retr.result;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkDND_SelTimeoutProc --
+ *
+ * This function is invoked once every second while waiting for the
+ * selection to be returned. After a while it gives up and aborts the
+ * selection retrieval.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * A new timer callback is created to call us again in another second,
+ * unless time has expired, in which case an error is recorded for the
+ * retrieval.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+TkDND_SelTimeoutProc(
+ ClientData clientData) /* Information about retrieval in progress. */
+{
+ register TkSelRetrievalInfo *retrPtr = (TkSelRetrievalInfo *) clientData;
+
+ /*
+ * Make sure that the retrieval is still in progress. Then see how long
+ * it's been since any sort of response was received from the other side.
+ */
+
+ if (retrPtr->result != -1) {
+ return;
+ }
+ retrPtr->idleTime++;
+ if (retrPtr->idleTime >= 5) {
+ /*
+ * Use a careful function to store the error message, because the
+ * result could already be partially filled in with a partial
+ * selection return.
+ */
+
+ Tcl_SetResult(retrPtr->interp, "selection owner didn't respond",
+ TCL_STATIC);
+ retrPtr->result = TCL_ERROR;
+ } else {
+ retrPtr->timeout = Tcl_CreateTimerHandler(1000, TkDND_SelTimeoutProc,
+ (ClientData) retrPtr);
+ }
+}
+
+/*
+ * The structure below is used to keep each thread's pending list separate.
+ */
+
+typedef struct ThreadSpecificData {
+ TkSelInProgress *pendingPtr;
+ /* Topmost search in progress, or NULL if
+ * none. */
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+
+int
+TkSelDefaultSelection(
+ TkSelectionInfo *infoPtr, /* Info about selection being retrieved. */
+ Atom target, /* Desired form of selection. */
+ char *buffer, /* Place to put selection characters. */
+ int maxBytes, /* Maximum # of bytes to store at buffer. */
+ Atom *typePtr) /* Store here the type of the selection, for
+ * use in converting to proper X format. */
+{
+ register TkWindow *winPtr = (TkWindow *) infoPtr->owner;
+ TkDisplay *dispPtr = winPtr->dispPtr;
+
+ if (target == dispPtr->timestampAtom) {
+ if (maxBytes < 20) {
+ return -1;
+ }
+ sprintf(buffer, "0x%x", (unsigned int) infoPtr->time);
+ *typePtr = XA_INTEGER;
+ return strlen(buffer);
+ }
+
+ if (target == dispPtr->targetsAtom) {
+ register TkSelHandler *selPtr;
+ int length;
+ Tcl_DString ds;
+
+ if (maxBytes < 50) {
+ return -1;
+ }
+ Tcl_DStringInit(&ds);
+ Tcl_DStringAppend(&ds,
+ "MULTIPLE TARGETS TIMESTAMP TK_APPLICATION TK_WINDOW", -1);
+ for (selPtr = winPtr->selHandlerList; selPtr != NULL;
+ selPtr = selPtr->nextPtr) {
+ if ((selPtr->selection == infoPtr->selection)
+ && (selPtr->target != dispPtr->applicationAtom)
+ && (selPtr->target != dispPtr->windowAtom)) {
+ const char *atomString = Tk_GetAtomName((Tk_Window) winPtr,
+ selPtr->target);
+ Tcl_DStringAppendElement(&ds, atomString);
+ }
+ }
+ length = Tcl_DStringLength(&ds);
+ if (length >= maxBytes) {
+ Tcl_DStringFree(&ds);
+ return -1;
+ }
+ memcpy(buffer, Tcl_DStringValue(&ds), (unsigned) (1+length));
+ Tcl_DStringFree(&ds);
+ *typePtr = XA_ATOM;
+ return length;
+ }
+
+ if (target == dispPtr->applicationAtom) {
+ int length;
+ Tk_Uid name = winPtr->mainPtr->winPtr->nameUid;
+
+ length = strlen(name);
+ if (maxBytes <= length) {
+ return -1;
+ }
+ strcpy(buffer, name);
+ *typePtr = XA_STRING;
+ return length;
+ }
+
+ if (target == dispPtr->windowAtom) {
+ int length;
+ char *name = winPtr->pathName;
+
+ length = strlen(name);
+ if (maxBytes <= length) {
+ return -1;
+ }
+ strcpy(buffer, name);
+ *typePtr = XA_STRING;
+ return length;
+ }
+
+ return -1;
+}
+
+int TkDND_GetSelection(Tcl_Interp *interp, Tk_Window tkwin, Atom selection,
+ Atom target, Time time,
+ Tk_GetSelProc *proc, ClientData clientData) {
+ TkWindow *winPtr = (TkWindow *) tkwin;
+ TkDisplay *dispPtr = winPtr->dispPtr;
+ TkSelectionInfo *infoPtr;
+ ThreadSpecificData *tsdPtr =
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ if (dispPtr->multipleAtom == None) {
+ TkSelInit(tkwin);
+ }
+
+ /*
+ * If the selection is owned by a window managed by this process, then
+ * call the retrieval function directly, rather than going through the X
+ * server (it's dangerous to go through the X server in this case because
+ * it could result in deadlock if an INCR-style selection results).
+ */
+
+ for (infoPtr = dispPtr->selectionInfoPtr; infoPtr != NULL;
+ infoPtr = infoPtr->nextPtr) {
+ if (infoPtr->selection == selection) {
+ break;
+ }
+ }
+ if (infoPtr != NULL) {
+ register TkSelHandler *selPtr;
+ int offset, result, count;
+ char buffer[TK_SEL_BYTES_AT_ONCE+1];
+ TkSelInProgress ip;
+
+ for (selPtr = ((TkWindow *) infoPtr->owner)->selHandlerList;
+ selPtr != NULL; selPtr = selPtr->nextPtr) {
+ if (selPtr->target==target && selPtr->selection==selection) {
+ break;
+ }
+ }
+ if (selPtr == NULL) {
+ Atom type;
+
+ count = TkSelDefaultSelection(infoPtr, target, buffer,
+ TK_SEL_BYTES_AT_ONCE, &type);
+ if (count > TK_SEL_BYTES_AT_ONCE) {
+ Tcl_Panic("selection handler returned too many bytes");
+ }
+ if (count < 0) {
+ goto cantget;
+ }
+ buffer[count] = 0;
+ result = proc(clientData, interp, buffer);
+ } else {
+ offset = 0;
+ result = TCL_OK;
+ ip.selPtr = selPtr;
+ ip.nextPtr = tsdPtr->pendingPtr;
+ tsdPtr->pendingPtr = &ip;
+ while (1) {
+ count = selPtr->proc(selPtr->clientData, offset, buffer,
+ TK_SEL_BYTES_AT_ONCE);
+ if ((count < 0) || (ip.selPtr == NULL)) {
+ tsdPtr->pendingPtr = ip.nextPtr;
+ goto cantget;
+ }
+ if (count > TK_SEL_BYTES_AT_ONCE) {
+ Tcl_Panic("selection handler returned too many bytes");
+ }
+ buffer[count] = '\0';
+ result = proc(clientData, interp, buffer);
+ if ((result != TCL_OK) || (count < TK_SEL_BYTES_AT_ONCE)
+ || (ip.selPtr == NULL)) {
+ break;
+ }
+ offset += count;
+ }
+ tsdPtr->pendingPtr = ip.nextPtr;
+ }
+ return result;
+ }
+
+ /*
+ * The selection is owned by some other process.
+ */
+
+ return TkDNDSelGetSelection(interp, tkwin, selection, target, time,
+ proc, clientData);
+
+ cantget:
+ Tcl_AppendResult(interp, Tk_GetAtomName(tkwin, selection),
+ " selection doesn't exist or form \"",
+ Tk_GetAtomName(tkwin, target), "\" not defined", NULL);
+ return TCL_ERROR;
+}
+
+/*
+ * Local Variables:
+ * mode: c
+ * c-basic-offset: 4
+ * fill-column: 78
+ * End:
+ */