Selection.c revision 0568f49b
1444c061aSmrg/***********************************************************
2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
31477040fSmrg
41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
51477040fSmrgcopy of this software and associated documentation files (the "Software"),
61477040fSmrgto deal in the Software without restriction, including without limitation
71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
91477040fSmrgSoftware is furnished to do so, subject to the following conditions:
101477040fSmrg
111477040fSmrgThe above copyright notice and this permission notice (including the next
121477040fSmrgparagraph) shall be included in all copies or substantial portions of the
131477040fSmrgSoftware.
141477040fSmrg
151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211477040fSmrgDEALINGS IN THE SOFTWARE.
221477040fSmrg
231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24444c061aSmrg
25444c061aSmrg                        All Rights Reserved
26444c061aSmrg
27444c061aSmrgPermission to use, copy, modify, and distribute this software and its
28444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
29444c061aSmrgprovided that the above copyright notice appear in all copies and that
30444c061aSmrgboth that copyright notice and this permission notice appear in
311477040fSmrgsupporting documentation, and that the name of Digital not be
32444c061aSmrgused in advertising or publicity pertaining to distribution of the
33444c061aSmrgsoftware without specific, written prior permission.
34444c061aSmrg
35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41444c061aSmrgSOFTWARE.
42444c061aSmrg
43444c061aSmrg******************************************************************/
44444c061aSmrg
45444c061aSmrg/*
46444c061aSmrg
47444c061aSmrgCopyright 1987, 1988, 1994, 1998  The Open Group
48444c061aSmrg
49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
51444c061aSmrgthe above copyright notice appear in all copies and that both that
52444c061aSmrgcopyright notice and this permission notice appear in supporting
53444c061aSmrgdocumentation.
54444c061aSmrg
55444c061aSmrgThe above copyright notice and this permission notice shall be included in
56444c061aSmrgall copies or substantial portions of the Software.
57444c061aSmrg
58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64444c061aSmrg
65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
67444c061aSmrgin this Software without prior written authorization from The Open Group.
68444c061aSmrg
69444c061aSmrg*/
70444c061aSmrg
71444c061aSmrg#ifdef HAVE_CONFIG_H
72444c061aSmrg#include <config.h>
73444c061aSmrg#endif
74444c061aSmrg#include "IntrinsicI.h"
75444c061aSmrg#include "StringDefs.h"
76444c061aSmrg#include "SelectionI.h"
77444c061aSmrg#include <X11/Xatom.h>
78444c061aSmrg#include <stdio.h>
79444c061aSmrg
80444c061aSmrgvoid _XtSetDefaultSelectionTimeout(
81444c061aSmrg	unsigned long *timeout)
82444c061aSmrg{
83444c061aSmrg	*timeout = 5000; /* default to 5 seconds */
84444c061aSmrg}
85444c061aSmrg
86444c061aSmrgvoid XtSetSelectionTimeout(
87444c061aSmrg	unsigned long timeout)
88444c061aSmrg{
89444c061aSmrg	XtAppSetSelectionTimeout(_XtDefaultAppContext(), timeout);
90444c061aSmrg}
91444c061aSmrg
92444c061aSmrgvoid XtAppSetSelectionTimeout(
93444c061aSmrg	XtAppContext app,
94444c061aSmrg	unsigned long timeout)
95444c061aSmrg{
96444c061aSmrg	LOCK_APP(app);
97444c061aSmrg	app->selectionTimeout = timeout;
98444c061aSmrg	UNLOCK_APP(app);
99444c061aSmrg}
100444c061aSmrg
101444c061aSmrgunsigned long XtGetSelectionTimeout(void)
102444c061aSmrg{
103444c061aSmrg	return XtAppGetSelectionTimeout(_XtDefaultAppContext());
104444c061aSmrg}
105444c061aSmrg
106444c061aSmrgunsigned long XtAppGetSelectionTimeout(
107444c061aSmrg	XtAppContext app)
108444c061aSmrg{
109444c061aSmrg	unsigned long retval;
110444c061aSmrg
111444c061aSmrg	LOCK_APP(app);
112444c061aSmrg	retval = app->selectionTimeout;
113444c061aSmrg	UNLOCK_APP(app);
114444c061aSmrg	return retval;
115444c061aSmrg}
116444c061aSmrg
117444c061aSmrg
118444c061aSmrg/* General utilities */
119444c061aSmrg
120444c061aSmrgstatic void HandleSelectionReplies(Widget, XtPointer, XEvent *, Boolean *);
121444c061aSmrgstatic void ReqTimedOut(XtPointer, XtIntervalId *);
122444c061aSmrgstatic void HandlePropertyGone(Widget, XtPointer, XEvent *, Boolean *);
123444c061aSmrgstatic void HandleGetIncrement(Widget, XtPointer, XEvent *, Boolean *);
124444c061aSmrgstatic void HandleIncremental(Display *, Widget, Atom, CallBackInfo, unsigned long);
125444c061aSmrg
126444c061aSmrgstatic XContext selectPropertyContext = 0;
127444c061aSmrgstatic XContext paramPropertyContext = 0;
128444c061aSmrgstatic XContext multipleContext = 0;
129444c061aSmrg
130444c061aSmrg/* Multiple utilities */
131444c061aSmrgstatic void AddSelectionRequests(Widget, Atom, int, Atom *, XtSelectionCallbackProc *, int, XtPointer *, Boolean *, Atom *);
132444c061aSmrgstatic Boolean IsGatheringRequest(Widget, Atom);
133444c061aSmrg
134444c061aSmrg#define PREALLOCED 32
135444c061aSmrg
136444c061aSmrg/* Parameter utilities */
137444c061aSmrgstatic void AddParamInfo(Widget, Atom, Atom);
138444c061aSmrgstatic void RemoveParamInfo(Widget, Atom);
139444c061aSmrgstatic Atom GetParamInfo(Widget, Atom);
140444c061aSmrg
141444c061aSmrgstatic int StorageSize[3] = {1, sizeof(short), sizeof(long)};
1420568f49bSmrg#define BYTELENGTH(length, format) ((length) * (size_t)StorageSize[(format)>>4])
143444c061aSmrg#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4])
1440568f49bSmrg#define NUMELEM2(bytelength, format) ((unsigned long)(bytelength) / (unsigned long) StorageSize[(format)>>4])
145444c061aSmrg
146444c061aSmrg/* Xlib and Xt are permitted to have different memory allocators, and in the
147444c061aSmrg * XtSelectionCallbackProc the client is instructed to free the selection
148444c061aSmrg * value with XtFree, so the selection value received from XGetWindowProperty
149444c061aSmrg * should be copied to memory allocated through Xt.  But copying is
150444c061aSmrg * undesirable since the selection value may be large, and, under normal
151444c061aSmrg * library configuration copying is unnecessary.
152444c061aSmrg */
153444c061aSmrg#ifdef XTTRACEMEMORY
154444c061aSmrg#define XT_COPY_SELECTION	1
155444c061aSmrg#endif
156444c061aSmrg
157444c061aSmrg/*ARGSUSED*/
158444c061aSmrgstatic void FreePropList(
159444c061aSmrg Widget w,			/* unused */
160444c061aSmrg XtPointer closure,
161444c061aSmrg XtPointer callData)		/* unused */
162444c061aSmrg{
163444c061aSmrg    PropList sarray = (PropList)closure;
164444c061aSmrg    LOCK_PROCESS;
165444c061aSmrg    XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy),
166444c061aSmrg		   selectPropertyContext);
167444c061aSmrg    UNLOCK_PROCESS;
168444c061aSmrg    XtFree((char*)sarray->list);
169444c061aSmrg    XtFree((char*)closure);
170444c061aSmrg}
171444c061aSmrg
172444c061aSmrg
173444c061aSmrgstatic PropList GetPropList(
174444c061aSmrg    Display *dpy)
175444c061aSmrg{
176444c061aSmrg    PropList sarray;
177444c061aSmrg
178444c061aSmrg    LOCK_PROCESS;
179444c061aSmrg    if (selectPropertyContext == 0)
180444c061aSmrg	selectPropertyContext = XUniqueContext();
181444c061aSmrg    if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
182444c061aSmrg		     (XPointer *)&sarray)) {
1830568f49bSmrg	Atom atoms[4];
1840568f49bSmrg	static char* names[] = {
1850568f49bSmrg	    "INCR",
1860568f49bSmrg	    "MULTIPLE",
1870568f49bSmrg	    "TIMESTAMP",
1880568f49bSmrg	    "_XT_SELECTION_0" };
1890568f49bSmrg
190444c061aSmrg	XtPerDisplay pd = _XtGetPerDisplay(dpy);
191444c061aSmrg	sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec));
192444c061aSmrg	sarray->dpy = dpy;
193444c061aSmrg	XInternAtoms(dpy, names, 4, FALSE, atoms);
194444c061aSmrg	sarray->incr_atom = atoms[0];
195444c061aSmrg	sarray->indirect_atom = atoms[1];
196444c061aSmrg	sarray->timestamp_atom = atoms[2];
197444c061aSmrg	sarray->propCount = 1;
198444c061aSmrg	sarray->list =
199444c061aSmrg	    (SelectionProp)__XtMalloc((unsigned) sizeof(SelectionPropRec));
200444c061aSmrg	sarray->list[0].prop = atoms[3];
201444c061aSmrg	sarray->list[0].avail = TRUE;
202444c061aSmrg	(void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
203444c061aSmrg			    (char *) sarray);
204444c061aSmrg	_XtAddCallback( &pd->destroy_callbacks,
205444c061aSmrg			FreePropList, (XtPointer)sarray );
206444c061aSmrg    }
207444c061aSmrg    UNLOCK_PROCESS;
208444c061aSmrg    return sarray;
209444c061aSmrg}
210444c061aSmrg
211444c061aSmrg
212444c061aSmrgstatic Atom GetSelectionProperty(
213444c061aSmrg    Display *dpy)
214444c061aSmrg{
215444c061aSmrg SelectionProp p;
216444c061aSmrg int propCount;
217444c061aSmrg char propname[80];
218444c061aSmrg PropList sarray = GetPropList(dpy);
219444c061aSmrg
220444c061aSmrg for (p = sarray->list, propCount=sarray->propCount;
221444c061aSmrg	propCount;
222444c061aSmrg	p++, propCount--) {
223444c061aSmrg   if (p->avail) {
224444c061aSmrg      p->avail = FALSE;
225444c061aSmrg      return(p->prop);
226444c061aSmrg   }
227444c061aSmrg }
228444c061aSmrg propCount = sarray->propCount++;
229444c061aSmrg sarray->list = (SelectionProp) XtRealloc((XtPointer)sarray->list,
2300568f49bSmrg  		(Cardinal)((size_t)sarray->propCount * sizeof(SelectionPropRec)));
231bdf0f55dSmrg (void) snprintf(propname, sizeof(propname), "_XT_SELECTION_%d", propCount);
232444c061aSmrg sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE);
233444c061aSmrg sarray->list[propCount].avail = FALSE;
234444c061aSmrg return(sarray->list[propCount].prop);
235444c061aSmrg}
236444c061aSmrg
237444c061aSmrgstatic void FreeSelectionProperty(
238444c061aSmrg    Display *dpy,
239444c061aSmrg    Atom prop)
240444c061aSmrg{
241444c061aSmrg SelectionProp p;
2429e7bcd65Smrg int propCount;
243444c061aSmrg PropList sarray;
244444c061aSmrg if (prop == None) return;
245444c061aSmrg LOCK_PROCESS;
246444c061aSmrg if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
247444c061aSmrg		  (XPointer *)&sarray))
248444c061aSmrg    XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
249444c061aSmrg	    "noSelectionProperties", "freeSelectionProperty", XtCXtToolkitError,
250444c061aSmrg		"internal error: no selection property context for display",
2510568f49bSmrg		 NULL,  NULL );
252444c061aSmrg UNLOCK_PROCESS;
2539e7bcd65Smrg for (p = sarray->list, propCount=sarray->propCount;
2549e7bcd65Smrg	propCount;
2559e7bcd65Smrg	p++, propCount--)
256444c061aSmrg   if (p->prop == prop) {
257444c061aSmrg      p->avail = TRUE;
258444c061aSmrg      return;
259444c061aSmrg      }
260444c061aSmrg}
261444c061aSmrg
262444c061aSmrgstatic void FreeInfo(
263444c061aSmrg    CallBackInfo info)
264444c061aSmrg{
265444c061aSmrg    XtFree((char*)info->incremental);
266444c061aSmrg    XtFree((char*)info->callbacks);
267444c061aSmrg    XtFree((char*)info->req_closure);
268444c061aSmrg    XtFree((char*)info->target);
269444c061aSmrg    XtFree((char*)info);
270444c061aSmrg}
271444c061aSmrg
272444c061aSmrgstatic CallBackInfo MakeInfo(
273444c061aSmrg    Select ctx,
274444c061aSmrg    XtSelectionCallbackProc *callbacks,
275444c061aSmrg    XtPointer *closures,
276444c061aSmrg    int count,
277444c061aSmrg    Widget widget,
278444c061aSmrg    Time time,
279444c061aSmrg    Boolean *incremental,
280444c061aSmrg    Atom *properties)
281444c061aSmrg{
282444c061aSmrg    	CallBackInfo info = XtNew(CallBackInfoRec);
283444c061aSmrg
284444c061aSmrg	info->ctx = ctx;
285444c061aSmrg	info->callbacks = (XtSelectionCallbackProc *)
2860568f49bSmrg	    __XtMalloc((unsigned) ((size_t)count * sizeof(XtSelectionCallbackProc)));
287444c061aSmrg	(void) memmove((char*)info->callbacks, (char*)callbacks,
2880568f49bSmrg		       (size_t)count * sizeof(XtSelectionCallbackProc));
289444c061aSmrg	info->req_closure =
2900568f49bSmrg	    (XtPointer*)__XtMalloc((unsigned) ((size_t)count * sizeof(XtPointer)));
291444c061aSmrg	(void) memmove((char*)info->req_closure, (char*)closures,
2920568f49bSmrg		       (size_t)count * sizeof(XtPointer));
293444c061aSmrg	if (count == 1 && properties != NULL && properties[0] != None)
294444c061aSmrg	    info->property = properties[0];
295444c061aSmrg	else {
296444c061aSmrg	    info->property = GetSelectionProperty(XtDisplay(widget));
297444c061aSmrg	    XDeleteProperty(XtDisplay(widget), XtWindow(widget),
298444c061aSmrg			    info->property);
299444c061aSmrg	}
300444c061aSmrg	info->proc = HandleSelectionReplies;
301444c061aSmrg	info->widget = widget;
302444c061aSmrg	info->time = time;
3030568f49bSmrg	info->incremental = (Boolean*) __XtMalloc((Cardinal)((size_t)count * sizeof(Boolean)));
304444c061aSmrg	(void) memmove((char*)info->incremental, (char*) incremental,
3050568f49bSmrg		       (size_t)count * sizeof(Boolean));
306444c061aSmrg	info->current = 0;
307444c061aSmrg	info->value = NULL;
308444c061aSmrg	return (info);
309444c061aSmrg}
310444c061aSmrg
311444c061aSmrgstatic void RequestSelectionValue(
312444c061aSmrg    CallBackInfo info,
313444c061aSmrg    Atom selection,
314444c061aSmrg    Atom target)
315444c061aSmrg{
316444c061aSmrg#ifndef DEBUG_WO_TIMERS
317444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(info->widget);
318444c061aSmrg	info->timeout = XtAppAddTimeOut(app,
319444c061aSmrg			 app->selectionTimeout, ReqTimedOut, (XtPointer)info);
320444c061aSmrg#endif
321444c061aSmrg	XtAddEventHandler(info->widget, (EventMask)0, TRUE,
322444c061aSmrg			  HandleSelectionReplies, (XtPointer)info);
323444c061aSmrg	XConvertSelection(info->ctx->dpy, selection, target,
324444c061aSmrg			  info->property, XtWindow(info->widget), info->time);
325444c061aSmrg}
326444c061aSmrg
327444c061aSmrg
328444c061aSmrgstatic XContext selectContext = 0;
329444c061aSmrg
330444c061aSmrgstatic Select NewContext(
331444c061aSmrg    Display *dpy,
332444c061aSmrg    Atom selection)
333444c061aSmrg{
334444c061aSmrg    /* assert(selectContext != 0) */
335444c061aSmrg    Select ctx = XtNew(SelectRec);
336444c061aSmrg    ctx->dpy = dpy;
337444c061aSmrg    ctx->selection = selection;
338444c061aSmrg    ctx->widget = NULL;
339444c061aSmrg    ctx->prop_list = GetPropList(dpy);
340444c061aSmrg    ctx->ref_count = 0;
341444c061aSmrg    ctx->free_when_done = FALSE;
342444c061aSmrg    ctx->was_disowned = FALSE;
343444c061aSmrg    LOCK_PROCESS;
344444c061aSmrg    (void)XSaveContext(dpy, (Window)selection, selectContext, (char *)ctx);
345444c061aSmrg    UNLOCK_PROCESS;
346444c061aSmrg    return ctx;
347444c061aSmrg}
348444c061aSmrg
349444c061aSmrgstatic Select FindCtx(
350444c061aSmrg    Display *dpy,
351444c061aSmrg    Atom selection)
352444c061aSmrg{
353444c061aSmrg    Select ctx;
354444c061aSmrg
355444c061aSmrg    LOCK_PROCESS;
356444c061aSmrg    if (selectContext == 0)
357444c061aSmrg	selectContext = XUniqueContext();
358444c061aSmrg    if (XFindContext(dpy, (Window)selection, selectContext, (XPointer *)&ctx))
359444c061aSmrg	ctx = NewContext(dpy, selection);
360444c061aSmrg    UNLOCK_PROCESS;
361444c061aSmrg    return ctx;
362444c061aSmrg}
363444c061aSmrg
364444c061aSmrg/*ARGSUSED*/
365444c061aSmrgstatic void WidgetDestroyed(
366444c061aSmrg    Widget widget,
367444c061aSmrg    XtPointer closure, XtPointer data)
368444c061aSmrg{
369444c061aSmrg    Select ctx = (Select) closure;
370444c061aSmrg    if (ctx->widget == widget) {
371444c061aSmrg	if (ctx->free_when_done)
372444c061aSmrg	    XtFree((char*)ctx);
373444c061aSmrg	else
374444c061aSmrg	    ctx->widget = NULL;
375444c061aSmrg    }
376444c061aSmrg}
377444c061aSmrg
378444c061aSmrg/* Selection Owner code */
379444c061aSmrg
380444c061aSmrgstatic void HandleSelectionEvents(Widget, XtPointer, XEvent *, Boolean *);
381444c061aSmrg
382444c061aSmrgstatic Boolean LoseSelection(
383444c061aSmrg    Select ctx,
384444c061aSmrg    Widget widget,
385444c061aSmrg    Atom selection,
386444c061aSmrg    Time time)
387444c061aSmrg{
388444c061aSmrg    if ((ctx->widget == widget) &&
389444c061aSmrg	(ctx->selection == selection) && /* paranoia */
390444c061aSmrg	!ctx->was_disowned &&
391444c061aSmrg	((time == CurrentTime) || (time >= ctx->time)))
392444c061aSmrg    {
393444c061aSmrg	XtRemoveEventHandler(widget, (EventMask)0, TRUE,
394444c061aSmrg			     HandleSelectionEvents, (XtPointer)ctx);
395444c061aSmrg	XtRemoveCallback(widget, XtNdestroyCallback,
396444c061aSmrg			 WidgetDestroyed, (XtPointer)ctx);
397444c061aSmrg	ctx->was_disowned = TRUE; /* widget officially loses ownership */
398444c061aSmrg	/* now inform widget */
399444c061aSmrg	if (ctx->loses) {
400444c061aSmrg	    if (ctx->incremental)
401444c061aSmrg	       (*(XtLoseSelectionIncrProc)ctx->loses)
402444c061aSmrg		   (widget, &ctx->selection, ctx->owner_closure);
403444c061aSmrg	    else  (*ctx->loses)(widget, &ctx->selection);
404444c061aSmrg	}
405444c061aSmrg	return(TRUE);
406444c061aSmrg    }
407444c061aSmrg    else return(FALSE);
408444c061aSmrg}
409444c061aSmrg
410444c061aSmrgstatic XContext selectWindowContext = 0;
411444c061aSmrg
412444c061aSmrg/* %%% Xlib.h should make this public! */
413444c061aSmrgtypedef int (*xErrorHandler)(Display*, XErrorEvent*);
414444c061aSmrg
415444c061aSmrgstatic xErrorHandler oldErrorHandler = NULL;
416444c061aSmrgstatic unsigned long firstProtectRequest;
417444c061aSmrgstatic Window errorWindow;
418444c061aSmrg
419444c061aSmrgstatic int LocalErrorHandler (
420444c061aSmrg    Display *dpy,
421444c061aSmrg    XErrorEvent *error)
422444c061aSmrg{
423444c061aSmrg    int retval;
424444c061aSmrg
425444c061aSmrg    /* If BadWindow error on selection requestor, nothing to do but let
426444c061aSmrg     * the transfer timeout.  Otherwise, invoke saved error handler. */
427444c061aSmrg
428444c061aSmrg    LOCK_PROCESS;
429444c061aSmrg
430444c061aSmrg    if (error->error_code == BadWindow && error->resourceid == errorWindow &&
431444c061aSmrg	error->serial >= firstProtectRequest) {
432444c061aSmrg	UNLOCK_PROCESS;
433444c061aSmrg	return 0;
434444c061aSmrg    }
435444c061aSmrg
436444c061aSmrg    if (oldErrorHandler == NULL) {
437444c061aSmrg	UNLOCK_PROCESS;
438444c061aSmrg	return 0;  /* should never happen */
439444c061aSmrg    }
440444c061aSmrg
441444c061aSmrg    retval = (*oldErrorHandler)(dpy, error);
442444c061aSmrg    UNLOCK_PROCESS;
443444c061aSmrg    return retval;
444444c061aSmrg}
445444c061aSmrg
446444c061aSmrgstatic void StartProtectedSection(
447444c061aSmrg    Display *dpy,
448444c061aSmrg    Window window)
449444c061aSmrg{
450444c061aSmrg    /* protect ourselves against request window being destroyed
451444c061aSmrg     * before completion of transfer */
452444c061aSmrg
453444c061aSmrg    LOCK_PROCESS;
454444c061aSmrg    oldErrorHandler = XSetErrorHandler(LocalErrorHandler);
455444c061aSmrg    firstProtectRequest = NextRequest(dpy);
456444c061aSmrg    errorWindow = window;
457444c061aSmrg    UNLOCK_PROCESS;
458444c061aSmrg}
459444c061aSmrg
460444c061aSmrgstatic void EndProtectedSection(
461444c061aSmrg    Display *dpy)
462444c061aSmrg{
463444c061aSmrg    /* flush any generated errors on requestor and
464444c061aSmrg     * restore original error handler */
465444c061aSmrg
466444c061aSmrg    XSync(dpy, False);
467444c061aSmrg
468444c061aSmrg    LOCK_PROCESS;
469444c061aSmrg    XSetErrorHandler(oldErrorHandler);
470444c061aSmrg    oldErrorHandler = NULL;
471444c061aSmrg    UNLOCK_PROCESS;
472444c061aSmrg}
473444c061aSmrg
474444c061aSmrgstatic void AddHandler(
475444c061aSmrg    Request req,
476444c061aSmrg    EventMask mask,
477444c061aSmrg    XtEventHandler proc,
478444c061aSmrg    XtPointer closure)
479444c061aSmrg{
480444c061aSmrg    Display *dpy = req->ctx->dpy;
481444c061aSmrg    Window window = req->requestor;
482444c061aSmrg    Widget widget = XtWindowToWidget(dpy, window);
483444c061aSmrg
484444c061aSmrg    if (widget != NULL) req->widget = widget;
485444c061aSmrg    else widget = req->widget;
486444c061aSmrg
487444c061aSmrg    if (XtWindow(widget) == window)
488444c061aSmrg	XtAddEventHandler(widget, mask, False, proc, closure);
489444c061aSmrg    else {
490444c061aSmrg	RequestWindowRec *requestWindowRec;
491444c061aSmrg	LOCK_PROCESS;
492444c061aSmrg	if (selectWindowContext == 0)
493444c061aSmrg	    selectWindowContext = XUniqueContext();
494444c061aSmrg	if (XFindContext(dpy, window, selectWindowContext,
495444c061aSmrg			 (XPointer *)&requestWindowRec)) {
496444c061aSmrg	    requestWindowRec = XtNew(RequestWindowRec);
497444c061aSmrg	    requestWindowRec->active_transfer_count = 0;
498444c061aSmrg	    (void)XSaveContext(dpy, window, selectWindowContext,
499444c061aSmrg			       (char *)requestWindowRec);
500444c061aSmrg	}
501444c061aSmrg	UNLOCK_PROCESS;
502444c061aSmrg	if (requestWindowRec->active_transfer_count++ == 0) {
503444c061aSmrg	    XtRegisterDrawable(dpy, window, widget);
5040568f49bSmrg	    XSelectInput(dpy, window, (long)mask);
505444c061aSmrg	}
506444c061aSmrg	XtAddRawEventHandler(widget, mask, FALSE, proc, closure);
507444c061aSmrg    }
508444c061aSmrg}
509444c061aSmrg
510444c061aSmrgstatic void RemoveHandler(
511444c061aSmrg    Request req,
512444c061aSmrg    EventMask mask,
513444c061aSmrg    XtEventHandler proc,
514444c061aSmrg    XtPointer closure)
515444c061aSmrg{
516444c061aSmrg    Display *dpy = req->ctx->dpy;
517444c061aSmrg    Window window = req->requestor;
518444c061aSmrg    Widget widget = req->widget;
519444c061aSmrg
520444c061aSmrg    if ((XtWindowToWidget(dpy, window) == widget) &&
521444c061aSmrg        (XtWindow(widget) != window)) {
522444c061aSmrg	/* we had to hang this window onto our widget; take it off */
523444c061aSmrg	RequestWindowRec* requestWindowRec;
524444c061aSmrg	XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure);
525444c061aSmrg	LOCK_PROCESS;
526444c061aSmrg	(void)XFindContext(dpy, window, selectWindowContext,
527444c061aSmrg			   (XPointer *)&requestWindowRec);
528444c061aSmrg	UNLOCK_PROCESS;
529444c061aSmrg	if (--requestWindowRec->active_transfer_count == 0) {
530444c061aSmrg	    XtUnregisterDrawable(dpy, window);
531444c061aSmrg	    StartProtectedSection(dpy, window);
532444c061aSmrg	    XSelectInput(dpy, window, 0L);
533444c061aSmrg	    EndProtectedSection(dpy);
534444c061aSmrg	    LOCK_PROCESS;
535444c061aSmrg	    (void)XDeleteContext(dpy, window, selectWindowContext);
536444c061aSmrg	    UNLOCK_PROCESS;
537444c061aSmrg	    XtFree((char*)requestWindowRec);
538444c061aSmrg	}
539444c061aSmrg    } else {
540444c061aSmrg        XtRemoveEventHandler(widget, mask, TRUE,  proc, closure);
541444c061aSmrg    }
542444c061aSmrg}
543444c061aSmrg
544444c061aSmrg/* ARGSUSED */
545444c061aSmrgstatic void OwnerTimedOut(
546444c061aSmrg    XtPointer closure,
547444c061aSmrg    XtIntervalId   *id)
548444c061aSmrg{
549444c061aSmrg    Request req = (Request)closure;
550444c061aSmrg    Select ctx = req->ctx;
551444c061aSmrg
552444c061aSmrg    if (ctx->incremental && (ctx->owner_cancel != NULL)) {
553444c061aSmrg	(*ctx->owner_cancel)(ctx->widget, &ctx->selection,
554444c061aSmrg			     &req->target, (XtRequestId*)&req,
555444c061aSmrg			     ctx->owner_closure);
556444c061aSmrg    } else {
557444c061aSmrg	if (ctx->notify == NULL)
558444c061aSmrg	    XtFree((char*)req->value);
559444c061aSmrg	else {
560444c061aSmrg	    /* the requestor hasn't deleted the property, but
561444c061aSmrg	     * the owner needs to free the value.
562444c061aSmrg	     */
563444c061aSmrg	    if (ctx->incremental)
564444c061aSmrg		(*(XtSelectionDoneIncrProc)ctx->notify)
565444c061aSmrg			      (ctx->widget, &ctx->selection, &req->target,
566444c061aSmrg			       (XtRequestId*)&req, ctx->owner_closure);
567444c061aSmrg	    else
568444c061aSmrg		(*ctx->notify)(ctx->widget, &ctx->selection, &req->target);
569444c061aSmrg	}
570444c061aSmrg    }
571444c061aSmrg
572444c061aSmrg    RemoveHandler(req, (EventMask)PropertyChangeMask,
573444c061aSmrg		  HandlePropertyGone, closure);
574444c061aSmrg    XtFree((char*)req);
575444c061aSmrg    if (--ctx->ref_count == 0 && ctx->free_when_done)
576444c061aSmrg	XtFree((char*)ctx);
577444c061aSmrg}
578444c061aSmrg
579444c061aSmrgstatic void SendIncrement(
580444c061aSmrg    Request incr)
581444c061aSmrg{
582444c061aSmrg    Display *dpy = incr->ctx->dpy;
583444c061aSmrg
5840568f49bSmrg    unsigned long incrSize = (unsigned long) MAX_SELECTION_INCR(dpy);
585444c061aSmrg    if (incrSize > incr->bytelength - incr->offset)
586444c061aSmrg        incrSize = incr->bytelength - incr->offset;
587444c061aSmrg    StartProtectedSection(dpy, incr->requestor);
588444c061aSmrg    XChangeProperty(dpy, incr->requestor, incr->property,
589444c061aSmrg    	    incr->type, incr->format, PropModeReplace,
590444c061aSmrg	    (unsigned char *)incr->value + incr->offset,
591444c061aSmrg	    NUMELEM((int)incrSize, incr->format));
592444c061aSmrg    EndProtectedSection(dpy);
593444c061aSmrg    incr->offset += incrSize;
594444c061aSmrg}
595444c061aSmrg
596444c061aSmrgstatic void AllSent(
597444c061aSmrg    Request req)
598444c061aSmrg{
599444c061aSmrg    Select ctx = req->ctx;
600444c061aSmrg    StartProtectedSection(ctx->dpy, req->requestor);
601444c061aSmrg    XChangeProperty(ctx->dpy, req->requestor,
602444c061aSmrg		    req->property, req->type,  req->format,
603444c061aSmrg		    PropModeReplace, (unsigned char *) NULL, 0);
604444c061aSmrg    EndProtectedSection(ctx->dpy);
605444c061aSmrg    req->allSent = TRUE;
606444c061aSmrg
607444c061aSmrg    if (ctx->notify == NULL) XtFree((char*)req->value);
608444c061aSmrg}
609444c061aSmrg
610444c061aSmrg/*ARGSUSED*/
611444c061aSmrgstatic void HandlePropertyGone(
612444c061aSmrg    Widget widget,
613444c061aSmrg    XtPointer closure,
614444c061aSmrg    XEvent *ev,
615444c061aSmrg    Boolean *cont)
616444c061aSmrg{
617444c061aSmrg    XPropertyEvent *event = (XPropertyEvent *) ev;
618444c061aSmrg    Request req = (Request)closure;
619444c061aSmrg    Select ctx = req->ctx;
620444c061aSmrg
621444c061aSmrg    if ((event->type != PropertyNotify) ||
622444c061aSmrg        (event->state != PropertyDelete) ||
623444c061aSmrg	(event->atom != req->property) ||
624444c061aSmrg	(event->window != req->requestor))
625444c061aSmrg      return;
626444c061aSmrg#ifndef DEBUG_WO_TIMERS
627444c061aSmrg    XtRemoveTimeOut(req->timeout);
628444c061aSmrg#endif
629444c061aSmrg    if (req->allSent) {
630444c061aSmrg	if (ctx->notify) {
631444c061aSmrg	    if (ctx->incremental) {
632444c061aSmrg		(*(XtSelectionDoneIncrProc)ctx->notify)
633444c061aSmrg			      (ctx->widget, &ctx->selection, &req->target,
634444c061aSmrg			       (XtRequestId*)&req, ctx->owner_closure);
635444c061aSmrg	    }
636444c061aSmrg	    else (*ctx->notify)(ctx->widget, &ctx->selection, &req->target);
637444c061aSmrg	}
638444c061aSmrg	RemoveHandler(req, (EventMask)PropertyChangeMask,
639444c061aSmrg		      HandlePropertyGone, closure);
640444c061aSmrg	XtFree((char*)req);
641444c061aSmrg	if (--ctx->ref_count == 0 && ctx->free_when_done)
642444c061aSmrg	    XtFree((char*)ctx);
643444c061aSmrg    } else  { /* is this part of an incremental transfer? */
644444c061aSmrg	if (ctx->incremental) {
645444c061aSmrg	     if (req->bytelength == 0)
646444c061aSmrg		AllSent(req);
647444c061aSmrg	     else {
6480568f49bSmrg		unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy);
649444c061aSmrg    		SendIncrement(req);
650444c061aSmrg		(*(XtConvertSelectionIncrProc)ctx->convert)
651444c061aSmrg			   (ctx->widget, &ctx->selection, &req->target,
652444c061aSmrg			    &req->type, &req->value,
653444c061aSmrg			    &req->bytelength, &req->format,
654444c061aSmrg			    &size, ctx->owner_closure, (XtPointer*)&req);
655444c061aSmrg		if (req->bytelength)
656444c061aSmrg		    req->bytelength = BYTELENGTH(req->bytelength, req->format);
657444c061aSmrg		req->offset = 0;
658444c061aSmrg	    }
659444c061aSmrg	} else {
660444c061aSmrg	    if (req->offset < req->bytelength)
661444c061aSmrg		SendIncrement(req);
662444c061aSmrg	    else AllSent(req);
663444c061aSmrg	}
664444c061aSmrg#ifndef DEBUG_WO_TIMERS
665444c061aSmrg	{
666444c061aSmrg	  XtAppContext app = XtWidgetToApplicationContext(req->widget);
667444c061aSmrg	  req->timeout = XtAppAddTimeOut(app,
668444c061aSmrg			 app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
669444c061aSmrg	}
670444c061aSmrg#endif
671444c061aSmrg    }
672444c061aSmrg}
673444c061aSmrg
674444c061aSmrgstatic void PrepareIncremental(
675444c061aSmrg    Request req,
676444c061aSmrg    Widget widget,
677444c061aSmrg    Window window,
678444c061aSmrg    Atom property,
679444c061aSmrg    Atom target,
680444c061aSmrg    Atom targetType,
681444c061aSmrg    XtPointer value,
682444c061aSmrg    unsigned long length,
683444c061aSmrg    int format)
684444c061aSmrg{
685444c061aSmrg	req->type = targetType;
686444c061aSmrg	req->value = value;
687444c061aSmrg	req->bytelength = BYTELENGTH(length,format);
688444c061aSmrg	req->format = format;
689444c061aSmrg	req->offset = 0;
690444c061aSmrg	req->target = target;
691444c061aSmrg	req->widget = widget;
692444c061aSmrg	req->allSent = FALSE;
693444c061aSmrg#ifndef DEBUG_WO_TIMERS
694444c061aSmrg	{
695444c061aSmrg	XtAppContext app = XtWidgetToApplicationContext(widget);
696444c061aSmrg	req->timeout = XtAppAddTimeOut(app,
697444c061aSmrg			 app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
698444c061aSmrg	}
699444c061aSmrg#endif
700444c061aSmrg	AddHandler(req, (EventMask)PropertyChangeMask,
701444c061aSmrg		   HandlePropertyGone, (XtPointer)req);
702444c061aSmrg/* now send client INCR property */
703444c061aSmrg	XChangeProperty(req->ctx->dpy, window, req->property,
704444c061aSmrg			req->ctx->prop_list->incr_atom,
705444c061aSmrg			32, PropModeReplace,
706444c061aSmrg			(unsigned char *)&req->bytelength, 1);
707444c061aSmrg}
708444c061aSmrg
709444c061aSmrgstatic Boolean GetConversion(
710444c061aSmrg    Select ctx,			/* logical owner */
711444c061aSmrg    XSelectionRequestEvent* event,
712444c061aSmrg    Atom target,
713444c061aSmrg    Atom property,		/* requestor's property */
714444c061aSmrg    Widget widget)		/* physical owner (receives events) */
715444c061aSmrg{
716444c061aSmrg    XtPointer value = NULL;
717444c061aSmrg    unsigned long length;
718444c061aSmrg    int format;
719444c061aSmrg    Atom targetType;
720444c061aSmrg    Request req = XtNew(RequestRec);
721444c061aSmrg    Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom);
722444c061aSmrg
723444c061aSmrg    req->ctx = ctx;
724444c061aSmrg    req->event = *event;
725444c061aSmrg    req->property = property;
726444c061aSmrg    req->requestor = event->requestor;
727444c061aSmrg
728444c061aSmrg    if (timestamp_target) {
729444c061aSmrg	value = __XtMalloc(sizeof(long));
7300568f49bSmrg	*(long*)value = (long) ctx->time;
731444c061aSmrg	targetType = XA_INTEGER;
732444c061aSmrg	length = 1;
733444c061aSmrg	format = 32;
734444c061aSmrg    }
735444c061aSmrg    else {
736444c061aSmrg	ctx->ref_count++;
737444c061aSmrg	if (ctx->incremental == TRUE) {
7380568f49bSmrg	     unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy);
739444c061aSmrg	     if ((*(XtConvertSelectionIncrProc)ctx->convert)
740444c061aSmrg			       (ctx->widget, &event->selection, &target,
741444c061aSmrg				&targetType, &value, &length, &format,
742444c061aSmrg				&size, ctx->owner_closure, (XtRequestId*)&req)
743444c061aSmrg		     == FALSE) {
744444c061aSmrg		 XtFree((char*)req);
745444c061aSmrg		 ctx->ref_count--;
746444c061aSmrg		 return(FALSE);
747444c061aSmrg	     }
748444c061aSmrg	     StartProtectedSection(ctx->dpy, event->requestor);
749444c061aSmrg	     PrepareIncremental(req, widget, event->requestor, property,
750444c061aSmrg				target, targetType, value, length, format);
751444c061aSmrg	     return(TRUE);
752444c061aSmrg	}
753444c061aSmrg	ctx->req = req;
754444c061aSmrg	if ((*ctx->convert)(ctx->widget, &event->selection, &target,
755444c061aSmrg			    &targetType, &value, &length, &format) == FALSE) {
756444c061aSmrg	    XtFree((char*)req);
757444c061aSmrg	    ctx->req = NULL;
758444c061aSmrg	    ctx->ref_count--;
759444c061aSmrg	    return(FALSE);
760444c061aSmrg	}
761444c061aSmrg	ctx->req = NULL;
762444c061aSmrg    }
763444c061aSmrg    StartProtectedSection(ctx->dpy, event->requestor);
764444c061aSmrg    if (BYTELENGTH(length,format) <= (unsigned long) MAX_SELECTION_INCR(ctx->dpy)) {
765444c061aSmrg	if (! timestamp_target) {
766444c061aSmrg	    if (ctx->notify != NULL) {
767444c061aSmrg		  req->target = target;
768444c061aSmrg		  req->widget = widget;
769444c061aSmrg		  req->allSent = TRUE;
770444c061aSmrg#ifndef DEBUG_WO_TIMERS
771444c061aSmrg		  {
772444c061aSmrg		  XtAppContext app = XtWidgetToApplicationContext(req->widget);
773444c061aSmrg		  req->timeout = XtAppAddTimeOut(app,
774444c061aSmrg			 app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
775444c061aSmrg		  }
776444c061aSmrg#endif
777444c061aSmrg	          AddHandler(req, (EventMask)PropertyChangeMask,
778444c061aSmrg			     HandlePropertyGone, (XtPointer)req);
779444c061aSmrg	      }
780444c061aSmrg	      else ctx->ref_count--;
781444c061aSmrg        }
782444c061aSmrg	XChangeProperty(ctx->dpy, event->requestor, property,
783444c061aSmrg			targetType, format, PropModeReplace,
784444c061aSmrg			(unsigned char *)value, (int)length);
785444c061aSmrg	/* free storage for client if no notify proc */
786444c061aSmrg	if (timestamp_target || ctx->notify == NULL) {
787444c061aSmrg	    XtFree((char*)value);
788444c061aSmrg	    XtFree((char*)req);
789444c061aSmrg	}
790444c061aSmrg    } else {
791444c061aSmrg	 PrepareIncremental(req, widget, event->requestor, property,
792444c061aSmrg			    target, targetType, value, length, format);
793444c061aSmrg    }
794444c061aSmrg    return(TRUE);
795444c061aSmrg}
796444c061aSmrg
797444c061aSmrg/*ARGSUSED*/
798444c061aSmrgstatic void HandleSelectionEvents(
799444c061aSmrg    Widget widget,
800444c061aSmrg    XtPointer closure,
801444c061aSmrg    XEvent *event,
802444c061aSmrg    Boolean *cont)
803444c061aSmrg{
804444c061aSmrg    Select ctx;
805444c061aSmrg    XSelectionEvent ev;
806444c061aSmrg    Atom target;
807444c061aSmrg
808444c061aSmrg    ctx = (Select) closure;
809444c061aSmrg    switch (event->type) {
810444c061aSmrg      case SelectionClear:
811444c061aSmrg	/* if this event is not for the selection we registered for,
812444c061aSmrg	 * don't do anything */
813444c061aSmrg	if (ctx->selection != event->xselectionclear.selection ||
814444c061aSmrg	    ctx->serial > event->xselectionclear.serial)
815444c061aSmrg	    break;
816444c061aSmrg	(void) LoseSelection(ctx, widget, event->xselectionclear.selection,
817444c061aSmrg			event->xselectionclear.time);
818444c061aSmrg	break;
819444c061aSmrg      case SelectionRequest:
820444c061aSmrg	/* if this event is not for the selection we registered for,
821444c061aSmrg	 * don't do anything */
822444c061aSmrg	if (ctx->selection != event->xselectionrequest.selection)
823444c061aSmrg	    break;
824444c061aSmrg	ev.type = SelectionNotify;
825444c061aSmrg	ev.display = event->xselectionrequest.display;
826444c061aSmrg	ev.requestor = event->xselectionrequest.requestor;
827444c061aSmrg	ev.selection = event->xselectionrequest.selection;
828444c061aSmrg	ev.time = event->xselectionrequest.time;
829444c061aSmrg	ev.target = event->xselectionrequest.target;
830444c061aSmrg	if (event->xselectionrequest.property == None) /* obsolete requestor */
831444c061aSmrg	   event->xselectionrequest.property = event->xselectionrequest.target;
832444c061aSmrg	if (ctx->widget != widget || ctx->was_disowned
833444c061aSmrg	   || ((event->xselectionrequest.time != CurrentTime)
834249c3046Smrg	        && (event->xselectionrequest.time < ctx->time))) {
835444c061aSmrg	    ev.property = None;
836249c3046Smrg	    StartProtectedSection(ev.display, ev.requestor);
837249c3046Smrg	} else {
838444c061aSmrg	   if (ev.target == ctx->prop_list->indirect_atom) {
839444c061aSmrg	      IndirectPair *p;
840444c061aSmrg	      int format;
841444c061aSmrg	      unsigned long bytesafter, length;
8429e7bcd65Smrg	      unsigned char *value = NULL;
8430568f49bSmrg	      int count;
8440568f49bSmrg	      Boolean writeback = FALSE;
8450568f49bSmrg
846444c061aSmrg	      ev.property = event->xselectionrequest.property;
847444c061aSmrg	      StartProtectedSection(ev.display, ev.requestor);
8489e7bcd65Smrg	      if (XGetWindowProperty(ev.display, ev.requestor,
849444c061aSmrg			event->xselectionrequest.property, 0L, 1000000,
850444c061aSmrg			False,(Atom)AnyPropertyType, &target, &format, &length,
8519e7bcd65Smrg			&bytesafter, &value) == Success)
8520568f49bSmrg		  count = (int) (BYTELENGTH(length, format) / sizeof(IndirectPair));
8539e7bcd65Smrg	      else
8549e7bcd65Smrg		  count = 0;
855444c061aSmrg	      for (p = (IndirectPair *)value; count; p++, count--) {
856444c061aSmrg		  EndProtectedSection(ctx->dpy);
857444c061aSmrg		  if (!GetConversion(ctx, (XSelectionRequestEvent*)event,
858444c061aSmrg				     p->target, p->property, widget)) {
859444c061aSmrg
860444c061aSmrg			p->target = None;
861444c061aSmrg			writeback = TRUE;
862444c061aSmrg			StartProtectedSection(ctx->dpy, ev.requestor);
863444c061aSmrg		  }
864444c061aSmrg	      }
865444c061aSmrg	      if (writeback)
866444c061aSmrg		XChangeProperty(ev.display, ev.requestor,
867444c061aSmrg			event->xselectionrequest.property, target,
868444c061aSmrg			format, PropModeReplace, value, (int)length);
869444c061aSmrg	      XFree((char *)value);
870444c061aSmrg	  } else /* not multiple */ {
871444c061aSmrg	       if (GetConversion(ctx, (XSelectionRequestEvent*)event,
872444c061aSmrg				 event->xselectionrequest.target,
873444c061aSmrg				 event->xselectionrequest.property,
874444c061aSmrg				 widget))
875444c061aSmrg		   ev.property = event->xselectionrequest.property;
876444c061aSmrg	       else {
877444c061aSmrg		   ev.property = None;
878444c061aSmrg		   StartProtectedSection(ctx->dpy, ev.requestor);
879444c061aSmrg	       }
880444c061aSmrg	   }
881444c061aSmrg      }
882444c061aSmrg      (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long)NULL,
883444c061aSmrg		   (XEvent *) &ev);
884444c061aSmrg
885444c061aSmrg      EndProtectedSection(ctx->dpy);
886444c061aSmrg
887444c061aSmrg      break;
888444c061aSmrg    }
889444c061aSmrg}
890444c061aSmrg
891444c061aSmrgstatic Boolean OwnSelection(
892444c061aSmrg    Widget widget,
893444c061aSmrg    Atom selection,
894444c061aSmrg    Time time,
895444c061aSmrg    XtConvertSelectionProc convert,
896444c061aSmrg    XtLoseSelectionProc lose,
897444c061aSmrg    XtSelectionDoneProc notify,
898444c061aSmrg    XtCancelConvertSelectionProc cancel,
899444c061aSmrg    XtPointer closure,
900444c061aSmrg    Boolean incremental)
901444c061aSmrg{
902444c061aSmrg    Select ctx;
903444c061aSmrg    Select oldctx = NULL;
904444c061aSmrg
905444c061aSmrg    if (!XtIsRealized(widget)) return False;
906444c061aSmrg
907444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
908444c061aSmrg    if (ctx->widget != widget || ctx->time != time ||
909444c061aSmrg	ctx->ref_count || ctx->was_disowned)
910444c061aSmrg    {
911444c061aSmrg	Boolean replacement = FALSE;
912444c061aSmrg	Window window = XtWindow(widget);
913444c061aSmrg	unsigned long serial = XNextRequest(ctx->dpy);
914444c061aSmrg        XSetSelectionOwner(ctx->dpy, selection, window, time);
915444c061aSmrg        if (XGetSelectionOwner(ctx->dpy, selection) != window)
916444c061aSmrg	    return FALSE;
917444c061aSmrg	if (ctx->ref_count) {	/* exchange is in-progress */
918444c061aSmrg#ifdef DEBUG_ACTIVE
919444c061aSmrg	    printf( "Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n",
920444c061aSmrg		    XtName(widget), (long)selection, ctx->ref_count );
921444c061aSmrg#endif
922444c061aSmrg	    if (ctx->widget != widget ||
923444c061aSmrg		ctx->convert != convert ||
924444c061aSmrg		ctx->loses != lose ||
925444c061aSmrg		ctx->notify != notify ||
926444c061aSmrg		ctx->owner_cancel != cancel ||
927444c061aSmrg		ctx->incremental != incremental ||
928444c061aSmrg		ctx->owner_closure != closure)
929444c061aSmrg	    {
930444c061aSmrg		if (ctx->widget == widget) {
931444c061aSmrg		    XtRemoveEventHandler(widget, (EventMask)0, TRUE,
932444c061aSmrg					HandleSelectionEvents, (XtPointer)ctx);
933444c061aSmrg		    XtRemoveCallback(widget, XtNdestroyCallback,
934444c061aSmrg				     WidgetDestroyed, (XtPointer)ctx);
935444c061aSmrg		    replacement = TRUE;
936444c061aSmrg		}
937444c061aSmrg		else if (!ctx->was_disowned) {
938444c061aSmrg		    oldctx = ctx;
939444c061aSmrg		}
940444c061aSmrg		ctx->free_when_done = TRUE;
941444c061aSmrg		ctx = NewContext(XtDisplay(widget), selection);
942444c061aSmrg	    }
943444c061aSmrg	    else if (!ctx->was_disowned) { /* current owner is new owner */
944444c061aSmrg		ctx->time = time;
945444c061aSmrg		return TRUE;
946444c061aSmrg	    }
947444c061aSmrg	}
948444c061aSmrg    	if (ctx->widget != widget || ctx->was_disowned || replacement) {
949444c061aSmrg	    if (ctx->widget && !ctx->was_disowned && !replacement) {
950444c061aSmrg		oldctx = ctx;
951444c061aSmrg		oldctx->free_when_done = TRUE;
952444c061aSmrg		ctx = NewContext(XtDisplay(widget), selection);
953444c061aSmrg	    }
954444c061aSmrg	    XtAddEventHandler(widget, (EventMask)0, TRUE,
955444c061aSmrg			      HandleSelectionEvents, (XtPointer)ctx);
956444c061aSmrg	    XtAddCallback(widget, XtNdestroyCallback,
957444c061aSmrg			  WidgetDestroyed, (XtPointer)ctx);
958444c061aSmrg	}
959444c061aSmrg	ctx->widget = widget;	/* Selection offically changes hands. */
960444c061aSmrg	ctx->time = time;
961444c061aSmrg	ctx->serial = serial;
962444c061aSmrg    }
963444c061aSmrg    ctx->convert = convert;
964444c061aSmrg    ctx->loses = lose;
965444c061aSmrg    ctx->notify = notify;
966444c061aSmrg    ctx->owner_cancel = cancel;
9670568f49bSmrg    XtSetBit(ctx->incremental, incremental);
968444c061aSmrg    ctx->owner_closure = closure;
969444c061aSmrg    ctx->was_disowned = FALSE;
970444c061aSmrg
971444c061aSmrg    /* Defer calling the previous selection owner's lose selection procedure
972444c061aSmrg     * until the new selection is established, to allow the previous
973444c061aSmrg     * selection owner to ask for the new selection to be converted in
974444c061aSmrg     * the lose selection procedure.  The context pointer is the closure
975444c061aSmrg     * of the event handler and the destroy callback, so the old context
976444c061aSmrg     * pointer and the record contents must be preserved for LoseSelection.
977444c061aSmrg     */
978444c061aSmrg    if (oldctx) {
979444c061aSmrg	(void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time);
980444c061aSmrg	if (!oldctx->ref_count && oldctx->free_when_done)
981444c061aSmrg	    XtFree((char*)oldctx);
982444c061aSmrg    }
983444c061aSmrg    return TRUE;
984444c061aSmrg}
985444c061aSmrg
986444c061aSmrg
987444c061aSmrgBoolean XtOwnSelection(
988444c061aSmrg    Widget widget,
989444c061aSmrg    Atom selection,
990444c061aSmrg    Time time,
991444c061aSmrg    XtConvertSelectionProc convert,
992444c061aSmrg    XtLoseSelectionProc lose,
993444c061aSmrg    XtSelectionDoneProc notify)
994444c061aSmrg{
995444c061aSmrg    Boolean retval;
996444c061aSmrg    WIDGET_TO_APPCON(widget);
997444c061aSmrg
998444c061aSmrg    LOCK_APP(app);
999444c061aSmrg    retval = OwnSelection(widget, selection, time, convert, lose, notify,
1000444c061aSmrg			(XtCancelConvertSelectionProc)NULL,
1001444c061aSmrg			(XtPointer)NULL, FALSE);
1002444c061aSmrg    UNLOCK_APP(app);
1003444c061aSmrg    return retval;
1004444c061aSmrg}
1005444c061aSmrg
1006444c061aSmrg
1007444c061aSmrgBoolean XtOwnSelectionIncremental(
1008444c061aSmrg    Widget widget,
1009444c061aSmrg    Atom selection,
1010444c061aSmrg    Time time,
1011444c061aSmrg    XtConvertSelectionIncrProc convert,
1012444c061aSmrg    XtLoseSelectionIncrProc lose,
1013444c061aSmrg    XtSelectionDoneIncrProc notify,
1014444c061aSmrg    XtCancelConvertSelectionProc cancel,
1015444c061aSmrg    XtPointer closure)
1016444c061aSmrg{
1017444c061aSmrg    Boolean retval;
1018444c061aSmrg    WIDGET_TO_APPCON(widget);
1019444c061aSmrg
1020444c061aSmrg    LOCK_APP(app);
1021444c061aSmrg    retval = OwnSelection(widget, selection, time,
1022444c061aSmrg			(XtConvertSelectionProc)convert,
1023444c061aSmrg			(XtLoseSelectionProc)lose,
1024444c061aSmrg			(XtSelectionDoneProc)notify,
1025444c061aSmrg			cancel, closure, TRUE);
1026444c061aSmrg    UNLOCK_APP(app);
1027444c061aSmrg    return retval;
1028444c061aSmrg}
1029444c061aSmrg
1030444c061aSmrg
10312265a131Smrgvoid XtDisownSelection(
10322265a131Smrg    Widget widget,
10332265a131Smrg    Atom selection,
10342265a131Smrg    Time time)
1035444c061aSmrg{
1036444c061aSmrg    Select ctx;
1037444c061aSmrg    WIDGET_TO_APPCON(widget);
1038444c061aSmrg
1039444c061aSmrg    LOCK_APP(app);
1040444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1041444c061aSmrg    if (LoseSelection(ctx, widget, selection, time))
1042444c061aSmrg	XSetSelectionOwner(XtDisplay(widget), selection, None, time);
1043444c061aSmrg    UNLOCK_APP(app);
1044444c061aSmrg}
1045444c061aSmrg
1046444c061aSmrg/* Selection Requestor code */
1047444c061aSmrg
1048444c061aSmrgstatic Boolean IsINCRtype(
1049444c061aSmrg    CallBackInfo info,
1050444c061aSmrg    Window window,
1051444c061aSmrg    Atom prop)
1052444c061aSmrg{
1053444c061aSmrg    unsigned long bytesafter;
1054444c061aSmrg    unsigned long length;
1055444c061aSmrg    int format;
1056444c061aSmrg    Atom type;
1057444c061aSmrg    unsigned char *value;
1058444c061aSmrg
1059444c061aSmrg    if (prop == None) return False;
1060444c061aSmrg
10619e7bcd65Smrg    if (XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L,
10629e7bcd65Smrg			   False, info->ctx->prop_list->incr_atom, &type,
10639e7bcd65Smrg			   &format, &length, &bytesafter, &value) != Success)
10649e7bcd65Smrg	return False;
1065444c061aSmrg
1066444c061aSmrg    return (type == info->ctx->prop_list->incr_atom);
1067444c061aSmrg}
1068444c061aSmrg
1069444c061aSmrg/*ARGSUSED*/
1070444c061aSmrgstatic void ReqCleanup(
1071444c061aSmrg    Widget widget,
1072444c061aSmrg    XtPointer closure,
1073444c061aSmrg    XEvent *ev,
1074444c061aSmrg    Boolean *cont)
1075444c061aSmrg{
1076444c061aSmrg    CallBackInfo info = (CallBackInfo)closure;
1077444c061aSmrg    unsigned long bytesafter, length;
1078444c061aSmrg    int format;
1079444c061aSmrg    Atom target;
1080444c061aSmrg
1081444c061aSmrg    if (ev->type == SelectionNotify) {
1082444c061aSmrg	XSelectionEvent *event = (XSelectionEvent *) ev;
1083444c061aSmrg	if (!MATCH_SELECT(event, info)) return; /* not really for us */
1084444c061aSmrg         XtRemoveEventHandler(widget, (EventMask)0, TRUE,
1085444c061aSmrg			   ReqCleanup, (XtPointer) info );
1086444c061aSmrg	if (IsINCRtype(info, XtWindow(widget), event->property)) {
1087444c061aSmrg	    info->proc = HandleGetIncrement;
1088444c061aSmrg	    XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
1089444c061aSmrg			      FALSE, ReqCleanup, (XtPointer) info);
1090444c061aSmrg	} else {
1091444c061aSmrg	   if (event->property != None)
1092444c061aSmrg		XDeleteProperty(event->display, XtWindow(widget),
1093444c061aSmrg				event->property);
1094444c061aSmrg           FreeSelectionProperty(XtDisplay(widget), info->property);
1095444c061aSmrg	   FreeInfo(info);
1096444c061aSmrg	}
1097444c061aSmrg    } else if ((ev->type == PropertyNotify) &&
1098444c061aSmrg		(ev->xproperty.state == PropertyNewValue) &&
1099444c061aSmrg	        (ev->xproperty.atom == info->property)) {
1100444c061aSmrg	XPropertyEvent *event = (XPropertyEvent *) ev;
11019e7bcd65Smrg	char *value = NULL;
11029e7bcd65Smrg	if (XGetWindowProperty(event->display, XtWindow(widget),
11039e7bcd65Smrg			       event->atom, 0L, 1000000, True, AnyPropertyType,
11049e7bcd65Smrg			       &target, &format, &length, &bytesafter,
11059e7bcd65Smrg			       (unsigned char **) &value) == Success) {
11069e7bcd65Smrg	    XFree(value);
11079e7bcd65Smrg	    if (length == 0) {
11089e7bcd65Smrg		XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask,
11099e7bcd65Smrg				     FALSE, ReqCleanup, (XtPointer) info );
11109e7bcd65Smrg		FreeSelectionProperty(XtDisplay(widget), info->property);
11119e7bcd65Smrg		XtFree(info->value); /* requestor never got this, so free now */
11129e7bcd65Smrg		FreeInfo(info);
11139e7bcd65Smrg	    }
1114444c061aSmrg	}
1115444c061aSmrg    }
1116444c061aSmrg}
1117444c061aSmrg
1118444c061aSmrg/* ARGSUSED */
1119444c061aSmrgstatic void ReqTimedOut(
1120444c061aSmrg    XtPointer closure,
1121444c061aSmrg    XtIntervalId   *id)
1122444c061aSmrg{
1123444c061aSmrg    XtPointer value = NULL;
1124444c061aSmrg    unsigned long length = 0;
1125444c061aSmrg    int format = 8;
1126444c061aSmrg    Atom resulttype = XT_CONVERT_FAIL;
1127444c061aSmrg    CallBackInfo info = (CallBackInfo)closure;
1128444c061aSmrg    unsigned long bytesafter;
1129444c061aSmrg    unsigned long proplength;
1130444c061aSmrg    Atom type;
1131444c061aSmrg
1132444c061aSmrg    if (*info->target == info->ctx->prop_list->indirect_atom) {
11339e7bcd65Smrg	IndirectPair *pairs = NULL;
11349e7bcd65Smrg	if (XGetWindowProperty(XtDisplay(info->widget), XtWindow(info->widget),
11359e7bcd65Smrg			       info->property, 0L, 10000000, True,
11369e7bcd65Smrg			       AnyPropertyType, &type, &format, &proplength,
11379e7bcd65Smrg			       &bytesafter, (unsigned char **) &pairs)
11389e7bcd65Smrg	    == Success) {
11390568f49bSmrg	    XtPointer *c;
11400568f49bSmrg	    int i;
11410568f49bSmrg
11429e7bcd65Smrg	    XFree(pairs);
11439e7bcd65Smrg	    for (proplength = proplength / IndirectPairWordSize, i = 0,
11449e7bcd65Smrg		     c = info->req_closure;
11459e7bcd65Smrg		 proplength; proplength--, c++, i++)
11469e7bcd65Smrg		(*info->callbacks[i])(info->widget, *c, &info->ctx->selection,
11479e7bcd65Smrg				      &resulttype, value, &length, &format);
11489e7bcd65Smrg	}
1149444c061aSmrg    } else {
1150444c061aSmrg	(*info->callbacks[0])(info->widget, *info->req_closure,
1151444c061aSmrg	    &info->ctx->selection, &resulttype, value, &length, &format);
1152444c061aSmrg    }
1153444c061aSmrg
1154444c061aSmrg    /* change event handlers for straggler events */
1155444c061aSmrg    if (info->proc == (XtEventHandler)HandleSelectionReplies) {
1156444c061aSmrg        XtRemoveEventHandler(info->widget, (EventMask)0,
1157444c061aSmrg			TRUE, info->proc, (XtPointer) info);
1158444c061aSmrg	XtAddEventHandler(info->widget, (EventMask)0, TRUE,
1159444c061aSmrg		ReqCleanup, (XtPointer) info);
1160444c061aSmrg    } else {
1161444c061aSmrg        XtRemoveEventHandler(info->widget,(EventMask) PropertyChangeMask,
1162444c061aSmrg			FALSE, info->proc, (XtPointer) info);
1163444c061aSmrg	XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
1164444c061aSmrg		FALSE, ReqCleanup, (XtPointer) info);
1165444c061aSmrg    }
1166444c061aSmrg
1167444c061aSmrg}
1168444c061aSmrg
1169444c061aSmrg/*ARGSUSED*/
1170444c061aSmrgstatic void HandleGetIncrement(
1171444c061aSmrg    Widget widget,
1172444c061aSmrg    XtPointer closure,
1173444c061aSmrg    XEvent *ev,
1174444c061aSmrg    Boolean *cont)
1175444c061aSmrg{
1176444c061aSmrg    XPropertyEvent *event = (XPropertyEvent *) ev;
1177444c061aSmrg    CallBackInfo info = (CallBackInfo) closure;
1178444c061aSmrg    Select ctx = info->ctx;
1179444c061aSmrg    char *value;
1180444c061aSmrg    unsigned long bytesafter;
1181444c061aSmrg    unsigned long length;
1182444c061aSmrg    int bad;
1183444c061aSmrg    int n = info->current;
1184444c061aSmrg
1185444c061aSmrg    if ((event->state != PropertyNewValue) || (event->atom != info->property))
1186444c061aSmrg	 return;
1187444c061aSmrg
1188444c061aSmrg    bad = XGetWindowProperty(event->display, XtWindow(widget),
1189444c061aSmrg			     event->atom, 0L,
1190444c061aSmrg			     10000000, True, AnyPropertyType, &info->type,
1191444c061aSmrg			     &info->format, &length, &bytesafter,
1192444c061aSmrg			     (unsigned char **) &value);
1193444c061aSmrg    if (bad)
1194444c061aSmrg      return;
1195444c061aSmrg#ifndef DEBUG_WO_TIMERS
1196444c061aSmrg    XtRemoveTimeOut(info->timeout);
1197444c061aSmrg#endif
1198444c061aSmrg    if (length == 0) {
11990568f49bSmrg       unsigned long u_offset = NUMELEM2(info->offset, info->format);
1200444c061aSmrg       (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection,
1201444c061aSmrg			     &info->type,
1202444c061aSmrg			     (info->offset == 0 ? value : info->value),
1203444c061aSmrg			     &u_offset, &info->format);
1204444c061aSmrg       /* assert ((info->offset != 0) == (info->incremental[n]) */
1205444c061aSmrg       if (info->offset != 0) XFree(value);
1206444c061aSmrg       XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
1207444c061aSmrg		HandleGetIncrement, (XtPointer) info);
1208444c061aSmrg       FreeSelectionProperty(event->display, info->property);
1209444c061aSmrg       FreeInfo(info);
1210444c061aSmrg    } else { /* add increment to collection */
1211444c061aSmrg      if (info->incremental[n]) {
1212444c061aSmrg#ifdef XT_COPY_SELECTION
12130568f49bSmrg	  int size = (int) BYTELENGTH(length, info->format) + 1;
1214444c061aSmrg	  char *tmp = __XtMalloc((Cardinal) size);
12150568f49bSmrg	  (void) memmove(tmp, value, (size_t) size);
1216444c061aSmrg	  XFree(value);
1217444c061aSmrg	  value = tmp;
1218444c061aSmrg#endif
1219444c061aSmrg        (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection,
1220444c061aSmrg			      &info->type, value, &length, &info->format);
1221444c061aSmrg      } else {
12220568f49bSmrg	  int size = (int) BYTELENGTH(length, info->format);
1223444c061aSmrg	  if (info->offset + size > info->bytelength) {
1224444c061aSmrg	      /* allocate enough for this and the next increment */
1225444c061aSmrg	      info->bytelength = info->offset + size * 2;
1226444c061aSmrg	      info->value = XtRealloc(info->value,
1227444c061aSmrg				      (Cardinal) info->bytelength);
1228444c061aSmrg	  }
12290568f49bSmrg	  (void) memmove(&info->value[info->offset], value, (size_t)size);
1230444c061aSmrg	  info->offset += size;
1231444c061aSmrg	  XFree(value);
1232444c061aSmrg      }
1233444c061aSmrg     /* reset timer */
1234444c061aSmrg#ifndef DEBUG_WO_TIMERS
1235444c061aSmrg     {
1236444c061aSmrg     XtAppContext app = XtWidgetToApplicationContext(info->widget);
1237444c061aSmrg     info->timeout = XtAppAddTimeOut(app,
1238444c061aSmrg			 app->selectionTimeout, ReqTimedOut, (XtPointer) info);
1239444c061aSmrg     }
1240444c061aSmrg#endif
1241444c061aSmrg   }
1242444c061aSmrg}
1243444c061aSmrg
1244444c061aSmrg
1245444c061aSmrgstatic void HandleNone(
1246444c061aSmrg    Widget widget,
1247444c061aSmrg    XtSelectionCallbackProc callback,
1248444c061aSmrg    XtPointer closure,
1249444c061aSmrg    Atom selection)
1250444c061aSmrg{
1251444c061aSmrg    unsigned long length = 0;
1252444c061aSmrg    int format = 8;
1253444c061aSmrg    Atom type = None;
1254444c061aSmrg
1255444c061aSmrg    (*callback)(widget, closure, &selection,
1256444c061aSmrg		&type, NULL, &length, &format);
1257444c061aSmrg}
1258444c061aSmrg
1259444c061aSmrg
12600568f49bSmrgstatic unsigned long IncrPropSize(
1261444c061aSmrg     Widget widget,
1262444c061aSmrg     unsigned char* value,
1263444c061aSmrg     int format,
1264444c061aSmrg     unsigned long length)
1265444c061aSmrg{
1266444c061aSmrg    if (format == 32) {
12670568f49bSmrg	unsigned long size;
12680568f49bSmrg	size = ((unsigned long*)value)[length-1]; /* %%% what order for longs? */
1269444c061aSmrg	return size;
1270444c061aSmrg    }
1271444c061aSmrg    else {
1272444c061aSmrg	XtAppWarningMsg( XtWidgetToApplicationContext(widget),
1273444c061aSmrg			"badFormat","xtGetSelectionValue",XtCXtToolkitError,
1274444c061aSmrg	"Selection owner returned type INCR property with format != 32",
12750568f49bSmrg			NULL, NULL );
1276444c061aSmrg	return 0;
1277444c061aSmrg    }
1278444c061aSmrg}
1279444c061aSmrg
1280444c061aSmrg
1281444c061aSmrgstatic
1282444c061aSmrgBoolean HandleNormal(
1283444c061aSmrg    Display *dpy,
1284444c061aSmrg    Widget widget,
1285444c061aSmrg    Atom property,
1286444c061aSmrg    CallBackInfo info,
1287444c061aSmrg    XtPointer closure,
1288444c061aSmrg    Atom selection)
1289444c061aSmrg{
1290444c061aSmrg    unsigned long bytesafter;
1291444c061aSmrg    unsigned long length;
1292444c061aSmrg    int format;
1293444c061aSmrg    Atom type;
12949e7bcd65Smrg    unsigned char *value = NULL;
1295444c061aSmrg    int number = info->current;
1296444c061aSmrg
12979e7bcd65Smrg    if (XGetWindowProperty(dpy, XtWindow(widget), property, 0L, 10000000,
12989e7bcd65Smrg			   False, AnyPropertyType, &type, &format, &length,
12999e7bcd65Smrg			   &bytesafter, &value) != Success)
13009e7bcd65Smrg	return FALSE;
1301444c061aSmrg
1302444c061aSmrg    if (type == info->ctx->prop_list->incr_atom) {
1303444c061aSmrg	unsigned long size = IncrPropSize(widget, value, format, length);
1304444c061aSmrg	XFree((char *)value);
1305444c061aSmrg	if (info->property != property) {
1306444c061aSmrg	    /* within MULTIPLE */
1307444c061aSmrg	    CallBackInfo ninfo;
1308444c061aSmrg	    ninfo = MakeInfo(info->ctx, &info->callbacks[number],
1309444c061aSmrg			     &info->req_closure[number], 1, widget,
1310444c061aSmrg			     info->time, &info->incremental[number], &property);
1311444c061aSmrg	    ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom));
1312444c061aSmrg	    *ninfo->target = info->target[number + 1];
1313444c061aSmrg	    info = ninfo;
1314444c061aSmrg	}
1315444c061aSmrg	HandleIncremental(dpy, widget, property, info, size);
1316444c061aSmrg	return FALSE;
1317444c061aSmrg    }
1318444c061aSmrg
1319444c061aSmrg    XDeleteProperty(dpy, XtWindow(widget), property);
1320444c061aSmrg#ifdef XT_COPY_SELECTION
1321444c061aSmrg    if (value) {   /* it could have been deleted after the SelectionNotify */
13220568f49bSmrg	int size = (int) BYTELENGTH(length, info->format) + 1;
1323444c061aSmrg	char *tmp = __XtMalloc((Cardinal) size);
13240568f49bSmrg	(void) memmove(tmp, value, (size_t) size);
1325444c061aSmrg	XFree(value);
1326444c061aSmrg	value = (unsigned char *) tmp;
1327444c061aSmrg    }
1328444c061aSmrg#endif
1329444c061aSmrg    (*info->callbacks[number])(widget, closure, &selection,
1330444c061aSmrg			       &type, (XtPointer)value, &length, &format);
1331444c061aSmrg
1332444c061aSmrg    if (info->incremental[number]) {
1333444c061aSmrg	/* let requestor know the whole thing has been received */
1334444c061aSmrg	value = (unsigned char*)__XtMalloc((unsigned)1);
1335444c061aSmrg	length = 0;
1336444c061aSmrg	(*info->callbacks[number])(widget, closure, &selection,
1337444c061aSmrg				   &type, (XtPointer)value, &length, &format);
1338444c061aSmrg    }
1339444c061aSmrg    return TRUE;
1340444c061aSmrg}
1341444c061aSmrg
1342444c061aSmrgstatic void HandleIncremental(
1343444c061aSmrg    Display *dpy,
1344444c061aSmrg    Widget widget,
1345444c061aSmrg    Atom property,
1346444c061aSmrg    CallBackInfo info,
1347444c061aSmrg    unsigned long size)
1348444c061aSmrg{
1349444c061aSmrg    XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
1350444c061aSmrg		      HandleGetIncrement, (XtPointer) info);
1351444c061aSmrg
1352444c061aSmrg    /* now start the transfer */
1353444c061aSmrg    XDeleteProperty(dpy, XtWindow(widget), property);
1354444c061aSmrg    XFlush(dpy);
1355444c061aSmrg
13560568f49bSmrg    info->bytelength = (int) size;
1357444c061aSmrg    if (info->incremental[info->current]) /* requestor wants incremental too */
1358444c061aSmrg	info->value = NULL;	/* so no need for buffer to assemble value */
1359444c061aSmrg    else
1360444c061aSmrg	info->value = (char *) __XtMalloc((unsigned) info->bytelength);
1361444c061aSmrg    info->offset = 0;
1362444c061aSmrg
1363444c061aSmrg    /* reset the timer */
1364444c061aSmrg    info->proc = HandleGetIncrement;
1365444c061aSmrg#ifndef DEBUG_WO_TIMERS
1366444c061aSmrg    {
1367444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(info->widget);
1368444c061aSmrg    info->timeout = XtAppAddTimeOut(app,
1369444c061aSmrg			 app->selectionTimeout, ReqTimedOut, (XtPointer) info);
1370444c061aSmrg    }
1371444c061aSmrg#endif
1372444c061aSmrg}
1373444c061aSmrg
1374444c061aSmrg/*ARGSUSED*/
1375444c061aSmrgstatic void HandleSelectionReplies(
1376444c061aSmrg    Widget widget,
1377444c061aSmrg    XtPointer closure,
1378444c061aSmrg    XEvent *ev,
1379444c061aSmrg    Boolean *cont)
1380444c061aSmrg{
1381444c061aSmrg    XSelectionEvent *event = (XSelectionEvent *) ev;
1382444c061aSmrg    Display *dpy = event->display;
1383444c061aSmrg    CallBackInfo info = (CallBackInfo) closure;
1384444c061aSmrg    Select ctx = info->ctx;
1385444c061aSmrg    unsigned long bytesafter;
1386444c061aSmrg    unsigned long length;
1387444c061aSmrg    int format;
1388444c061aSmrg    Atom type;
1389444c061aSmrg
1390444c061aSmrg    if (event->type != SelectionNotify) return;
1391444c061aSmrg    if (!MATCH_SELECT(event, info)) return; /* not really for us */
1392444c061aSmrg#ifndef DEBUG_WO_TIMERS
1393444c061aSmrg    XtRemoveTimeOut(info->timeout);
1394444c061aSmrg#endif
1395444c061aSmrg    XtRemoveEventHandler(widget, (EventMask)0, TRUE,
1396444c061aSmrg		HandleSelectionReplies, (XtPointer) info );
1397444c061aSmrg    if (event->target == ctx->prop_list->indirect_atom) {
13989e7bcd65Smrg       IndirectPair *pairs = NULL, *p;
13990568f49bSmrg       XtPointer *c;
14000568f49bSmrg
14019e7bcd65Smrg       if (XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L,
14029e7bcd65Smrg			      10000000, True, AnyPropertyType, &type, &format,
14039e7bcd65Smrg			      &length, &bytesafter, (unsigned char **) &pairs)
14049e7bcd65Smrg	   != Success)
14059e7bcd65Smrg	   length = 0;
1406444c061aSmrg       for (length = length / IndirectPairWordSize, p = pairs,
1407444c061aSmrg	    c = info->req_closure;
1408444c061aSmrg	    length; length--, p++, c++, info->current++) {
1409444c061aSmrg	    if (event->property == None || format != 32 || p->target == None
1410444c061aSmrg		|| /* bug compatibility */ p->property == None) {
1411444c061aSmrg		HandleNone(widget, info->callbacks[info->current],
1412444c061aSmrg			   *c, event->selection);
1413444c061aSmrg		if (p->property != None)
1414444c061aSmrg                    FreeSelectionProperty(XtDisplay(widget), p->property);
1415444c061aSmrg	    } else {
1416444c061aSmrg		if (HandleNormal(dpy, widget, p->property, info, *c,
1417444c061aSmrg				 event->selection)) {
1418444c061aSmrg		    FreeSelectionProperty(XtDisplay(widget), p->property);
1419444c061aSmrg		}
1420444c061aSmrg	    }
1421444c061aSmrg       }
1422444c061aSmrg       XFree((char*)pairs);
1423444c061aSmrg       FreeSelectionProperty(dpy, info->property);
1424444c061aSmrg       FreeInfo(info);
1425444c061aSmrg    } else if (event->property == None) {
1426444c061aSmrg	HandleNone(widget, info->callbacks[0], *info->req_closure, event->selection);
1427444c061aSmrg        FreeSelectionProperty(XtDisplay(widget), info->property);
1428444c061aSmrg	FreeInfo(info);
1429444c061aSmrg    } else {
1430444c061aSmrg	if (HandleNormal(dpy, widget, event->property, info,
1431444c061aSmrg			 *info->req_closure, event->selection)) {
1432444c061aSmrg	    FreeSelectionProperty(XtDisplay(widget), info->property);
1433444c061aSmrg	    FreeInfo(info);
1434444c061aSmrg	}
1435444c061aSmrg    }
1436444c061aSmrg}
1437444c061aSmrg
1438444c061aSmrgstatic void DoLocalTransfer(
1439444c061aSmrg    Request req,
1440444c061aSmrg    Atom selection,
1441444c061aSmrg    Atom target,
1442444c061aSmrg    Widget widget,		/* The widget requesting the value. */
1443444c061aSmrg    XtSelectionCallbackProc callback,
1444444c061aSmrg    XtPointer closure,	/* the closure for the callback, not the conversion */
1445444c061aSmrg    Boolean incremental,
1446444c061aSmrg    Atom property)
1447444c061aSmrg{
1448444c061aSmrg    Select ctx = req->ctx;
1449444c061aSmrg    XtPointer value = NULL, temp, total = NULL;
1450444c061aSmrg    unsigned long length;
1451444c061aSmrg    int format;
1452444c061aSmrg    Atom resulttype;
1453444c061aSmrg    unsigned long totallength = 0;
1454444c061aSmrg
1455444c061aSmrg        req->event.type = 0;
1456444c061aSmrg        req->event.target = target;
1457444c061aSmrg        req->event.property = req->property = property;
1458444c061aSmrg        req->event.requestor = req->requestor = XtWindow(widget);
1459444c061aSmrg
1460444c061aSmrg	if (ctx->incremental) {
14610568f49bSmrg	   unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy);
1462444c061aSmrg	   if (!(*(XtConvertSelectionIncrProc)ctx->convert)
1463444c061aSmrg			   (ctx->widget, &selection, &target,
1464444c061aSmrg			    &resulttype, &value, &length, &format,
1465444c061aSmrg			    &size, ctx->owner_closure, (XtRequestId*)&req)) {
1466444c061aSmrg	       HandleNone(widget, callback, closure, selection);
1467444c061aSmrg	   }
1468444c061aSmrg	   else {
1469444c061aSmrg		if (incremental) {
1470444c061aSmrg		  Boolean allSent = FALSE;
1471444c061aSmrg	          while (!allSent) {
1472444c061aSmrg	    	      if (ctx->notify && (value != NULL)) {
14730568f49bSmrg              	        int bytelength = (int) BYTELENGTH(length,format);
1474444c061aSmrg	                /* both sides think they own this storage */
1475444c061aSmrg	                temp = __XtMalloc((unsigned)bytelength);
14760568f49bSmrg	                (void) memmove(temp, value, (size_t) bytelength);
1477444c061aSmrg	                value = temp;
1478444c061aSmrg	              }
1479444c061aSmrg		      /* use care; older clients were never warned that
1480444c061aSmrg		       * they must return a value even if length==0
1481444c061aSmrg		       */
1482444c061aSmrg		     if (value == NULL) value = __XtMalloc((unsigned)1);
1483444c061aSmrg		     (*callback)(widget, closure, &selection,
1484444c061aSmrg			&resulttype, value, &length, &format);
1485444c061aSmrg		     if (length) {
1486444c061aSmrg			 /* should owner be notified on end-of-piece?
1487444c061aSmrg			  * Spec is unclear, but non-local transfers don't.
1488444c061aSmrg			  */
1489444c061aSmrg			 (*(XtConvertSelectionIncrProc)ctx->convert)
1490444c061aSmrg					(ctx->widget, &selection, &target,
1491444c061aSmrg					 &resulttype, &value, &length, &format,
1492444c061aSmrg					 &size, ctx->owner_closure,
1493444c061aSmrg					 (XtRequestId*)&req);
1494444c061aSmrg		     }
1495444c061aSmrg		     else allSent = TRUE;
1496444c061aSmrg		  }
1497444c061aSmrg	        } else {
1498444c061aSmrg	          while (length) {
14990568f49bSmrg		    int bytelength = (int) BYTELENGTH(length, format);
1500444c061aSmrg		    total = XtRealloc(total,
15010568f49bSmrg			    (Cardinal) (totallength = totallength + (unsigned long)bytelength));
1502444c061aSmrg		    (void) memmove((char*)total + totallength - bytelength,
1503444c061aSmrg			    value,
15040568f49bSmrg			    (size_t) bytelength);
1505444c061aSmrg		    (*(XtConvertSelectionIncrProc)ctx->convert)
1506444c061aSmrg			   (ctx->widget, &selection, &target,
1507444c061aSmrg			    &resulttype, &value, &length, &format,
1508444c061aSmrg			    &size, ctx->owner_closure, (XtRequestId*)&req);
1509444c061aSmrg		  }
1510444c061aSmrg		  if (total == NULL) total = __XtMalloc(1);
15110568f49bSmrg		  totallength = NUMELEM2(totallength, format);
1512444c061aSmrg		  (*callback)(widget, closure, &selection, &resulttype,
1513444c061aSmrg		    total,  &totallength, &format);
1514444c061aSmrg	      }
1515444c061aSmrg	      if (ctx->notify)
1516444c061aSmrg		  (*(XtSelectionDoneIncrProc)ctx->notify)
1517444c061aSmrg				(ctx->widget, &selection, &target,
1518444c061aSmrg				 (XtRequestId*)&req, ctx->owner_closure);
1519444c061aSmrg	      else XtFree((char*)value);
1520444c061aSmrg	  }
1521444c061aSmrg	} else { /* not incremental owner */
1522444c061aSmrg	  if (!(*ctx->convert)(ctx->widget, &selection, &target,
1523444c061aSmrg			     &resulttype, &value, &length, &format)) {
1524444c061aSmrg	    HandleNone(widget, callback, closure, selection);
1525444c061aSmrg	  } else {
1526444c061aSmrg	      if (ctx->notify && (value != NULL)) {
15270568f49bSmrg                int bytelength = (int) BYTELENGTH(length,format);
1528444c061aSmrg	        /* both sides think they own this storage; better copy */
1529444c061aSmrg	        temp = __XtMalloc((unsigned)bytelength);
15300568f49bSmrg	        (void) memmove(temp, value, (size_t) bytelength);
1531444c061aSmrg	        value = temp;
1532444c061aSmrg	      }
1533444c061aSmrg	      if (value == NULL) value = __XtMalloc((unsigned)1);
1534444c061aSmrg	      (*callback)(widget, closure, &selection, &resulttype,
1535444c061aSmrg			  value, &length, &format);
1536444c061aSmrg	      if (ctx->notify)
1537444c061aSmrg	         (*ctx->notify)(ctx->widget, &selection, &target);
1538444c061aSmrg	  }
1539444c061aSmrg      }
1540444c061aSmrg}
1541444c061aSmrg
1542444c061aSmrgstatic void GetSelectionValue(
1543444c061aSmrg    Widget widget,
1544444c061aSmrg    Atom selection,
1545444c061aSmrg    Atom target,
1546444c061aSmrg    XtSelectionCallbackProc callback,
1547444c061aSmrg    XtPointer closure,
1548444c061aSmrg    Time time,
1549444c061aSmrg    Boolean incremental,
1550444c061aSmrg    Atom property)
1551444c061aSmrg{
1552444c061aSmrg    Select ctx;
1553444c061aSmrg    Atom properties[1];
1554444c061aSmrg
1555444c061aSmrg    properties[0] = property;
1556444c061aSmrg
1557444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1558444c061aSmrg    if (ctx->widget && !ctx->was_disowned) {
1559444c061aSmrg	RequestRec req;
1560444c061aSmrg	ctx->req = &req;
1561444c061aSmrg	req.ctx = ctx;
1562444c061aSmrg	req.event.time = time;
1563444c061aSmrg	ctx->ref_count++;
1564444c061aSmrg	DoLocalTransfer(&req, selection, target, widget,
1565444c061aSmrg			callback, closure, incremental, property);
1566444c061aSmrg	if (--ctx->ref_count == 0 && ctx->free_when_done)
1567444c061aSmrg	    XtFree((char*)ctx);
1568444c061aSmrg	else
1569444c061aSmrg	    ctx->req = NULL;
1570444c061aSmrg    }
1571444c061aSmrg    else {
15720568f49bSmrg	CallBackInfo info;
1573444c061aSmrg	info = MakeInfo(ctx, &callback, &closure, 1, widget,
1574444c061aSmrg			time, &incremental, properties);
1575444c061aSmrg	info->target = (Atom *)__XtMalloc((unsigned) sizeof(Atom));
1576444c061aSmrg	 *(info->target) = target;
1577444c061aSmrg	RequestSelectionValue(info, selection, target);
1578444c061aSmrg    }
1579444c061aSmrg}
1580444c061aSmrg
1581444c061aSmrg
1582444c061aSmrgvoid XtGetSelectionValue(
1583444c061aSmrg    Widget widget,
1584444c061aSmrg    Atom selection,
1585444c061aSmrg    Atom target,
1586444c061aSmrg    XtSelectionCallbackProc callback,
1587444c061aSmrg    XtPointer closure,
1588444c061aSmrg    Time time)
1589444c061aSmrg{
1590444c061aSmrg    Atom property;
1591444c061aSmrg    Boolean incr = False;
1592444c061aSmrg    WIDGET_TO_APPCON(widget);
1593444c061aSmrg
1594444c061aSmrg    LOCK_APP(app);
1595444c061aSmrg    property = GetParamInfo(widget, selection);
1596444c061aSmrg    RemoveParamInfo(widget, selection);
1597444c061aSmrg
1598444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1599444c061aSmrg      AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
1600444c061aSmrg			   &closure, &incr, &property);
1601444c061aSmrg    } else {
1602444c061aSmrg      GetSelectionValue(widget, selection, target, callback,
1603444c061aSmrg			closure, time, FALSE, property);
1604444c061aSmrg    }
1605444c061aSmrg    UNLOCK_APP(app);
1606444c061aSmrg}
1607444c061aSmrg
1608444c061aSmrg
1609444c061aSmrgvoid XtGetSelectionValueIncremental(
1610444c061aSmrg    Widget widget,
1611444c061aSmrg    Atom selection,
1612444c061aSmrg    Atom target,
1613444c061aSmrg    XtSelectionCallbackProc callback,
1614444c061aSmrg    XtPointer closure,
1615444c061aSmrg    Time time)
1616444c061aSmrg{
1617444c061aSmrg    Atom property;
1618444c061aSmrg    Boolean incr = TRUE;
1619444c061aSmrg    WIDGET_TO_APPCON(widget);
1620444c061aSmrg
1621444c061aSmrg    LOCK_APP(app);
1622444c061aSmrg    property = GetParamInfo(widget, selection);
1623444c061aSmrg    RemoveParamInfo(widget, selection);
1624444c061aSmrg
1625444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1626444c061aSmrg      AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
1627444c061aSmrg			   &closure, &incr, &property);
1628444c061aSmrg    } else {
1629444c061aSmrg      GetSelectionValue(widget, selection, target, callback,
1630444c061aSmrg			closure, time, TRUE, property);
1631444c061aSmrg    }
1632444c061aSmrg
1633444c061aSmrg    UNLOCK_APP(app);
1634444c061aSmrg}
1635444c061aSmrg
1636444c061aSmrg
1637444c061aSmrgstatic void GetSelectionValues(
1638444c061aSmrg    Widget widget,
1639444c061aSmrg    Atom selection,
1640444c061aSmrg    Atom *targets,
1641444c061aSmrg    int count,
1642444c061aSmrg    XtSelectionCallbackProc *callbacks,
1643444c061aSmrg    int num_callbacks,
1644444c061aSmrg    XtPointer *closures,
1645444c061aSmrg    Time time,
1646444c061aSmrg    Boolean *incremental,
1647444c061aSmrg    Atom *properties)
1648444c061aSmrg{
1649444c061aSmrg    Select ctx;
16500568f49bSmrg    IndirectPair *pairs;
1651444c061aSmrg
1652444c061aSmrg    if (count == 0) return;
1653444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1654444c061aSmrg    if (ctx->widget && !ctx->was_disowned) {
1655444c061aSmrg        int j, i;
1656444c061aSmrg	RequestRec req;
1657444c061aSmrg	ctx->req = &req;
1658444c061aSmrg	req.ctx = ctx;
1659444c061aSmrg	req.event.time = time;
1660444c061aSmrg	ctx->ref_count++;
1661444c061aSmrg	for (i = 0, j = 0; count; count--, i++, j++ ) {
1662444c061aSmrg	  if (j >= num_callbacks) j = 0;
1663444c061aSmrg
1664444c061aSmrg	  DoLocalTransfer(&req, selection, targets[i], widget,
1665444c061aSmrg			  callbacks[j], closures[i], incremental[i],
1666444c061aSmrg			  properties ? properties[i] : None);
1667444c061aSmrg
1668444c061aSmrg	}
1669444c061aSmrg	if (--ctx->ref_count == 0 && ctx->free_when_done)
1670444c061aSmrg	    XtFree((char*)ctx);
1671444c061aSmrg	else
1672444c061aSmrg	    ctx->req = NULL;
1673444c061aSmrg    } else {
1674444c061aSmrg        XtSelectionCallbackProc *passed_callbacks;
1675444c061aSmrg	XtSelectionCallbackProc stack_cbs[32];
16760568f49bSmrg	CallBackInfo info;
16770568f49bSmrg	IndirectPair *p;
16780568f49bSmrg	Atom *t;
1679444c061aSmrg        int i = 0, j = 0;
1680444c061aSmrg
1681444c061aSmrg	passed_callbacks = (XtSelectionCallbackProc *)
16820568f49bSmrg	  XtStackAlloc(sizeof(XtSelectionCallbackProc) * (size_t)count, stack_cbs);
1683444c061aSmrg
1684444c061aSmrg	/* To deal with the old calls from XtGetSelectionValues* we
1685444c061aSmrg	   will repeat however many callbacks have been passed into
1686444c061aSmrg	   the array */
1687444c061aSmrg	for(i = 0; i < count; i++) {
1688444c061aSmrg	  if (j >= num_callbacks) j = 0;
1689444c061aSmrg	  passed_callbacks[i] = callbacks[j];
1690444c061aSmrg	  j++;
1691444c061aSmrg	}
1692444c061aSmrg	info = MakeInfo(ctx, passed_callbacks, closures, count, widget,
1693444c061aSmrg			time, incremental, properties);
1694444c061aSmrg	XtStackFree((XtPointer) passed_callbacks, stack_cbs);
1695444c061aSmrg
16960568f49bSmrg	info->target = (Atom *)__XtMalloc((unsigned) ((size_t)(count+1) * sizeof(Atom)));
1697444c061aSmrg        (*info->target) = ctx->prop_list->indirect_atom;
1698444c061aSmrg	(void) memmove((char *) info->target+sizeof(Atom), (char *) targets,
16990568f49bSmrg		       (size_t) count * sizeof(Atom));
17000568f49bSmrg	pairs = (IndirectPair*)__XtMalloc((unsigned)((size_t)count*sizeof(IndirectPair)));
1701444c061aSmrg	for (p = &pairs[count-1], t = &targets[count-1], i = count - 1;
1702444c061aSmrg	     p >= pairs;  p--, t--, i--) {
1703444c061aSmrg	   p->target = *t;
1704444c061aSmrg	   if (properties == NULL || properties[i] == None) {
1705444c061aSmrg	     p->property = GetSelectionProperty(XtDisplay(widget));
1706444c061aSmrg	     XDeleteProperty(XtDisplay(widget), XtWindow(widget),
1707444c061aSmrg			     p->property);
1708444c061aSmrg	   } else {
1709444c061aSmrg	     p->property = properties[i];
1710444c061aSmrg	   }
1711444c061aSmrg	}
1712444c061aSmrg	XChangeProperty(XtDisplay(widget), XtWindow(widget),
1713444c061aSmrg			info->property, info->property,
1714444c061aSmrg			32, PropModeReplace, (unsigned char *) pairs,
1715444c061aSmrg			count * IndirectPairWordSize);
1716444c061aSmrg	XtFree((char*)pairs);
1717444c061aSmrg	RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom);
1718444c061aSmrg    }
1719444c061aSmrg}
1720444c061aSmrg
1721444c061aSmrg
1722444c061aSmrgvoid XtGetSelectionValues(
1723444c061aSmrg    Widget widget,
1724444c061aSmrg    Atom selection,
1725444c061aSmrg    Atom *targets,
1726444c061aSmrg    int count,
1727444c061aSmrg    XtSelectionCallbackProc callback,
1728444c061aSmrg    XtPointer *closures,
1729444c061aSmrg    Time time)
1730444c061aSmrg{
1731444c061aSmrg    Boolean incremental_values[32];
1732444c061aSmrg    Boolean *incremental;
1733444c061aSmrg    int i;
1734444c061aSmrg    WIDGET_TO_APPCON(widget);
1735444c061aSmrg
1736444c061aSmrg    LOCK_APP(app);
17370568f49bSmrg    incremental = XtStackAlloc((size_t)count * sizeof(Boolean), incremental_values);
1738444c061aSmrg    for(i = 0; i < count; i++) incremental[i] = FALSE;
1739444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1740444c061aSmrg      AddSelectionRequests(widget, selection, count, targets, &callback,
1741444c061aSmrg			   1, closures, incremental, NULL);
1742444c061aSmrg    } else {
1743444c061aSmrg      GetSelectionValues(widget, selection, targets, count, &callback, 1,
1744444c061aSmrg			 closures, time, incremental, NULL);
1745444c061aSmrg    }
1746444c061aSmrg    XtStackFree((XtPointer) incremental, incremental_values);
1747444c061aSmrg    UNLOCK_APP(app);
1748444c061aSmrg}
1749444c061aSmrg
1750444c061aSmrg
1751444c061aSmrgvoid XtGetSelectionValuesIncremental(
1752444c061aSmrg    Widget widget,
1753444c061aSmrg    Atom selection,
1754444c061aSmrg    Atom *targets,
1755444c061aSmrg    int count,
1756444c061aSmrg    XtSelectionCallbackProc callback,
1757444c061aSmrg    XtPointer *closures,
1758444c061aSmrg    Time time)
1759444c061aSmrg{
1760444c061aSmrg    Boolean incremental_values[32];
1761444c061aSmrg    Boolean *incremental;
1762444c061aSmrg    int i;
1763444c061aSmrg    WIDGET_TO_APPCON(widget);
1764444c061aSmrg
1765444c061aSmrg    LOCK_APP(app);
17660568f49bSmrg    incremental = XtStackAlloc((size_t)count * sizeof(Boolean), incremental_values);
1767444c061aSmrg    for(i = 0; i < count; i++) incremental[i] = TRUE;
1768444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1769444c061aSmrg      AddSelectionRequests(widget, selection, count, targets, &callback,
1770444c061aSmrg			   1, closures, incremental, NULL);
1771444c061aSmrg    } else {
1772444c061aSmrg      GetSelectionValues(widget, selection, targets, count,
1773444c061aSmrg			 &callback, 1, closures, time, incremental, NULL);
1774444c061aSmrg    }
1775444c061aSmrg    XtStackFree((XtPointer) incremental, incremental_values);
1776444c061aSmrg    UNLOCK_APP(app);
1777444c061aSmrg}
1778444c061aSmrg
1779444c061aSmrg
1780444c061aSmrgstatic Request GetRequestRecord(
1781444c061aSmrg    Widget widget,
1782444c061aSmrg    Atom selection,
1783444c061aSmrg    XtRequestId id)
1784444c061aSmrg{
1785444c061aSmrg    Request req = (Request)id;
1786444c061aSmrg    Select ctx = NULL;
1787444c061aSmrg
1788444c061aSmrg    if (   (req == NULL
1789444c061aSmrg	    && ((ctx = FindCtx( XtDisplay(widget), selection )) == NULL
1790444c061aSmrg		|| ctx->req == NULL
1791444c061aSmrg		|| ctx->selection != selection
1792444c061aSmrg		|| ctx->widget == NULL))
1793444c061aSmrg	|| (req != NULL
1794444c061aSmrg	    && (req->ctx == NULL
1795444c061aSmrg		|| req->ctx->selection != selection
1796444c061aSmrg		|| req->ctx->widget != widget)))
1797444c061aSmrg    {
1798444c061aSmrg	String params = XtName(widget);
1799444c061aSmrg	Cardinal num_params = 1;
1800444c061aSmrg	XtAppWarningMsg(XtWidgetToApplicationContext(widget),
1801444c061aSmrg			 "notInConvertSelection", "xtGetSelectionRequest",
1802444c061aSmrg			 XtCXtToolkitError,
1803444c061aSmrg			 "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc",
1804444c061aSmrg			 &params, &num_params
1805444c061aSmrg		       );
1806444c061aSmrg	return NULL;
1807444c061aSmrg    }
1808444c061aSmrg
1809444c061aSmrg    if (req == NULL) {
1810444c061aSmrg	/* non-incremental owner; only one request can be
1811444c061aSmrg	 * outstanding at a time, so it's safe to keep ptr in ctx */
1812444c061aSmrg	req = ctx->req;
1813444c061aSmrg    }
1814444c061aSmrg    return req;
1815444c061aSmrg}
1816444c061aSmrg
1817444c061aSmrgXSelectionRequestEvent *XtGetSelectionRequest(
1818444c061aSmrg    Widget widget,
1819444c061aSmrg    Atom selection,
1820444c061aSmrg    XtRequestId id)
1821444c061aSmrg{
1822444c061aSmrg    Request req = (Request)id;
1823444c061aSmrg    WIDGET_TO_APPCON(widget);
1824444c061aSmrg
1825444c061aSmrg    LOCK_APP(app);
1826444c061aSmrg
1827444c061aSmrg    req = GetRequestRecord(widget, selection, id);
1828444c061aSmrg
1829444c061aSmrg    if (! req) {
1830444c061aSmrg	UNLOCK_APP(app);
1831444c061aSmrg	return (XSelectionRequestEvent*) NULL;
1832444c061aSmrg    }
1833444c061aSmrg
1834444c061aSmrg    if (req->event.type == 0) {
1835444c061aSmrg	/* owner is local; construct the remainder of the event */
1836444c061aSmrg	req->event.type = SelectionRequest;
1837444c061aSmrg	req->event.serial = LastKnownRequestProcessed(XtDisplay(widget));
1838444c061aSmrg	req->event.send_event = True;
1839444c061aSmrg	req->event.display = XtDisplay(widget);
1840444c061aSmrg	req->event.owner = XtWindow(req->ctx->widget);
1841444c061aSmrg	req->event.selection = selection;
1842444c061aSmrg    }
1843444c061aSmrg    UNLOCK_APP(app);
1844444c061aSmrg    return &req->event;
1845444c061aSmrg}
1846444c061aSmrg
1847444c061aSmrg/* Property atom access */
1848444c061aSmrgAtom XtReservePropertyAtom(
1849444c061aSmrg     Widget w)
1850444c061aSmrg{
1851444c061aSmrg  return(GetSelectionProperty(XtDisplay(w)));
1852444c061aSmrg}
1853444c061aSmrg
1854444c061aSmrgvoid XtReleasePropertyAtom(
1855444c061aSmrg     Widget w,
1856444c061aSmrg     Atom atom)
1857444c061aSmrg{
1858444c061aSmrg  FreeSelectionProperty(XtDisplay(w), atom);
1859444c061aSmrg}
1860444c061aSmrg
1861444c061aSmrg
1862444c061aSmrg/* Multiple utilities */
1863444c061aSmrg
1864444c061aSmrg/* All requests are put in a single list per widget.  It is
1865444c061aSmrg   very unlikely anyone will be gathering multiple MULTIPLE
1866444c061aSmrg   requests at the same time,  so the loss in efficiency for
1867444c061aSmrg   this case is acceptable */
1868444c061aSmrg
1869444c061aSmrg/* Queue one or more requests to the one we're gathering */
1870444c061aSmrgstatic void AddSelectionRequests(
1871444c061aSmrg     Widget wid,
1872444c061aSmrg     Atom sel,
1873444c061aSmrg     int count,
1874444c061aSmrg     Atom *targets,
1875444c061aSmrg     XtSelectionCallbackProc *callbacks,
1876444c061aSmrg     int num_cb,
1877444c061aSmrg     XtPointer *closures,
1878444c061aSmrg     Boolean *incrementals,
1879444c061aSmrg     Atom *properties)
1880444c061aSmrg{
1881444c061aSmrg  QueuedRequestInfo qi;
1882444c061aSmrg  Window window = XtWindow(wid);
1883444c061aSmrg  Display *dpy = XtDisplay(wid);
1884444c061aSmrg
1885444c061aSmrg  LOCK_PROCESS;
1886444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
1887444c061aSmrg
1888444c061aSmrg  qi = NULL;
1889444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi);
1890444c061aSmrg
1891444c061aSmrg  if (qi != NULL) {
1892444c061aSmrg    QueuedRequest *req = qi->requests;
1893444c061aSmrg    int start = qi->count;
1894444c061aSmrg    int i = 0;
1895444c061aSmrg    int j = 0;
1896444c061aSmrg
1897444c061aSmrg    qi->count += count;
1898444c061aSmrg    req = (QueuedRequest*) XtRealloc((char*) req,
18990568f49bSmrg				     (Cardinal)((size_t)(start + count) *
19000568f49bSmrg				     sizeof(QueuedRequest)));
1901444c061aSmrg    while(i < count) {
1902444c061aSmrg      QueuedRequest newreq = (QueuedRequest)
1903444c061aSmrg	__XtMalloc(sizeof(QueuedRequestRec));
1904444c061aSmrg      newreq->selection = sel;
1905444c061aSmrg      newreq->target = targets[i];
1906444c061aSmrg      if (properties != NULL)
1907444c061aSmrg	newreq->param = properties[i];
1908444c061aSmrg      else {
1909444c061aSmrg	newreq->param = GetSelectionProperty(dpy);
1910444c061aSmrg	XDeleteProperty(dpy, window, newreq->param);
1911444c061aSmrg      }
1912444c061aSmrg      newreq->callback = callbacks[j];
1913444c061aSmrg      newreq->closure = closures[i];
1914444c061aSmrg      newreq->incremental = incrementals[i];
1915444c061aSmrg
1916444c061aSmrg      req[start] = newreq;
1917444c061aSmrg      start++;
1918444c061aSmrg      i++;
1919444c061aSmrg      j++;
1920444c061aSmrg      if (j > num_cb) j = 0;
1921444c061aSmrg    }
1922444c061aSmrg
1923444c061aSmrg    qi->requests = req;
1924444c061aSmrg  } else {
1925444c061aSmrg    /* Impossible */
1926444c061aSmrg  }
1927444c061aSmrg
1928444c061aSmrg  UNLOCK_PROCESS;
1929444c061aSmrg}
1930444c061aSmrg
1931444c061aSmrg/* Only call IsGatheringRequest when we have a lock already */
1932444c061aSmrg
1933444c061aSmrgstatic Boolean IsGatheringRequest(
1934444c061aSmrg     Widget wid,
1935444c061aSmrg     Atom sel)
1936444c061aSmrg{
1937444c061aSmrg  QueuedRequestInfo qi;
1938444c061aSmrg  Window window = XtWindow(wid);
1939444c061aSmrg  Display *dpy = XtDisplay(wid);
1940444c061aSmrg  Boolean found = False;
1941444c061aSmrg
1942444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
1943444c061aSmrg
1944444c061aSmrg  qi = NULL;
1945444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi);
1946444c061aSmrg
1947444c061aSmrg  if (qi != NULL) {
19480568f49bSmrg    int i = 0;
1949444c061aSmrg    while(qi->selections[i] != None) {
1950444c061aSmrg      if (qi->selections[i] == sel) {
1951444c061aSmrg	found = True;
1952444c061aSmrg	break;
1953444c061aSmrg      }
1954444c061aSmrg      i++;
1955444c061aSmrg    }
1956444c061aSmrg  }
1957444c061aSmrg
1958444c061aSmrg  return(found);
1959444c061aSmrg}
1960444c061aSmrg
1961444c061aSmrg/* Cleanup request scans the request queue and releases any
1962444c061aSmrg   properties queued, and removes any requests queued */
1963444c061aSmrgstatic void CleanupRequest(
1964444c061aSmrg     Display *dpy,
1965444c061aSmrg     QueuedRequestInfo qi,
1966444c061aSmrg     Atom sel)
1967444c061aSmrg{
1968444c061aSmrg  int i, j, n;
1969444c061aSmrg
1970444c061aSmrg  i = 0;
1971444c061aSmrg
1972444c061aSmrg  /* Remove this selection from the list */
1973444c061aSmrg  n = 0;
1974444c061aSmrg  while(qi->selections[n] != sel &&
1975444c061aSmrg	qi->selections[n] != None) n++;
1976444c061aSmrg  if (qi->selections[n] == sel) {
1977444c061aSmrg    while(qi->selections[n] != None) {
1978444c061aSmrg      qi->selections[n] = qi->selections[n + 1];
1979444c061aSmrg      n++;
1980444c061aSmrg    }
1981444c061aSmrg  }
1982444c061aSmrg
1983444c061aSmrg  while(i < qi->count) {
1984444c061aSmrg    QueuedRequest req = qi->requests[i];
1985444c061aSmrg
1986444c061aSmrg    if (req->selection == sel) {
1987444c061aSmrg      /* Match */
1988444c061aSmrg      if (req->param != None)
1989444c061aSmrg	FreeSelectionProperty(dpy, req->param);
1990444c061aSmrg      qi->count--;
1991444c061aSmrg
1992444c061aSmrg      for(j = i; j < qi->count; j++)
1993444c061aSmrg	qi->requests[j] = qi->requests[j + 1];
1994444c061aSmrg
1995444c061aSmrg      XtFree((char*) req);
1996444c061aSmrg    } else {
1997444c061aSmrg      i++;
1998444c061aSmrg    }
1999444c061aSmrg  }
2000444c061aSmrg}
2001444c061aSmrg
20022265a131Smrgvoid XtCreateSelectionRequest(
2003444c061aSmrg    Widget widget,
2004444c061aSmrg    Atom selection)
2005444c061aSmrg{
2006444c061aSmrg  QueuedRequestInfo queueInfo;
2007444c061aSmrg  Window window = XtWindow(widget);
2008444c061aSmrg  Display *dpy = XtDisplay(widget);
2009444c061aSmrg  int n;
2010444c061aSmrg
2011444c061aSmrg  LOCK_PROCESS;
2012444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
2013444c061aSmrg
2014444c061aSmrg  queueInfo = NULL;
2015444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
2016444c061aSmrg
2017444c061aSmrg  /* If there is one,  then cancel it */
20182265a131Smrg  if (queueInfo != NULL)
2019444c061aSmrg    CleanupRequest(dpy, queueInfo, selection);
2020444c061aSmrg  else {
2021444c061aSmrg    /* Create it */
2022444c061aSmrg    queueInfo = (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec));
2023444c061aSmrg    queueInfo->count = 0;
2024444c061aSmrg    queueInfo->selections = (Atom*) __XtMalloc(sizeof(Atom) * 2);
2025444c061aSmrg    queueInfo->selections[0] = None;
2026444c061aSmrg    queueInfo->requests = (QueuedRequest *)
2027444c061aSmrg      __XtMalloc(sizeof(QueuedRequest));
2028444c061aSmrg  }
2029444c061aSmrg
2030444c061aSmrg  /* Append this selection to list */
2031444c061aSmrg  n = 0;
2032444c061aSmrg  while(queueInfo->selections[n] != None) n++;
2033444c061aSmrg  queueInfo->selections =
2034444c061aSmrg    (Atom*) XtRealloc((char*) queueInfo->selections,
20350568f49bSmrg		      (Cardinal)((size_t)(n + 2) * sizeof(Atom)));
2036444c061aSmrg  queueInfo->selections[n] = selection;
2037444c061aSmrg  queueInfo->selections[n + 1] = None;
2038444c061aSmrg
2039444c061aSmrg  (void) XSaveContext(dpy, window, multipleContext, (char*) queueInfo);
2040444c061aSmrg  UNLOCK_PROCESS;
2041444c061aSmrg}
2042444c061aSmrg
20432265a131Smrgvoid XtSendSelectionRequest(
2044444c061aSmrg    Widget widget,
2045444c061aSmrg    Atom selection,
2046444c061aSmrg    Time time)
2047444c061aSmrg{
2048444c061aSmrg  QueuedRequestInfo queueInfo;
2049444c061aSmrg  Window window = XtWindow(widget);
2050444c061aSmrg  Display *dpy = XtDisplay(widget);
2051444c061aSmrg
2052444c061aSmrg  LOCK_PROCESS;
2053444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
2054444c061aSmrg
2055444c061aSmrg  queueInfo = NULL;
2056444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
2057444c061aSmrg  if (queueInfo != NULL) {
2058444c061aSmrg    int i;
20590568f49bSmrg    int count = 0;
2060444c061aSmrg    QueuedRequest *req = queueInfo->requests;
2061444c061aSmrg
2062444c061aSmrg    /* Construct the requests and send it using
2063444c061aSmrg       GetSelectionValues */
2064444c061aSmrg    for(i = 0; i < queueInfo->count; i++)
2065444c061aSmrg      if (req[i]->selection == selection) count++;
2066444c061aSmrg
2067444c061aSmrg    if (count > 0) {
2068444c061aSmrg      if (count == 1) {
2069444c061aSmrg	for(i = 0; i < queueInfo->count; i++)
2070444c061aSmrg	  if (req[i]->selection == selection) break;
2071444c061aSmrg
2072444c061aSmrg	/* special case a multiple which isn't needed */
2073444c061aSmrg	GetSelectionValue(widget, selection, req[i]->target,
2074444c061aSmrg			  req[i]->callback, req[i]->closure, time,
2075444c061aSmrg			  req[i]->incremental, req[i]->param);
2076444c061aSmrg      } else {
2077444c061aSmrg	Atom *targets;
2078444c061aSmrg	Atom t[PREALLOCED];
2079444c061aSmrg	XtSelectionCallbackProc *cbs;
2080444c061aSmrg	XtSelectionCallbackProc c[PREALLOCED];
2081444c061aSmrg	XtPointer *closures;
2082444c061aSmrg	XtPointer cs[PREALLOCED];
2083444c061aSmrg	Boolean *incrs;
2084444c061aSmrg	Boolean ins[PREALLOCED];
2085444c061aSmrg	Atom *props;
2086444c061aSmrg	Atom p[PREALLOCED];
2087444c061aSmrg	int j = 0;
2088444c061aSmrg
2089444c061aSmrg	/* Allocate */
20900568f49bSmrg	targets = (Atom *) XtStackAlloc((size_t)count * sizeof(Atom), t);
2091444c061aSmrg	cbs = (XtSelectionCallbackProc *)
20920568f49bSmrg	  XtStackAlloc((size_t)count * sizeof(XtSelectionCallbackProc), c);
20930568f49bSmrg	closures = (XtPointer *) XtStackAlloc((size_t)count * sizeof(XtPointer), cs);
20940568f49bSmrg	incrs = (Boolean *) XtStackAlloc((size_t)count * sizeof(Boolean), ins);
20950568f49bSmrg	props = (Atom *) XtStackAlloc((size_t)count * sizeof(Atom), p);
2096444c061aSmrg
2097444c061aSmrg	/* Copy */
2098444c061aSmrg	for(i = 0; i < queueInfo->count; i++) {
2099444c061aSmrg	  if (req[i]->selection == selection) {
2100444c061aSmrg	    targets[j] = req[i]->target;
2101444c061aSmrg	    cbs[j] = req[i]->callback;
2102444c061aSmrg	    closures[j] = req[i]->closure;
2103444c061aSmrg	    incrs[j] = req[i]->incremental;
2104444c061aSmrg	    props[j] = req[i]->param;
2105444c061aSmrg	    j++;
2106444c061aSmrg	  }
2107444c061aSmrg	}
2108444c061aSmrg
2109444c061aSmrg	/* Make the request */
2110444c061aSmrg	GetSelectionValues(widget, selection, targets, count,
2111444c061aSmrg			   cbs, count, closures, time, incrs, props);
2112444c061aSmrg
2113444c061aSmrg	/* Free */
2114444c061aSmrg	XtStackFree((XtPointer) targets, t);
2115444c061aSmrg	XtStackFree((XtPointer) cbs, c);
2116444c061aSmrg	XtStackFree((XtPointer) closures, cs);
2117444c061aSmrg	XtStackFree((XtPointer) incrs, ins);
2118444c061aSmrg	XtStackFree((XtPointer) props, p);
2119444c061aSmrg      }
2120444c061aSmrg    }
2121444c061aSmrg  }
2122444c061aSmrg
2123444c061aSmrg  CleanupRequest(dpy, queueInfo, selection);
2124444c061aSmrg  UNLOCK_PROCESS;
2125444c061aSmrg}
2126444c061aSmrg
21272265a131Smrgvoid XtCancelSelectionRequest(
2128444c061aSmrg    Widget widget,
2129444c061aSmrg    Atom selection)
2130444c061aSmrg{
2131444c061aSmrg  QueuedRequestInfo queueInfo;
2132444c061aSmrg  Window window = XtWindow(widget);
2133444c061aSmrg  Display *dpy = XtDisplay(widget);
2134444c061aSmrg
2135444c061aSmrg  LOCK_PROCESS;
2136444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
2137444c061aSmrg
2138444c061aSmrg  queueInfo = NULL;
2139444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
2140444c061aSmrg  /* If there is one,  then cancel it */
21412265a131Smrg  if (queueInfo != NULL)
2142444c061aSmrg    CleanupRequest(dpy, queueInfo, selection);
2143444c061aSmrg  UNLOCK_PROCESS;
2144444c061aSmrg}
2145444c061aSmrg
2146444c061aSmrg/* Parameter utilities */
2147444c061aSmrg
2148444c061aSmrg/* Parameters on a selection request */
2149444c061aSmrg/* Places data on allocated parameter atom,  then records the
2150444c061aSmrg   parameter atom data for use in the next call to one of
2151444c061aSmrg   the XtGetSelectionValue functions. */
2152444c061aSmrgvoid XtSetSelectionParameters(
2153444c061aSmrg    Widget requestor,
2154444c061aSmrg    Atom selection,
2155444c061aSmrg    Atom type,
2156444c061aSmrg    XtPointer value,
2157444c061aSmrg    unsigned long length,
2158444c061aSmrg    int format)
2159444c061aSmrg{
2160444c061aSmrg  Display *dpy = XtDisplay(requestor);
2161444c061aSmrg  Window window = XtWindow(requestor);
2162444c061aSmrg  Atom property = GetParamInfo(requestor, selection);
2163444c061aSmrg
2164444c061aSmrg  if (property == None) {
2165444c061aSmrg    property = GetSelectionProperty(dpy);
2166444c061aSmrg    AddParamInfo(requestor, selection, property);
2167444c061aSmrg  }
2168444c061aSmrg
2169444c061aSmrg  XChangeProperty(dpy, window, property,
2170444c061aSmrg		  type, format, PropModeReplace,
21710568f49bSmrg		  (unsigned char *) value, (int) length);
2172444c061aSmrg}
2173444c061aSmrg
2174444c061aSmrg/* Retrieves data passed in a parameter. Data for this is stored
2175444c061aSmrg   on the originator's window */
2176444c061aSmrgvoid XtGetSelectionParameters(
2177444c061aSmrg    Widget owner,
2178444c061aSmrg    Atom selection,
2179444c061aSmrg    XtRequestId request_id,
2180444c061aSmrg    Atom* type_return,
2181444c061aSmrg    XtPointer* value_return,
2182444c061aSmrg    unsigned long* length_return,
2183444c061aSmrg    int* format_return)
2184444c061aSmrg{
2185444c061aSmrg    Request req;
2186444c061aSmrg    Display *dpy = XtDisplay(owner);
2187444c061aSmrg    WIDGET_TO_APPCON(owner);
2188444c061aSmrg
2189444c061aSmrg    *value_return = NULL;
21900568f49bSmrg    *length_return = (unsigned long) (*format_return = 0);
2191444c061aSmrg    *type_return = None;
2192444c061aSmrg
2193444c061aSmrg    LOCK_APP(app);
2194444c061aSmrg
2195444c061aSmrg    req = GetRequestRecord(owner, selection, request_id);
2196444c061aSmrg
2197444c061aSmrg    if (req && req->property) {
2198444c061aSmrg	unsigned long bytes_after;	/* unused */
2199444c061aSmrg	StartProtectedSection(dpy, req->requestor);
2200444c061aSmrg	XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000,
2201444c061aSmrg			   False, AnyPropertyType, type_return, format_return,
2202444c061aSmrg			   length_return, &bytes_after,
2203444c061aSmrg			   (unsigned char**) value_return);
2204444c061aSmrg	EndProtectedSection(dpy);
2205444c061aSmrg#ifdef XT_COPY_SELECTION
2206444c061aSmrg	if (*value_return) {
22070568f49bSmrg	    int size = (int) BYTELENGTH(*length_return, *format_return) + 1;
2208444c061aSmrg	    char *tmp = __XtMalloc((Cardinal) size);
22090568f49bSmrg	    (void) memmove(tmp, *value_return, (size_t) size);
2210444c061aSmrg	    XFree(*value_return);
2211444c061aSmrg	    *value_return = tmp;
2212444c061aSmrg	}
2213444c061aSmrg#endif
2214444c061aSmrg    }
2215444c061aSmrg    UNLOCK_APP(app);
2216444c061aSmrg}
2217444c061aSmrg
2218444c061aSmrg/*  Parameters are temporarily stashed in an XContext.  A list is used because
2219444c061aSmrg *  there may be more than one selection request in progress.  The context
2220444c061aSmrg *  data is deleted when the list is empty.  In the future, the parameter
2221444c061aSmrg *  context could be merged with other contexts used during selections.
2222444c061aSmrg */
2223444c061aSmrg
2224444c061aSmrgstatic void AddParamInfo(
2225444c061aSmrg    Widget w,
2226444c061aSmrg    Atom selection,
2227444c061aSmrg    Atom param_atom)
2228444c061aSmrg{
2229444c061aSmrg    Param p;
2230444c061aSmrg    ParamInfo pinfo;
2231444c061aSmrg
2232444c061aSmrg    LOCK_PROCESS;
2233444c061aSmrg    if (paramPropertyContext == 0)
2234444c061aSmrg	paramPropertyContext = XUniqueContext();
2235444c061aSmrg
2236444c061aSmrg    if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2237444c061aSmrg		     (XPointer *) &pinfo)) {
2238444c061aSmrg	pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec));
2239444c061aSmrg	pinfo->count = 1;
2240444c061aSmrg	pinfo->paramlist = XtNew(ParamRec);
2241444c061aSmrg	p = pinfo->paramlist;
2242444c061aSmrg	(void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2243444c061aSmrg			    (char *)pinfo);
2244444c061aSmrg    }
2245444c061aSmrg    else {
22460568f49bSmrg	int n;
22470568f49bSmrg	for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) {
2248444c061aSmrg	    if (p->selection == None || p->selection == selection)
2249444c061aSmrg		break;
2250444c061aSmrg	}
2251444c061aSmrg	if (n == 0) {
2252444c061aSmrg	    pinfo->count++;
2253444c061aSmrg	    pinfo->paramlist = (Param)
2254444c061aSmrg		XtRealloc((char*) pinfo->paramlist,
22550568f49bSmrg			  (Cardinal)(pinfo->count * sizeof(ParamRec)));
2256444c061aSmrg	    p = &pinfo->paramlist[pinfo->count - 1];
2257444c061aSmrg	    (void) XSaveContext(XtDisplay(w), XtWindow(w),
2258444c061aSmrg				paramPropertyContext, (char *)pinfo);
2259444c061aSmrg	}
2260444c061aSmrg    }
2261444c061aSmrg    p->selection = selection;
2262444c061aSmrg    p->param = param_atom;
2263444c061aSmrg    UNLOCK_PROCESS;
2264444c061aSmrg}
2265444c061aSmrg
2266444c061aSmrgstatic void RemoveParamInfo(
2267444c061aSmrg    Widget w,
2268444c061aSmrg    Atom selection)
2269444c061aSmrg{
2270444c061aSmrg    ParamInfo pinfo;
2271444c061aSmrg    Boolean retain = False;
2272444c061aSmrg
2273444c061aSmrg    LOCK_PROCESS;
2274444c061aSmrg    if (paramPropertyContext
2275444c061aSmrg	&& (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2276444c061aSmrg			 (XPointer *) &pinfo) == 0)) {
22770568f49bSmrg	Param p;
22780568f49bSmrg	int n;
2279444c061aSmrg
2280444c061aSmrg	/* Find and invalidate the parameter data. */
22810568f49bSmrg	for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) {
2282444c061aSmrg	    if (p->selection != None) {
2283444c061aSmrg		if (p->selection == selection)
2284444c061aSmrg		    p->selection = None;
2285444c061aSmrg		else
2286444c061aSmrg		    retain = True;
2287444c061aSmrg	    }
2288444c061aSmrg	}
2289444c061aSmrg	/* If there's no valid data remaining, release the context entry. */
2290444c061aSmrg	if (! retain) {
2291444c061aSmrg	    XtFree((char*) pinfo->paramlist);
2292444c061aSmrg	    XtFree((char*) pinfo);
2293444c061aSmrg	    XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext);
2294444c061aSmrg	}
2295444c061aSmrg    }
2296444c061aSmrg    UNLOCK_PROCESS;
2297444c061aSmrg}
2298444c061aSmrg
2299444c061aSmrgstatic Atom GetParamInfo(
2300444c061aSmrg    Widget w,
2301444c061aSmrg    Atom selection)
2302444c061aSmrg{
2303444c061aSmrg    ParamInfo pinfo;
2304444c061aSmrg    Atom atom = None;
2305444c061aSmrg
2306444c061aSmrg    LOCK_PROCESS;
2307444c061aSmrg    if (paramPropertyContext
2308444c061aSmrg	&& (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2309444c061aSmrg			 (XPointer *) &pinfo) == 0)) {
23100568f49bSmrg	Param p;
23110568f49bSmrg	int n;
2312444c061aSmrg
23130568f49bSmrg	for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++)
2314444c061aSmrg	    if (p->selection == selection) {
2315444c061aSmrg		atom = p->param;
2316444c061aSmrg		break;
2317444c061aSmrg	    }
2318444c061aSmrg    }
2319444c061aSmrg    UNLOCK_PROCESS;
2320444c061aSmrg    return atom;
2321444c061aSmrg}
2322