#include "IntrinsicI.h"
#include "StringDefs.h"
#include "SelectionI.h"
#include <X11/Xatom.h>
#include <stdio.h>
void _XtSetDefaultSelectionTimeout(timeout)
unsigned long *timeout;
{
*timeout = 5000;
}
void XtSetSelectionTimeout(timeout)
unsigned long timeout;
{
XtAppSetSelectionTimeout(_XtDefaultAppContext(), timeout);
}
void XtAppSetSelectionTimeout(app, timeout)
XtAppContext app;
unsigned long timeout;
{
LOCK_APP(app);
app->selectionTimeout = timeout;
UNLOCK_APP(app);
}
unsigned long XtGetSelectionTimeout()
{
return XtAppGetSelectionTimeout(_XtDefaultAppContext());
}
unsigned long XtAppGetSelectionTimeout(app)
XtAppContext app;
{
unsigned long retval;
LOCK_APP(app);
retval = app->selectionTimeout;
UNLOCK_APP(app);
return retval;
}
static void HandleSelectionReplies();
static void ReqTimedOut();
static void HandlePropertyGone();
static void HandleGetIncrement();
static void HandleIncremental();
static XContext selectPropertyContext = 0;
static XContext paramPropertyContext = 0;
static XContext multipleContext = 0;
static void AddSelectionRequests();
static Boolean IsGatheringRequest();
#define PREALLOCED 32
static void AddParamInfo();
static void RemoveParamInfo();
static Atom GetParamInfo();
static int StorageSize[3] = {1, sizeof(short), sizeof(long)};
#define BYTELENGTH(length, format) ((length) * StorageSize[(format)>>4])
#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4])
#ifdef XTTRACEMEMORY
#define XT_COPY_SELECTION 1
#endif
static void FreePropList(w, closure, callData)
Widget w;
XtPointer closure;
XtPointer callData;
{
PropList sarray = (PropList)closure;
LOCK_PROCESS;
XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy),
selectPropertyContext);
UNLOCK_PROCESS;
XtFree((char*)sarray->list);
XtFree((char*)closure);
}
static PropList GetPropList(dpy)
Display *dpy;
{
PropList sarray;
Atom atoms[4];
static char* names[] = {
"INCR",
"MULTIPLE",
"TIMESTAMP",
"_XT_SELECTION_0" };
LOCK_PROCESS;
if (selectPropertyContext == 0)
selectPropertyContext = XUniqueContext();
if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
(XPointer *)&sarray)) {
XtPerDisplay pd = _XtGetPerDisplay(dpy);
sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec));
sarray->dpy = dpy;
XInternAtoms(dpy, names, 4, FALSE, atoms);
sarray->incr_atom = atoms[0];
sarray->indirect_atom = atoms[1];
sarray->timestamp_atom = atoms[2];
sarray->propCount = 1;
sarray->list =
(SelectionProp)__XtMalloc((unsigned) sizeof(SelectionPropRec));
sarray->list[0].prop = atoms[3];
sarray->list[0].avail = TRUE;
(void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
(char *) sarray);
_XtAddCallback( &pd->destroy_callbacks,
FreePropList, (XtPointer)sarray );
}
UNLOCK_PROCESS;
return sarray;
}
static Atom GetSelectionProperty(dpy)
Display *dpy;
{
SelectionProp p;
int propCount;
char propname[80];
PropList sarray = GetPropList(dpy);
for (p = sarray->list, propCount=sarray->propCount;
propCount;
p++, propCount--) {
if (p->avail) {
p->avail = FALSE;
return(p->prop);
}
}
propCount = sarray->propCount++;
sarray->list = (SelectionProp) XtRealloc((XtPointer)sarray->list,
(unsigned)(sarray->propCount*sizeof(SelectionPropRec)));
(void) sprintf(propname, "%s%d", "_XT_SELECTION_", propCount);
sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE);
sarray->list[propCount].avail = FALSE;
return(sarray->list[propCount].prop);
}
static void FreeSelectionProperty(dpy, prop)
Display *dpy;
Atom prop;
{
SelectionProp p;
PropList sarray;
if (prop == None) return;
LOCK_PROCESS;
if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
(XPointer *)&sarray))
XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
"noSelectionProperties", "freeSelectionProperty", XtCXtToolkitError,
"internal error: no selection property context for display",
(String *)NULL, (Cardinal *)NULL );
UNLOCK_PROCESS;
for (p = sarray->list; p; p++)
if (p->prop == prop) {
p->avail = TRUE;
return;
}
}
static void FreeInfo(info)
CallBackInfo info;
{
XtFree((char*)info->incremental);
XtFree((char*)info->callbacks);
XtFree((char*)info->req_closure);
XtFree((char*)info->target);
XtFree((char*)info);
}
static CallBackInfo MakeInfo(ctx, callbacks, closures, count,
widget, time, incremental, properties)
Select ctx;
XtSelectionCallbackProc *callbacks;
XtPointer *closures;
int count;
Widget widget;
Time time;
Boolean *incremental;
Atom *properties;
{
CallBackInfo info = XtNew(CallBackInfoRec);
info->ctx = ctx;
info->callbacks = (XtSelectionCallbackProc *)
__XtMalloc((unsigned) (count * sizeof(XtSelectionCallbackProc)));
(void) memmove((char*)info->callbacks, (char*)callbacks,
count * sizeof(XtSelectionCallbackProc));
info->req_closure =
(XtPointer*)__XtMalloc((unsigned) (count * sizeof(XtPointer)));
(void) memmove((char*)info->req_closure, (char*)closures,
count * sizeof(XtPointer));
if (count == 1 && properties != NULL && properties[0] != None)
info->property = properties[0];
else {
info->property = GetSelectionProperty(XtDisplay(widget));
XDeleteProperty(XtDisplay(widget), XtWindow(widget),
info->property);
}
info->proc = HandleSelectionReplies;
info->widget = widget;
info->time = time;
info->incremental = (Boolean*) __XtMalloc(count * sizeof(Boolean));
(void) memmove((char*)info->incremental, (char*) incremental,
count * sizeof(Boolean));
info->current = 0;
info->value = NULL;
return (info);
}
static void RequestSelectionValue(info, selection, target)
CallBackInfo info;
Atom selection;
Atom target;
{
#ifndef DEBUG_WO_TIMERS
XtAppContext app = XtWidgetToApplicationContext(info->widget);
info->timeout = XtAppAddTimeOut(app,
app->selectionTimeout, ReqTimedOut, (XtPointer)info);
#endif
XtAddEventHandler(info->widget, (EventMask)0, TRUE,
HandleSelectionReplies, (XtPointer)info);
XConvertSelection(info->ctx->dpy, selection, target,
info->property, XtWindow(info->widget), info->time);
}
static XContext selectContext = 0;
static Select NewContext(dpy, selection)
Display *dpy;
Atom selection;
{
Select ctx = XtNew(SelectRec);
ctx->dpy = dpy;
ctx->selection = selection;
ctx->widget = NULL;
ctx->prop_list = GetPropList(dpy);
ctx->ref_count = 0;
ctx->free_when_done = FALSE;
ctx->was_disowned = FALSE;
LOCK_PROCESS;
(void)XSaveContext(dpy, (Window)selection, selectContext, (char *)ctx);
UNLOCK_PROCESS;
return ctx;
}
static Select FindCtx(dpy, selection)
Display *dpy;
Atom selection;
{
Select ctx;
LOCK_PROCESS;
if (selectContext == 0)
selectContext = XUniqueContext();
if (XFindContext(dpy, (Window)selection, selectContext, (XPointer *)&ctx))
ctx = NewContext(dpy, selection);
UNLOCK_PROCESS;
return ctx;
}
static void WidgetDestroyed(widget, closure, data)
Widget widget;
XtPointer closure, data;
{
Select ctx = (Select) closure;
if (ctx->widget == widget) {
if (ctx->free_when_done)
XtFree((char*)ctx);
else
ctx->widget = NULL;
}
}
static void HandleSelectionEvents();
static Boolean LoseSelection(ctx, widget, selection, time)
Select ctx;
Widget widget;
Atom selection;
Time time;
{
if ((ctx->widget == widget) &&
(ctx->selection == selection) &&
!ctx->was_disowned &&
((time == CurrentTime) || (time >= ctx->time)))
{
XtRemoveEventHandler(widget, (EventMask)0, TRUE,
HandleSelectionEvents, (XtPointer)ctx);
XtRemoveCallback(widget, XtNdestroyCallback,
WidgetDestroyed, (XtPointer)ctx);
ctx->was_disowned = TRUE;
if (ctx->loses) {
if (ctx->incremental)
(*(XtLoseSelectionIncrProc)ctx->loses)
(widget, &ctx->selection, ctx->owner_closure);
else (*ctx->loses)(widget, &ctx->selection);
}
return(TRUE);
}
else return(FALSE);
}
static XContext selectWindowContext = 0;
typedef int (*xErrorHandler)(Display*, XErrorEvent*);
static xErrorHandler oldErrorHandler = NULL;
static unsigned long firstProtectRequest;
static Window errorWindow;
static int LocalErrorHandler (dpy, error)
Display *dpy;
XErrorEvent *error;
{
int retval;
LOCK_PROCESS;
if (error->error_code == BadWindow && error->resourceid == errorWindow &&
error->serial >= firstProtectRequest) {
UNLOCK_PROCESS;
return 0;
}
if (oldErrorHandler == NULL) {
UNLOCK_PROCESS;
return 0;
}
retval = (*oldErrorHandler)(dpy, error);
UNLOCK_PROCESS;
return retval;
}
static void StartProtectedSection(dpy, window)
Display *dpy;
Window window;
{
LOCK_PROCESS;
oldErrorHandler = XSetErrorHandler(LocalErrorHandler);
firstProtectRequest = NextRequest(dpy);
errorWindow = window;
UNLOCK_PROCESS;
}
static void EndProtectedSection(dpy)
Display *dpy;
{
XSync(dpy, False);
LOCK_PROCESS;
XSetErrorHandler(oldErrorHandler);
oldErrorHandler = NULL;
UNLOCK_PROCESS;
}
static void AddHandler(req, mask, proc, closure)
Request req;
EventMask mask;
XtEventHandler proc;
XtPointer closure;
{
Display *dpy = req->ctx->dpy;
Window window = req->requestor;
Widget widget = XtWindowToWidget(dpy, window);
if (widget != NULL) req->widget = widget;
else widget = req->widget;
if (XtWindow(widget) == window)
XtAddEventHandler(widget, mask, False, proc, closure);
else {
RequestWindowRec *requestWindowRec;
LOCK_PROCESS;
if (selectWindowContext == 0)
selectWindowContext = XUniqueContext();
if (XFindContext(dpy, window, selectWindowContext,
(XPointer *)&requestWindowRec)) {
requestWindowRec = XtNew(RequestWindowRec);
requestWindowRec->active_transfer_count = 0;
(void)XSaveContext(dpy, window, selectWindowContext,
(char *)requestWindowRec);
}
UNLOCK_PROCESS;
if (requestWindowRec->active_transfer_count++ == 0) {
XtRegisterDrawable(dpy, window, widget);
XSelectInput(dpy, window, mask);
}
XtAddRawEventHandler(widget, mask, FALSE, proc, closure);
}
}
static void RemoveHandler(req, mask, proc, closure)
Request req;
EventMask mask;
XtEventHandler proc;
XtPointer closure;
{
Display *dpy = req->ctx->dpy;
Window window = req->requestor;
Widget widget = req->widget;
if ((XtWindowToWidget(dpy, window) == widget) &&
(XtWindow(widget) != window)) {
RequestWindowRec* requestWindowRec;
XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure);
LOCK_PROCESS;
(void)XFindContext(dpy, window, selectWindowContext,
(XPointer *)&requestWindowRec);
UNLOCK_PROCESS;
if (--requestWindowRec->active_transfer_count == 0) {
XtUnregisterDrawable(dpy, window);
StartProtectedSection(dpy, window);
XSelectInput(dpy, window, 0L);
EndProtectedSection(dpy);
LOCK_PROCESS;
(void)XDeleteContext(dpy, window, selectWindowContext);
UNLOCK_PROCESS;
XtFree((char*)requestWindowRec);
}
} else {
XtRemoveEventHandler(widget, mask, TRUE, proc, closure);
}
}
static void OwnerTimedOut(closure, id)
XtPointer closure;
XtIntervalId *id;
{
Request req = (Request)closure;
Select ctx = req->ctx;
if (ctx->incremental && (ctx->owner_cancel != NULL)) {
(*ctx->owner_cancel)(ctx->widget, &ctx->selection,
&req->target, (XtRequestId*)&req,
ctx->owner_closure);
} else {
if (ctx->notify == NULL)
XtFree((char*)req->value);
else {
if (ctx->incremental)
(*(XtSelectionDoneIncrProc)ctx->notify)
(ctx->widget, &ctx->selection, &req->target,
(XtRequestId*)&req, ctx->owner_closure);
else
(*ctx->notify)(ctx->widget, &ctx->selection, &req->target);
}
}
RemoveHandler(req, (EventMask)PropertyChangeMask,
HandlePropertyGone, closure);
XtFree((char*)req);
if (--ctx->ref_count == 0 && ctx->free_when_done)
XtFree((char*)ctx);
}
static void SendIncrement(incr)
Request incr;
{
Display *dpy = incr->ctx->dpy;
int incrSize = MAX_SELECTION_INCR(dpy);
if (incrSize > incr->bytelength - incr->offset)
incrSize = incr->bytelength - incr->offset;
StartProtectedSection(dpy, incr->requestor);
XChangeProperty(dpy, incr->requestor, incr->property,
incr->type, incr->format, PropModeReplace,
(unsigned char *)incr->value + incr->offset,
NUMELEM(incrSize, incr->format));
EndProtectedSection(dpy);
incr->offset += incrSize;
}
static void AllSent(req)
Request req;
{
Select ctx = req->ctx;
StartProtectedSection(ctx->dpy, req->requestor);
XChangeProperty(ctx->dpy, req->requestor,
req->property, req->type, req->format,
PropModeReplace, (unsigned char *) NULL, 0);
EndProtectedSection(ctx->dpy);
req->allSent = TRUE;
if (ctx->notify == NULL) XtFree((char*)req->value);
}
static void HandlePropertyGone(widget, closure, ev, cont)
Widget widget;
XtPointer closure;
XEvent *ev;
Boolean *cont;
{
XPropertyEvent *event = (XPropertyEvent *) ev;
Request req = (Request)closure;
Select ctx = req->ctx;
if ((event->type != PropertyNotify) ||
(event->state != PropertyDelete) ||
(event->atom != req->property) ||
(event->window != req->requestor))
return;
#ifndef DEBUG_WO_TIMERS
XtRemoveTimeOut(req->timeout);
#endif
if (req->allSent) {
if (ctx->notify) {
if (ctx->incremental) {
(*(XtSelectionDoneIncrProc)ctx->notify)
(ctx->widget, &ctx->selection, &req->target,
(XtRequestId*)&req, ctx->owner_closure);
}
else (*ctx->notify)(ctx->widget, &ctx->selection, &req->target);
}
RemoveHandler(req, (EventMask)PropertyChangeMask,
HandlePropertyGone, closure);
XtFree((char*)req);
if (--ctx->ref_count == 0 && ctx->free_when_done)
XtFree((char*)ctx);
} else {
if (ctx->incremental) {
if (req->bytelength == 0)
AllSent(req);
else {
unsigned long size = MAX_SELECTION_INCR(ctx->dpy);
SendIncrement(req);
(*(XtConvertSelectionIncrProc)ctx->convert)
(ctx->widget, &ctx->selection, &req->target,
&req->type, &req->value,
&req->bytelength, &req->format,
&size, ctx->owner_closure, (XtPointer*)&req);
if (req->bytelength)
req->bytelength = BYTELENGTH(req->bytelength, req->format);
req->offset = 0;
}
} else {
if (req->offset < req->bytelength)
SendIncrement(req);
else AllSent(req);
}
#ifndef DEBUG_WO_TIMERS
{
XtAppContext app = XtWidgetToApplicationContext(req->widget);
req->timeout = XtAppAddTimeOut(app,
app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
}
#endif
}
}
static void PrepareIncremental(req, widget, window, property, target,
targetType, value, length, format)
Request req;
Widget widget;
Window window;
Atom target;
Atom property;
Atom targetType;
XtPointer value;
unsigned long length;
int format;
{
req->type = targetType;
req->value = value;
req->bytelength = BYTELENGTH(length,format);
req->format = format;
req->offset = 0;
req->target = target;
req->widget = widget;
req->allSent = FALSE;
#ifndef DEBUG_WO_TIMERS
{
XtAppContext app = XtWidgetToApplicationContext(widget);
req->timeout = XtAppAddTimeOut(app,
app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
}
#endif
AddHandler(req, (EventMask)PropertyChangeMask,
HandlePropertyGone, (XtPointer)req);
XChangeProperty(req->ctx->dpy, window, req->property,
req->ctx->prop_list->incr_atom,
32, PropModeReplace,
(unsigned char *)&req->bytelength, 1);
}
static Boolean GetConversion(ctx, event, target, property, widget)
Select ctx;
XSelectionRequestEvent* event;
Atom target;
Atom property;
Widget widget;
{
XtPointer value = NULL;
unsigned long length;
int format;
Atom targetType;
Request req = XtNew(RequestRec);
Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom);
req->ctx = ctx;
req->event = *event;
req->property = property;
req->requestor = event->requestor;
if (timestamp_target) {
value = __XtMalloc(sizeof(long));
*(long*)value = ctx->time;
targetType = XA_INTEGER;
length = 1;
format = 32;
}
else {
ctx->ref_count++;
if (ctx->incremental == TRUE) {
unsigned long size = MAX_SELECTION_INCR(ctx->dpy);
if ((*(XtConvertSelectionIncrProc)ctx->convert)
(ctx->widget, &event->selection, &target,
&targetType, &value, &length, &format,
&size, ctx->owner_closure, (XtRequestId*)&req)
== FALSE) {
XtFree((char*)req);
ctx->ref_count--;
return(FALSE);
}
StartProtectedSection(ctx->dpy, event->requestor);
PrepareIncremental(req, widget, event->requestor, property,
target, targetType, value, length, format);
return(TRUE);
}
ctx->req = req;
if ((*ctx->convert)(ctx->widget, &event->selection, &target,
&targetType, &value, &length, &format) == FALSE) {
XtFree((char*)req);
ctx->req = NULL;
ctx->ref_count--;
return(FALSE);
}
ctx->req = NULL;
}
StartProtectedSection(ctx->dpy, event->requestor);
if (BYTELENGTH(length,format) <= MAX_SELECTION_INCR(ctx->dpy)) {
if (! timestamp_target) {
if (ctx->notify != NULL) {
req->target = target;
req->widget = widget;
req->allSent = TRUE;
#ifndef DEBUG_WO_TIMERS
{
XtAppContext app = XtWidgetToApplicationContext(req->widget);
req->timeout = XtAppAddTimeOut(app,
app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
}
#endif
AddHandler(req, (EventMask)PropertyChangeMask,
HandlePropertyGone, (XtPointer)req);
}
else ctx->ref_count--;
}
XChangeProperty(ctx->dpy, event->requestor, property,
targetType, format, PropModeReplace,
(unsigned char *)value, (int)length);
if (timestamp_target || ctx->notify == NULL) {
XtFree((char*)value);
XtFree((char*)req);
}
} else {
PrepareIncremental(req, widget, event->requestor, property,
target, targetType, value, length, format);
}
return(TRUE);
}
static void HandleSelectionEvents(widget, closure, event, cont)
Widget widget;
XtPointer closure;
XEvent *event;
Boolean *cont;
{
Select ctx;
XSelectionEvent ev;
Atom target;
int count;
Boolean writeback = FALSE;
ctx = (Select) closure;
switch (event->type) {
case SelectionClear:
if (ctx->selection != event->xselectionclear.selection ||
ctx->serial > event->xselectionclear.serial)
break;
(void) LoseSelection(ctx, widget, event->xselectionclear.selection,
event->xselectionclear.time);
break;
case SelectionRequest:
if (ctx->selection != event->xselectionrequest.selection)
break;
ev.type = SelectionNotify;
ev.display = event->xselectionrequest.display;
ev.requestor = event->xselectionrequest.requestor;
ev.selection = event->xselectionrequest.selection;
ev.time = event->xselectionrequest.time;
ev.target = event->xselectionrequest.target;
if (event->xselectionrequest.property == None)
event->xselectionrequest.property = event->xselectionrequest.target;
if (ctx->widget != widget || ctx->was_disowned
|| ((event->xselectionrequest.time != CurrentTime)
&& (event->xselectionrequest.time < ctx->time)))
ev.property = None;
else {
if (ev.target == ctx->prop_list->indirect_atom) {
IndirectPair *p;
int format;
unsigned long bytesafter, length;
unsigned char *value;
ev.property = event->xselectionrequest.property;
StartProtectedSection(ev.display, ev.requestor);
(void) XGetWindowProperty(ev.display, ev.requestor,
event->xselectionrequest.property, 0L, 1000000,
False,(Atom)AnyPropertyType, &target, &format, &length,
&bytesafter, &value);
count = BYTELENGTH(length, format) / sizeof(IndirectPair);
for (p = (IndirectPair *)value; count; p++, count--) {
EndProtectedSection(ctx->dpy);
if (!GetConversion(ctx, (XSelectionRequestEvent*)event,
p->target, p->property, widget)) {
p->target = None;
writeback = TRUE;
StartProtectedSection(ctx->dpy, ev.requestor);
}
}
if (writeback)
XChangeProperty(ev.display, ev.requestor,
event->xselectionrequest.property, target,
format, PropModeReplace, value, (int)length);
XFree((char *)value);
} else {
if (GetConversion(ctx, (XSelectionRequestEvent*)event,
event->xselectionrequest.target,
event->xselectionrequest.property,
widget))
ev.property = event->xselectionrequest.property;
else {
ev.property = None;
StartProtectedSection(ctx->dpy, ev.requestor);
}
}
}
(void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long)NULL,
(XEvent *) &ev);
EndProtectedSection(ctx->dpy);
break;
}
}
static Boolean OwnSelection(widget, selection, time, convert, lose, notify,
cancel, closure, incremental)
Widget widget;
Atom selection;
Time time;
XtConvertSelectionProc convert;
XtLoseSelectionProc lose;
XtSelectionDoneProc notify;
XtCancelConvertSelectionProc cancel;
XtPointer closure;
Boolean incremental;
{
Select ctx;
Select oldctx = NULL;
if (!XtIsRealized(widget)) return False;
ctx = FindCtx(XtDisplay(widget), selection);
if (ctx->widget != widget || ctx->time != time ||
ctx->ref_count || ctx->was_disowned)
{
Boolean replacement = FALSE;
Window window = XtWindow(widget);
unsigned long serial = XNextRequest(ctx->dpy);
XSetSelectionOwner(ctx->dpy, selection, window, time);
if (XGetSelectionOwner(ctx->dpy, selection) != window)
return FALSE;
if (ctx->ref_count) {
#ifdef DEBUG_ACTIVE
printf( "Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n",
XtName(widget), (long)selection, ctx->ref_count );
#endif
if (ctx->widget != widget ||
ctx->convert != convert ||
ctx->loses != lose ||
ctx->notify != notify ||
ctx->owner_cancel != cancel ||
ctx->incremental != incremental ||
ctx->owner_closure != closure)
{
if (ctx->widget == widget) {
XtRemoveEventHandler(widget, (EventMask)0, TRUE,
HandleSelectionEvents, (XtPointer)ctx);
XtRemoveCallback(widget, XtNdestroyCallback,
WidgetDestroyed, (XtPointer)ctx);
replacement = TRUE;
}
else if (!ctx->was_disowned) {
oldctx = ctx;
}
ctx->free_when_done = TRUE;
ctx = NewContext(XtDisplay(widget), selection);
}
else if (!ctx->was_disowned) {
ctx->time = time;
return TRUE;
}
}
if (ctx->widget != widget || ctx->was_disowned || replacement) {
if (ctx->widget && !ctx->was_disowned && !replacement) {
oldctx = ctx;
oldctx->free_when_done = TRUE;
ctx = NewContext(XtDisplay(widget), selection);
}
XtAddEventHandler(widget, (EventMask)0, TRUE,
HandleSelectionEvents, (XtPointer)ctx);
XtAddCallback(widget, XtNdestroyCallback,
WidgetDestroyed, (XtPointer)ctx);
}
ctx->widget = widget;
ctx->time = time;
ctx->serial = serial;
}
ctx->convert = convert;
ctx->loses = lose;
ctx->notify = notify;
ctx->owner_cancel = cancel;
ctx->incremental = incremental;
ctx->owner_closure = closure;
ctx->was_disowned = FALSE;
if (oldctx) {
(void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time);
if (!oldctx->ref_count && oldctx->free_when_done)
XtFree((char*)oldctx);
}
return TRUE;
}
Boolean XtOwnSelection(widget, selection, time, convert, lose, notify)
Widget widget;
Atom selection;
Time time;
XtConvertSelectionProc convert;
XtLoseSelectionProc lose;
XtSelectionDoneProc notify;
{
Boolean retval;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
retval = OwnSelection(widget, selection, time, convert, lose, notify,
(XtCancelConvertSelectionProc)NULL,
(XtPointer)NULL, FALSE);
UNLOCK_APP(app);
return retval;
}
Boolean XtOwnSelectionIncremental(widget, selection, time, convert,
lose, notify, cancel, closure)
Widget widget;
Atom selection;
Time time;
XtConvertSelectionIncrProc convert;
XtLoseSelectionIncrProc lose;
XtSelectionDoneIncrProc notify;
XtCancelConvertSelectionProc cancel;
XtPointer closure;
{
Boolean retval;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
retval = OwnSelection(widget, selection, time,
(XtConvertSelectionProc)convert,
(XtLoseSelectionProc)lose,
(XtSelectionDoneProc)notify,
cancel, closure, TRUE);
UNLOCK_APP(app);
return retval;
}
void XtDisownSelection(widget, selection, time)
Widget widget;
Atom selection;
Time time;
{
Select ctx;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
ctx = FindCtx(XtDisplay(widget), selection);
if (LoseSelection(ctx, widget, selection, time))
XSetSelectionOwner(XtDisplay(widget), selection, None, time);
UNLOCK_APP(app);
}
static Boolean IsINCRtype(info, window, prop)
CallBackInfo info;
Window window;
Atom prop;
{
unsigned long bytesafter;
unsigned long length;
int format;
Atom type;
unsigned char *value;
if (prop == None) return False;
(void)XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L,
False, info->ctx->prop_list->incr_atom,
&type, &format, &length, &bytesafter, &value);
return (type == info->ctx->prop_list->incr_atom);
}
static void ReqCleanup(widget, closure, ev, cont)
Widget widget;
XtPointer closure;
XEvent *ev;
Boolean *cont;
{
CallBackInfo info = (CallBackInfo)closure;
unsigned long bytesafter, length;
char *value;
int format;
Atom target;
if (ev->type == SelectionNotify) {
XSelectionEvent *event = (XSelectionEvent *) ev;
if (!MATCH_SELECT(event, info)) return;
XtRemoveEventHandler(widget, (EventMask)0, TRUE,
ReqCleanup, (XtPointer) info );
if (IsINCRtype(info, XtWindow(widget), event->property)) {
info->proc = HandleGetIncrement;
XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
FALSE, ReqCleanup, (XtPointer) info);
} else {
if (event->property != None)
XDeleteProperty(event->display, XtWindow(widget),
event->property);
FreeSelectionProperty(XtDisplay(widget), info->property);
FreeInfo(info);
}
} else if ((ev->type == PropertyNotify) &&
(ev->xproperty.state == PropertyNewValue) &&
(ev->xproperty.atom == info->property)) {
XPropertyEvent *event = (XPropertyEvent *) ev;
(void) XGetWindowProperty(event->display, XtWindow(widget),
event->atom, 0L, 1000000, True, AnyPropertyType,
&target, &format, &length, &bytesafter,
(unsigned char **) &value);
XFree(value);
if (length == 0) {
XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
ReqCleanup, (XtPointer) info );
FreeSelectionProperty(XtDisplay(widget), info->property);
XtFree(info->value);
FreeInfo(info);
}
}
}
static void ReqTimedOut(closure, id)
XtPointer closure;
XtIntervalId *id;
{
XtPointer value = NULL;
unsigned long length = 0;
int format = 8;
Atom resulttype = XT_CONVERT_FAIL;
CallBackInfo info = (CallBackInfo)closure;
unsigned long bytesafter;
unsigned long proplength;
Atom type;
IndirectPair *pairs;
XtPointer *c;
int i;
if (*info->target == info->ctx->prop_list->indirect_atom) {
(void) XGetWindowProperty(XtDisplay(info->widget),
XtWindow(info->widget), info->property, 0L,
10000000, True, AnyPropertyType, &type, &format,
&proplength, &bytesafter, (unsigned char **) &pairs);
XFree((char*)pairs);
for (proplength = proplength / IndirectPairWordSize, i = 0, c = info->req_closure;
proplength; proplength--, c++, i++)
(*info->callbacks[i])(info->widget, *c,
&info->ctx->selection, &resulttype, value, &length, &format);
} else {
(*info->callbacks[0])(info->widget, *info->req_closure,
&info->ctx->selection, &resulttype, value, &length, &format);
}
if (info->proc == (XtEventHandler)HandleSelectionReplies) {
XtRemoveEventHandler(info->widget, (EventMask)0,
TRUE, info->proc, (XtPointer) info);
XtAddEventHandler(info->widget, (EventMask)0, TRUE,
ReqCleanup, (XtPointer) info);
} else {
XtRemoveEventHandler(info->widget,(EventMask) PropertyChangeMask,
FALSE, info->proc, (XtPointer) info);
XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
FALSE, ReqCleanup, (XtPointer) info);
}
}
static void HandleGetIncrement(widget, closure, ev, cont)
Widget widget;
XtPointer closure;
XEvent *ev;
Boolean *cont;
{
XPropertyEvent *event = (XPropertyEvent *) ev;
CallBackInfo info = (CallBackInfo) closure;
Select ctx = info->ctx;
char *value;
unsigned long bytesafter;
unsigned long length;
int bad;
int n = info->current;
if ((event->state != PropertyNewValue) || (event->atom != info->property))
return;
bad = XGetWindowProperty(event->display, XtWindow(widget),
event->atom, 0L,
10000000, True, AnyPropertyType, &info->type,
&info->format, &length, &bytesafter,
(unsigned char **) &value);
if (bad)
return;
#ifndef DEBUG_WO_TIMERS
XtRemoveTimeOut(info->timeout);
#endif
if (length == 0) {
unsigned long u_offset = NUMELEM(info->offset, info->format);
(*info->callbacks[n])(widget, *info->req_closure, &ctx->selection,
&info->type,
(info->offset == 0 ? value : info->value),
&u_offset, &info->format);
if (info->offset != 0) XFree(value);
XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
HandleGetIncrement, (XtPointer) info);
FreeSelectionProperty(event->display, info->property);
FreeInfo(info);
} else {
if (info->incremental[n]) {
#ifdef XT_COPY_SELECTION
int size = BYTELENGTH(length, info->format) + 1;
char *tmp = __XtMalloc((Cardinal) size);
(void) memmove(tmp, value, size);
XFree(value);
value = tmp;
#endif
(*info->callbacks[n])(widget, *info->req_closure, &ctx->selection,
&info->type, value, &length, &info->format);
} else {
int size = BYTELENGTH(length, info->format);
if (info->offset + size > info->bytelength) {
info->bytelength = info->offset + size * 2;
info->value = XtRealloc(info->value,
(Cardinal) info->bytelength);
}
(void) memmove(&info->value[info->offset], value, size);
info->offset += size;
XFree(value);
}
#ifndef DEBUG_WO_TIMERS
{
XtAppContext app = XtWidgetToApplicationContext(info->widget);
info->timeout = XtAppAddTimeOut(app,
app->selectionTimeout, ReqTimedOut, (XtPointer) info);
}
#endif
}
}
static void HandleNone(widget, callback, closure, selection)
Widget widget;
XtSelectionCallbackProc callback;
XtPointer closure;
Atom selection;
{
unsigned long length = 0;
int format = 8;
Atom type = None;
(*callback)(widget, closure, &selection,
&type, NULL, &length, &format);
}
static long IncrPropSize(widget, value, format, length)
Widget widget;
unsigned char* value;
int format;
unsigned long length;
{
unsigned long size;
if (format == 32) {
size = ((long*)value)[length-1];
return size;
}
else {
XtAppWarningMsg( XtWidgetToApplicationContext(widget),
"badFormat","xtGetSelectionValue",XtCXtToolkitError,
"Selection owner returned type INCR property with format != 32",
(String*)NULL, (Cardinal*)NULL );
return 0;
}
}
static
Boolean HandleNormal(dpy, widget, property, info, closure, selection)
Display *dpy;
Widget widget;
Atom property;
CallBackInfo info;
XtPointer closure;
Atom selection;
{
unsigned long bytesafter;
unsigned long length;
int format;
Atom type;
unsigned char *value;
int number = info->current;
(void) XGetWindowProperty(dpy, XtWindow(widget), property, 0L,
10000000, False, AnyPropertyType,
&type, &format, &length, &bytesafter, &value);
if (type == info->ctx->prop_list->incr_atom) {
unsigned long size = IncrPropSize(widget, value, format, length);
XFree((char *)value);
if (info->property != property) {
CallBackInfo ninfo;
ninfo = MakeInfo(info->ctx, &info->callbacks[number],
&info->req_closure[number], 1, widget,
info->time, &info->incremental[number], &property);
ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom));
*ninfo->target = info->target[number + 1];
info = ninfo;
}
HandleIncremental(dpy, widget, property, info, size);
return FALSE;
}
XDeleteProperty(dpy, XtWindow(widget), property);
#ifdef XT_COPY_SELECTION
if (value) {
int size = BYTELENGTH(length, info->format) + 1;
char *tmp = __XtMalloc((Cardinal) size);
(void) memmove(tmp, value, size);
XFree(value);
value = (unsigned char *) tmp;
}
#endif
(*info->callbacks[number])(widget, closure, &selection,
&type, (XtPointer)value, &length, &format);
if (info->incremental[number]) {
value = (unsigned char*)__XtMalloc((unsigned)1);
length = 0;
(*info->callbacks[number])(widget, closure, &selection,
&type, (XtPointer)value, &length, &format);
}
return TRUE;
}
static void HandleIncremental(dpy, widget, property, info, size)
Display *dpy;
Widget widget;
Atom property;
CallBackInfo info;
unsigned long size;
{
XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
HandleGetIncrement, (XtPointer) info);
XDeleteProperty(dpy, XtWindow(widget), property);
XFlush(dpy);
info->bytelength = size;
if (info->incremental[info->current])
info->value = NULL;
else
info->value = (char *) __XtMalloc((unsigned) info->bytelength);
info->offset = 0;
info->proc = HandleGetIncrement;
#ifndef DEBUG_WO_TIMERS
{
XtAppContext app = XtWidgetToApplicationContext(info->widget);
info->timeout = XtAppAddTimeOut(app,
app->selectionTimeout, ReqTimedOut, (XtPointer) info);
}
#endif
}
static void HandleSelectionReplies(widget, closure, ev, cont)
Widget widget;
XtPointer closure;
XEvent *ev;
Boolean *cont;
{
XSelectionEvent *event = (XSelectionEvent *) ev;
Display *dpy = event->display;
CallBackInfo info = (CallBackInfo) closure;
Select ctx = info->ctx;
IndirectPair *pairs, *p;
unsigned long bytesafter;
unsigned long length;
int format;
Atom type;
XtPointer *c;
if (event->type != SelectionNotify) return;
if (!MATCH_SELECT(event, info)) return;
#ifndef DEBUG_WO_TIMERS
XtRemoveTimeOut(info->timeout);
#endif
XtRemoveEventHandler(widget, (EventMask)0, TRUE,
HandleSelectionReplies, (XtPointer) info );
if (event->target == ctx->prop_list->indirect_atom) {
(void) XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L,
10000000, True, AnyPropertyType, &type, &format,
&length, &bytesafter, (unsigned char **) &pairs);
for (length = length / IndirectPairWordSize, p = pairs,
c = info->req_closure;
length; length--, p++, c++, info->current++) {
if (event->property == None || format != 32 || p->target == None
|| p->property == None) {
HandleNone(widget, info->callbacks[info->current],
*c, event->selection);
if (p->property != None)
FreeSelectionProperty(XtDisplay(widget), p->property);
} else {
if (HandleNormal(dpy, widget, p->property, info, *c,
event->selection)) {
FreeSelectionProperty(XtDisplay(widget), p->property);
}
}
}
XFree((char*)pairs);
FreeSelectionProperty(dpy, info->property);
FreeInfo(info);
} else if (event->property == None) {
HandleNone(widget, info->callbacks[0], *info->req_closure, event->selection);
FreeSelectionProperty(XtDisplay(widget), info->property);
FreeInfo(info);
} else {
if (HandleNormal(dpy, widget, event->property, info,
*info->req_closure, event->selection)) {
FreeSelectionProperty(XtDisplay(widget), info->property);
FreeInfo(info);
}
}
}
static void DoLocalTransfer(req, selection, target, widget,
callback, closure, incremental, property)
Request req;
Atom selection;
Atom target;
Widget widget;
XtSelectionCallbackProc callback;
XtPointer closure;
Boolean incremental;
Atom property;
{
Select ctx = req->ctx;
XtPointer value = NULL, temp, total = NULL;
unsigned long length;
int format;
Atom resulttype;
unsigned long totallength = 0;
req->event.type = 0;
req->event.target = target;
req->event.property = req->property = property;
req->event.requestor = req->requestor = XtWindow(widget);
if (ctx->incremental) {
unsigned long size = MAX_SELECTION_INCR(ctx->dpy);
if (!(*(XtConvertSelectionIncrProc)ctx->convert)
(ctx->widget, &selection, &target,
&resulttype, &value, &length, &format,
&size, ctx->owner_closure, (XtRequestId*)&req)) {
HandleNone(widget, callback, closure, selection);
}
else {
if (incremental) {
Boolean allSent = FALSE;
while (!allSent) {
if (ctx->notify && (value != NULL)) {
int bytelength = BYTELENGTH(length,format);
temp = __XtMalloc((unsigned)bytelength);
(void) memmove(temp, value, bytelength);
value = temp;
}
if (value == NULL) value = __XtMalloc((unsigned)1);
(*callback)(widget, closure, &selection,
&resulttype, value, &length, &format);
if (length) {
(*(XtConvertSelectionIncrProc)ctx->convert)
(ctx->widget, &selection, &target,
&resulttype, &value, &length, &format,
&size, ctx->owner_closure,
(XtRequestId*)&req);
}
else allSent = TRUE;
}
} else {
while (length) {
int bytelength = BYTELENGTH(length, format);
total = XtRealloc(total,
(unsigned) (totallength += bytelength));
(void) memmove((char*)total + totallength - bytelength,
value,
bytelength);
(*(XtConvertSelectionIncrProc)ctx->convert)
(ctx->widget, &selection, &target,
&resulttype, &value, &length, &format,
&size, ctx->owner_closure, (XtRequestId*)&req);
}
if (total == NULL) total = __XtMalloc(1);
totallength = NUMELEM(totallength, format);
(*callback)(widget, closure, &selection, &resulttype,
total, &totallength, &format);
}
if (ctx->notify)
(*(XtSelectionDoneIncrProc)ctx->notify)
(ctx->widget, &selection, &target,
(XtRequestId*)&req, ctx->owner_closure);
else XtFree((char*)value);
}
} else {
if (!(*ctx->convert)(ctx->widget, &selection, &target,
&resulttype, &value, &length, &format)) {
HandleNone(widget, callback, closure, selection);
} else {
if (ctx->notify && (value != NULL)) {
int bytelength = BYTELENGTH(length,format);
temp = __XtMalloc((unsigned)bytelength);
(void) memmove(temp, value, bytelength);
value = temp;
}
if (value == NULL) value = __XtMalloc((unsigned)1);
(*callback)(widget, closure, &selection, &resulttype,
value, &length, &format);
if (ctx->notify)
(*ctx->notify)(ctx->widget, &selection, &target);
}
}
}
static void GetSelectionValue(widget, selection, target, callback,
closure, time, incremental, property)
Widget widget;
Atom selection;
Atom target;
XtSelectionCallbackProc callback;
XtPointer closure;
Time time;
Boolean incremental;
Atom property;
{
Select ctx;
CallBackInfo info;
Atom properties[1];
properties[0] = property;
ctx = FindCtx(XtDisplay(widget), selection);
if (ctx->widget && !ctx->was_disowned) {
RequestRec req;
ctx->req = &req;
req.ctx = ctx;
req.event.time = time;
ctx->ref_count++;
DoLocalTransfer(&req, selection, target, widget,
callback, closure, incremental, property);
if (--ctx->ref_count == 0 && ctx->free_when_done)
XtFree((char*)ctx);
else
ctx->req = NULL;
}
else {
info = MakeInfo(ctx, &callback, &closure, 1, widget,
time, &incremental, properties);
info->target = (Atom *)__XtMalloc((unsigned) sizeof(Atom));
*(info->target) = target;
RequestSelectionValue(info, selection, target);
}
}
void XtGetSelectionValue(widget, selection, target, callback, closure, time)
Widget widget;
Atom selection;
Atom target;
XtSelectionCallbackProc callback;
XtPointer closure;
Time time;
{
Atom property;
Boolean incr = False;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
property = GetParamInfo(widget, selection);
RemoveParamInfo(widget, selection);
if (IsGatheringRequest(widget, selection)) {
AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
&closure, &incr, &property);
} else {
GetSelectionValue(widget, selection, target, callback,
closure, time, FALSE, property);
}
UNLOCK_APP(app);
}
void XtGetSelectionValueIncremental(widget, selection, target, callback,
closure, time)
Widget widget;
Atom selection;
Atom target;
XtSelectionCallbackProc callback;
XtPointer closure;
Time time;
{
Atom property;
Boolean incr = TRUE;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
property = GetParamInfo(widget, selection);
RemoveParamInfo(widget, selection);
if (IsGatheringRequest(widget, selection)) {
AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
&closure, &incr, &property);
} else {
GetSelectionValue(widget, selection, target, callback,
closure, time, TRUE, property);
}
UNLOCK_APP(app);
}
static void GetSelectionValues(widget, selection, targets, count, callbacks,
num_callbacks, closures, time, incremental,
properties)
Widget widget;
Atom selection;
Atom *targets;
int count;
XtSelectionCallbackProc *callbacks;
int num_callbacks;
XtPointer *closures;
Time time;
Boolean *incremental;
Atom *properties;
{
Select ctx;
CallBackInfo info;
IndirectPair *pairs, *p;
Atom *t;
if (count == 0) return;
ctx = FindCtx(XtDisplay(widget), selection);
if (ctx->widget && !ctx->was_disowned) {
int j, i;
RequestRec req;
ctx->req = &req;
req.ctx = ctx;
req.event.time = time;
ctx->ref_count++;
for (i = 0, j = 0; count; count--, i++, j++ ) {
if (j >= num_callbacks) j = 0;
DoLocalTransfer(&req, selection, targets[i], widget,
callbacks[j], closures[i], incremental[i],
properties ? properties[i] : None);
}
if (--ctx->ref_count == 0 && ctx->free_when_done)
XtFree((char*)ctx);
else
ctx->req = NULL;
} else {
XtSelectionCallbackProc *passed_callbacks;
XtSelectionCallbackProc stack_cbs[32];
int i = 0, j = 0;
passed_callbacks = (XtSelectionCallbackProc *)
XtStackAlloc(sizeof(XtSelectionCallbackProc) * count, stack_cbs);
for(i = 0; i < count; i++) {
if (j >= num_callbacks) j = 0;
passed_callbacks[i] = callbacks[j];
j++;
}
info = MakeInfo(ctx, passed_callbacks, closures, count, widget,
time, incremental, properties);
XtStackFree((XtPointer) passed_callbacks, stack_cbs);
info->target = (Atom *)__XtMalloc((unsigned) ((count+1) * sizeof(Atom)));
(*info->target) = ctx->prop_list->indirect_atom;
(void) memmove((char *) info->target+sizeof(Atom), (char *) targets,
count * sizeof(Atom));
pairs = (IndirectPair*)__XtMalloc((unsigned)(count*sizeof(IndirectPair)));
for (p = &pairs[count-1], t = &targets[count-1], i = count - 1;
p >= pairs; p--, t--, i--) {
p->target = *t;
if (properties == NULL || properties[i] == None) {
p->property = GetSelectionProperty(XtDisplay(widget));
XDeleteProperty(XtDisplay(widget), XtWindow(widget),
p->property);
} else {
p->property = properties[i];
}
}
XChangeProperty(XtDisplay(widget), XtWindow(widget),
info->property, info->property,
32, PropModeReplace, (unsigned char *) pairs,
count * IndirectPairWordSize);
XtFree((char*)pairs);
RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom);
}
}
void XtGetSelectionValues(widget, selection, targets, count, callback,
closures, time)
Widget widget;
Atom selection;
Atom *targets;
int count;
XtSelectionCallbackProc callback;
XtPointer *closures;
Time time;
{
Boolean incremental_values[32];
Boolean *incremental;
int i;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values);
for(i = 0; i < count; i++) incremental[i] = FALSE;
if (IsGatheringRequest(widget, selection)) {
AddSelectionRequests(widget, selection, count, targets, &callback,
1, closures, incremental, NULL);
} else {
GetSelectionValues(widget, selection, targets, count, &callback, 1,
closures, time, incremental, NULL);
}
XtStackFree((XtPointer) incremental, incremental_values);
UNLOCK_APP(app);
}
void XtGetSelectionValuesIncremental(widget, selection, targets, count,
callback, closures, time)
Widget widget;
Atom selection;
Atom *targets;
int count;
XtSelectionCallbackProc callback;
XtPointer *closures;
Time time;
{
Boolean incremental_values[32];
Boolean *incremental;
int i;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values);
for(i = 0; i < count; i++) incremental[i] = TRUE;
if (IsGatheringRequest(widget, selection)) {
AddSelectionRequests(widget, selection, count, targets, &callback,
1, closures, incremental, NULL);
} else {
GetSelectionValues(widget, selection, targets, count,
&callback, 1, closures, time, incremental, NULL);
}
XtStackFree((XtPointer) incremental, incremental_values);
UNLOCK_APP(app);
}
static Request GetRequestRecord(widget, selection, id)
Widget widget;
Atom selection;
XtRequestId id;
{
Request req = (Request)id;
Select ctx = NULL;
if ( (req == NULL
&& ((ctx = FindCtx( XtDisplay(widget), selection )) == NULL
|| ctx->req == NULL
|| ctx->selection != selection
|| ctx->widget == NULL))
|| (req != NULL
&& (req->ctx == NULL
|| req->ctx->selection != selection
|| req->ctx->widget != widget)))
{
String params = XtName(widget);
Cardinal num_params = 1;
XtAppWarningMsg(XtWidgetToApplicationContext(widget),
"notInConvertSelection", "xtGetSelectionRequest",
XtCXtToolkitError,
"XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc",
¶ms, &num_params
);
return NULL;
}
if (req == NULL) {
req = ctx->req;
}
return req;
}
XSelectionRequestEvent *XtGetSelectionRequest(widget, selection, id)
Widget widget;
Atom selection;
XtRequestId id;
{
Request req = (Request)id;
WIDGET_TO_APPCON(widget);
LOCK_APP(app);
req = GetRequestRecord(widget, selection, id);
if (! req) {
UNLOCK_APP(app);
return (XSelectionRequestEvent*) NULL;
}
if (req->event.type == 0) {
req->event.type = SelectionRequest;
req->event.serial = LastKnownRequestProcessed(XtDisplay(widget));
req->event.send_event = True;
req->event.display = XtDisplay(widget);
req->event.owner = XtWindow(req->ctx->widget);
req->event.selection = selection;
}
UNLOCK_APP(app);
return &req->event;
}
Atom XtReservePropertyAtom(w)
Widget w;
{
return(GetSelectionProperty(XtDisplay(w)));
}
void XtReleasePropertyAtom(w, atom)
Widget w;
Atom atom;
{
FreeSelectionProperty(XtDisplay(w), atom);
}
static void AddSelectionRequests(wid, sel, count, targets, callbacks,
num_cb, closures, incrementals, properties)
Widget wid;
Atom sel;
int count;
Atom *targets;
XtSelectionCallbackProc *callbacks;
int num_cb;
XtPointer *closures;
Boolean *incrementals;
Atom *properties;
{
QueuedRequestInfo qi;
Window window = XtWindow(wid);
Display *dpy = XtDisplay(wid);
LOCK_PROCESS;
if (multipleContext == 0) multipleContext = XUniqueContext();
qi = NULL;
(void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi);
if (qi != NULL) {
QueuedRequest *req = qi->requests;
int start = qi->count;
int i = 0;
int j = 0;
qi->count += count;
req = (QueuedRequest*) XtRealloc((char*) req,
(start + count) *
sizeof(QueuedRequest));
while(i < count) {
QueuedRequest newreq = (QueuedRequest)
__XtMalloc(sizeof(QueuedRequestRec));
newreq->selection = sel;
newreq->target = targets[i];
if (properties != NULL)
newreq->param = properties[i];
else {
newreq->param = GetSelectionProperty(dpy);
XDeleteProperty(dpy, window, newreq->param);
}
newreq->callback = callbacks[j];
newreq->closure = closures[i];
newreq->incremental = incrementals[i];
req[start] = newreq;
start++;
i++;
j++;
if (j > num_cb) j = 0;
}
qi->requests = req;
} else {
}
UNLOCK_PROCESS;
}
static Boolean IsGatheringRequest(wid, sel)
Widget wid;
Atom sel;
{
QueuedRequestInfo qi;
Window window = XtWindow(wid);
Display *dpy = XtDisplay(wid);
Boolean found = False;
int i;
if (multipleContext == 0) multipleContext = XUniqueContext();
qi = NULL;
(void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi);
if (qi != NULL) {
i = 0;
while(qi->selections[i] != None) {
if (qi->selections[i] == sel) {
found = True;
break;
}
i++;
}
}
return(found);
}
static void CleanupRequest(dpy, qi, sel)
Display *dpy;
QueuedRequestInfo qi;
Atom sel;
{
int i, j, n;
i = 0;
n = 0;
while(qi->selections[n] != sel &&
qi->selections[n] != None) n++;
if (qi->selections[n] == sel) {
while(qi->selections[n] != None) {
qi->selections[n] = qi->selections[n + 1];
n++;
}
}
while(i < qi->count) {
QueuedRequest req = qi->requests[i];
if (req->selection == sel) {
if (req->param != None)
FreeSelectionProperty(dpy, req->param);
qi->count--;
for(j = i; j < qi->count; j++)
qi->requests[j] = qi->requests[j + 1];
XtFree((char*) req);
} else {
i++;
}
}
}
extern void XtCreateSelectionRequest(widget, selection)
Widget widget;
Atom selection;
{
QueuedRequestInfo queueInfo;
Window window = XtWindow(widget);
Display *dpy = XtDisplay(widget);
int n;
LOCK_PROCESS;
if (multipleContext == 0) multipleContext = XUniqueContext();
queueInfo = NULL;
(void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
if (queueInfo != 0)
CleanupRequest(dpy, queueInfo, selection);
else {
queueInfo = (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec));
queueInfo->count = 0;
queueInfo->selections = (Atom*) __XtMalloc(sizeof(Atom) * 2);
queueInfo->selections[0] = None;
queueInfo->requests = (QueuedRequest *)
__XtMalloc(sizeof(QueuedRequest));
}
n = 0;
while(queueInfo->selections[n] != None) n++;
queueInfo->selections =
(Atom*) XtRealloc((char*) queueInfo->selections,
(n + 2) * sizeof(Atom));
queueInfo->selections[n] = selection;
queueInfo->selections[n + 1] = None;
(void) XSaveContext(dpy, window, multipleContext, (char*) queueInfo);
UNLOCK_PROCESS;
}
extern void XtSendSelectionRequest(widget, selection, time)
Widget widget;
Atom selection;
Time time;
{
QueuedRequestInfo queueInfo;
Window window = XtWindow(widget);
Display *dpy = XtDisplay(widget);
LOCK_PROCESS;
if (multipleContext == 0) multipleContext = XUniqueContext();
queueInfo = NULL;
(void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
if (queueInfo != NULL) {
int count = 0;
int i;
QueuedRequest *req = queueInfo->requests;
for(i = 0; i < queueInfo->count; i++)
if (req[i]->selection == selection) count++;
if (count > 0) {
if (count == 1) {
for(i = 0; i < queueInfo->count; i++)
if (req[i]->selection == selection) break;
GetSelectionValue(widget, selection, req[i]->target,
req[i]->callback, req[i]->closure, time,
req[i]->incremental, req[i]->param);
} else {
Atom *targets;
Atom t[PREALLOCED];
XtSelectionCallbackProc *cbs;
XtSelectionCallbackProc c[PREALLOCED];
XtPointer *closures;
XtPointer cs[PREALLOCED];
Boolean *incrs;
Boolean ins[PREALLOCED];
Atom *props;
Atom p[PREALLOCED];
int i = 0;
int j = 0;
targets = (Atom *) XtStackAlloc(count * sizeof(Atom), t);
cbs = (XtSelectionCallbackProc *)
XtStackAlloc(count * sizeof(XtSelectionCallbackProc), c);
closures = (XtPointer *) XtStackAlloc(count * sizeof(XtPointer), cs);
incrs = (Boolean *) XtStackAlloc(count * sizeof(Boolean), ins);
props = (Atom *) XtStackAlloc(count * sizeof(Atom), p);
for(i = 0; i < queueInfo->count; i++) {
if (req[i]->selection == selection) {
targets[j] = req[i]->target;
cbs[j] = req[i]->callback;
closures[j] = req[i]->closure;
incrs[j] = req[i]->incremental;
props[j] = req[i]->param;
j++;
}
}
GetSelectionValues(widget, selection, targets, count,
cbs, count, closures, time, incrs, props);
XtStackFree((XtPointer) targets, t);
XtStackFree((XtPointer) cbs, c);
XtStackFree((XtPointer) closures, cs);
XtStackFree((XtPointer) incrs, ins);
XtStackFree((XtPointer) props, p);
}
}
}
CleanupRequest(dpy, queueInfo, selection);
UNLOCK_PROCESS;
}
extern void XtCancelSelectionRequest(widget, selection)
Widget widget;
Atom selection;
{
QueuedRequestInfo queueInfo;
Window window = XtWindow(widget);
Display *dpy = XtDisplay(widget);
LOCK_PROCESS;
if (multipleContext == 0) multipleContext = XUniqueContext();
queueInfo = NULL;
(void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
if (queueInfo != 0)
CleanupRequest(dpy, queueInfo, selection);
UNLOCK_PROCESS;
}
void XtSetSelectionParameters(requestor, selection, type, value, length, format)
Widget requestor;
Atom selection;
Atom type;
XtPointer value;
unsigned long length;
int format;
{
Display *dpy = XtDisplay(requestor);
Window window = XtWindow(requestor);
Atom property = GetParamInfo(requestor, selection);
if (property == None) {
property = GetSelectionProperty(dpy);
AddParamInfo(requestor, selection, property);
}
XChangeProperty(dpy, window, property,
type, format, PropModeReplace,
(unsigned char *) value, length);
}
void XtGetSelectionParameters(owner, selection, request_id, type_return,
value_return, length_return, format_return)
Widget owner;
Atom selection;
XtRequestId request_id;
Atom* type_return;
XtPointer* value_return;
unsigned long* length_return;
int* format_return;
{
Request req;
Display *dpy = XtDisplay(owner);
WIDGET_TO_APPCON(owner);
*value_return = NULL;
*length_return = *format_return = 0;
*type_return = None;
LOCK_APP(app);
req = GetRequestRecord(owner, selection, request_id);
if (req && req->property) {
unsigned long bytes_after;
StartProtectedSection(dpy, req->requestor);
XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000,
False, AnyPropertyType, type_return, format_return,
length_return, &bytes_after,
(unsigned char**) value_return);
EndProtectedSection(dpy);
#ifdef XT_COPY_SELECTION
if (*value_return) {
int size = BYTELENGTH(*length_return, *format_return) + 1;
char *tmp = __XtMalloc((Cardinal) size);
(void) memmove(tmp, *value_return, size);
XFree(*value_return);
*value_return = tmp;
}
#endif
}
UNLOCK_APP(app);
}
static void AddParamInfo(w, selection, param_atom)
Widget w;
Atom selection;
Atom param_atom;
{
int n;
Param p;
ParamInfo pinfo;
LOCK_PROCESS;
if (paramPropertyContext == 0)
paramPropertyContext = XUniqueContext();
if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
(XPointer *) &pinfo)) {
pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec));
pinfo->count = 1;
pinfo->paramlist = XtNew(ParamRec);
p = pinfo->paramlist;
(void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
(char *)pinfo);
}
else {
for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) {
if (p->selection == None || p->selection == selection)
break;
}
if (n == 0) {
pinfo->count++;
pinfo->paramlist = (Param)
XtRealloc((char*) pinfo->paramlist,
pinfo->count * sizeof(ParamRec));
p = &pinfo->paramlist[pinfo->count - 1];
(void) XSaveContext(XtDisplay(w), XtWindow(w),
paramPropertyContext, (char *)pinfo);
}
}
p->selection = selection;
p->param = param_atom;
UNLOCK_PROCESS;
}
static void RemoveParamInfo(w, selection)
Widget w;
Atom selection;
{
int n;
Param p;
ParamInfo pinfo;
Boolean retain = False;
LOCK_PROCESS;
if (paramPropertyContext
&& (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
(XPointer *) &pinfo) == 0)) {
for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) {
if (p->selection != None) {
if (p->selection == selection)
p->selection = None;
else
retain = True;
}
}
if (! retain) {
XtFree((char*) pinfo->paramlist);
XtFree((char*) pinfo);
XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext);
}
}
UNLOCK_PROCESS;
}
static Atom GetParamInfo(w, selection)
Widget w;
Atom selection;
{
int n;
Param p;
ParamInfo pinfo;
Atom atom = None;
LOCK_PROCESS;
if (paramPropertyContext
&& (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
(XPointer *) &pinfo) == 0)) {
for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++)
if (p->selection == selection) {
atom = p->param;
break;
}
}
UNLOCK_PROCESS;
return atom;
}