Selection.c revision 249c3046
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)};
142444c061aSmrg#define BYTELENGTH(length, format) ((length) * StorageSize[(format)>>4])
143444c061aSmrg#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4])
144444c061aSmrg
145444c061aSmrg/* Xlib and Xt are permitted to have different memory allocators, and in the
146444c061aSmrg * XtSelectionCallbackProc the client is instructed to free the selection
147444c061aSmrg * value with XtFree, so the selection value received from XGetWindowProperty
148444c061aSmrg * should be copied to memory allocated through Xt.  But copying is
149444c061aSmrg * undesirable since the selection value may be large, and, under normal
150444c061aSmrg * library configuration copying is unnecessary.
151444c061aSmrg */
152444c061aSmrg#ifdef XTTRACEMEMORY
153444c061aSmrg#define XT_COPY_SELECTION	1
154444c061aSmrg#endif
155444c061aSmrg
156444c061aSmrg/*ARGSUSED*/
157444c061aSmrgstatic void FreePropList(
158444c061aSmrg Widget w,			/* unused */
159444c061aSmrg XtPointer closure,
160444c061aSmrg XtPointer callData)		/* unused */
161444c061aSmrg{
162444c061aSmrg    PropList sarray = (PropList)closure;
163444c061aSmrg    LOCK_PROCESS;
164444c061aSmrg    XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy),
165444c061aSmrg		   selectPropertyContext);
166444c061aSmrg    UNLOCK_PROCESS;
167444c061aSmrg    XtFree((char*)sarray->list);
168444c061aSmrg    XtFree((char*)closure);
169444c061aSmrg}
170444c061aSmrg
171444c061aSmrg
172444c061aSmrgstatic PropList GetPropList(
173444c061aSmrg    Display *dpy)
174444c061aSmrg{
175444c061aSmrg    PropList sarray;
176444c061aSmrg    Atom atoms[4];
177444c061aSmrg    static char* names[] = {
178444c061aSmrg	"INCR",
179444c061aSmrg	"MULTIPLE",
180444c061aSmrg	"TIMESTAMP",
181444c061aSmrg	"_XT_SELECTION_0" };
182444c061aSmrg
183444c061aSmrg    LOCK_PROCESS;
184444c061aSmrg    if (selectPropertyContext == 0)
185444c061aSmrg	selectPropertyContext = XUniqueContext();
186444c061aSmrg    if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
187444c061aSmrg		     (XPointer *)&sarray)) {
188444c061aSmrg	XtPerDisplay pd = _XtGetPerDisplay(dpy);
189444c061aSmrg	sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec));
190444c061aSmrg	sarray->dpy = dpy;
191444c061aSmrg	XInternAtoms(dpy, names, 4, FALSE, atoms);
192444c061aSmrg	sarray->incr_atom = atoms[0];
193444c061aSmrg	sarray->indirect_atom = atoms[1];
194444c061aSmrg	sarray->timestamp_atom = atoms[2];
195444c061aSmrg	sarray->propCount = 1;
196444c061aSmrg	sarray->list =
197444c061aSmrg	    (SelectionProp)__XtMalloc((unsigned) sizeof(SelectionPropRec));
198444c061aSmrg	sarray->list[0].prop = atoms[3];
199444c061aSmrg	sarray->list[0].avail = TRUE;
200444c061aSmrg	(void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
201444c061aSmrg			    (char *) sarray);
202444c061aSmrg	_XtAddCallback( &pd->destroy_callbacks,
203444c061aSmrg			FreePropList, (XtPointer)sarray );
204444c061aSmrg    }
205444c061aSmrg    UNLOCK_PROCESS;
206444c061aSmrg    return sarray;
207444c061aSmrg}
208444c061aSmrg
209444c061aSmrg
210444c061aSmrgstatic Atom GetSelectionProperty(
211444c061aSmrg    Display *dpy)
212444c061aSmrg{
213444c061aSmrg SelectionProp p;
214444c061aSmrg int propCount;
215444c061aSmrg char propname[80];
216444c061aSmrg PropList sarray = GetPropList(dpy);
217444c061aSmrg
218444c061aSmrg for (p = sarray->list, propCount=sarray->propCount;
219444c061aSmrg	propCount;
220444c061aSmrg	p++, propCount--) {
221444c061aSmrg   if (p->avail) {
222444c061aSmrg      p->avail = FALSE;
223444c061aSmrg      return(p->prop);
224444c061aSmrg   }
225444c061aSmrg }
226444c061aSmrg propCount = sarray->propCount++;
227444c061aSmrg sarray->list = (SelectionProp) XtRealloc((XtPointer)sarray->list,
228444c061aSmrg  		(unsigned)(sarray->propCount*sizeof(SelectionPropRec)));
229444c061aSmrg (void) sprintf(propname, "%s%d", "_XT_SELECTION_", propCount);
230444c061aSmrg sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE);
231444c061aSmrg sarray->list[propCount].avail = FALSE;
232444c061aSmrg return(sarray->list[propCount].prop);
233444c061aSmrg}
234444c061aSmrg
235444c061aSmrgstatic void FreeSelectionProperty(
236444c061aSmrg    Display *dpy,
237444c061aSmrg    Atom prop)
238444c061aSmrg{
239444c061aSmrg SelectionProp p;
240444c061aSmrg PropList sarray;
241444c061aSmrg if (prop == None) return;
242444c061aSmrg LOCK_PROCESS;
243444c061aSmrg if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
244444c061aSmrg		  (XPointer *)&sarray))
245444c061aSmrg    XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
246444c061aSmrg	    "noSelectionProperties", "freeSelectionProperty", XtCXtToolkitError,
247444c061aSmrg		"internal error: no selection property context for display",
248444c061aSmrg		 (String *)NULL,  (Cardinal *)NULL );
249444c061aSmrg UNLOCK_PROCESS;
250444c061aSmrg for (p = sarray->list; p; p++)
251444c061aSmrg   if (p->prop == prop) {
252444c061aSmrg      p->avail = TRUE;
253444c061aSmrg      return;
254444c061aSmrg      }
255444c061aSmrg}
256444c061aSmrg
257444c061aSmrgstatic void FreeInfo(
258444c061aSmrg    CallBackInfo info)
259444c061aSmrg{
260444c061aSmrg    XtFree((char*)info->incremental);
261444c061aSmrg    XtFree((char*)info->callbacks);
262444c061aSmrg    XtFree((char*)info->req_closure);
263444c061aSmrg    XtFree((char*)info->target);
264444c061aSmrg    XtFree((char*)info);
265444c061aSmrg}
266444c061aSmrg
267444c061aSmrgstatic CallBackInfo MakeInfo(
268444c061aSmrg    Select ctx,
269444c061aSmrg    XtSelectionCallbackProc *callbacks,
270444c061aSmrg    XtPointer *closures,
271444c061aSmrg    int count,
272444c061aSmrg    Widget widget,
273444c061aSmrg    Time time,
274444c061aSmrg    Boolean *incremental,
275444c061aSmrg    Atom *properties)
276444c061aSmrg{
277444c061aSmrg    	CallBackInfo info = XtNew(CallBackInfoRec);
278444c061aSmrg
279444c061aSmrg	info->ctx = ctx;
280444c061aSmrg	info->callbacks = (XtSelectionCallbackProc *)
281444c061aSmrg	    __XtMalloc((unsigned) (count * sizeof(XtSelectionCallbackProc)));
282444c061aSmrg	(void) memmove((char*)info->callbacks, (char*)callbacks,
283444c061aSmrg		       count * sizeof(XtSelectionCallbackProc));
284444c061aSmrg	info->req_closure =
285444c061aSmrg	    (XtPointer*)__XtMalloc((unsigned) (count * sizeof(XtPointer)));
286444c061aSmrg	(void) memmove((char*)info->req_closure, (char*)closures,
287444c061aSmrg		       count * sizeof(XtPointer));
288444c061aSmrg	if (count == 1 && properties != NULL && properties[0] != None)
289444c061aSmrg	    info->property = properties[0];
290444c061aSmrg	else {
291444c061aSmrg	    info->property = GetSelectionProperty(XtDisplay(widget));
292444c061aSmrg	    XDeleteProperty(XtDisplay(widget), XtWindow(widget),
293444c061aSmrg			    info->property);
294444c061aSmrg	}
295444c061aSmrg	info->proc = HandleSelectionReplies;
296444c061aSmrg	info->widget = widget;
297444c061aSmrg	info->time = time;
298444c061aSmrg	info->incremental = (Boolean*) __XtMalloc(count * sizeof(Boolean));
299444c061aSmrg	(void) memmove((char*)info->incremental, (char*) incremental,
300444c061aSmrg		       count * sizeof(Boolean));
301444c061aSmrg	info->current = 0;
302444c061aSmrg	info->value = NULL;
303444c061aSmrg	return (info);
304444c061aSmrg}
305444c061aSmrg
306444c061aSmrgstatic void RequestSelectionValue(
307444c061aSmrg    CallBackInfo info,
308444c061aSmrg    Atom selection,
309444c061aSmrg    Atom target)
310444c061aSmrg{
311444c061aSmrg#ifndef DEBUG_WO_TIMERS
312444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(info->widget);
313444c061aSmrg	info->timeout = XtAppAddTimeOut(app,
314444c061aSmrg			 app->selectionTimeout, ReqTimedOut, (XtPointer)info);
315444c061aSmrg#endif
316444c061aSmrg	XtAddEventHandler(info->widget, (EventMask)0, TRUE,
317444c061aSmrg			  HandleSelectionReplies, (XtPointer)info);
318444c061aSmrg	XConvertSelection(info->ctx->dpy, selection, target,
319444c061aSmrg			  info->property, XtWindow(info->widget), info->time);
320444c061aSmrg}
321444c061aSmrg
322444c061aSmrg
323444c061aSmrgstatic XContext selectContext = 0;
324444c061aSmrg
325444c061aSmrgstatic Select NewContext(
326444c061aSmrg    Display *dpy,
327444c061aSmrg    Atom selection)
328444c061aSmrg{
329444c061aSmrg    /* assert(selectContext != 0) */
330444c061aSmrg    Select ctx = XtNew(SelectRec);
331444c061aSmrg    ctx->dpy = dpy;
332444c061aSmrg    ctx->selection = selection;
333444c061aSmrg    ctx->widget = NULL;
334444c061aSmrg    ctx->prop_list = GetPropList(dpy);
335444c061aSmrg    ctx->ref_count = 0;
336444c061aSmrg    ctx->free_when_done = FALSE;
337444c061aSmrg    ctx->was_disowned = FALSE;
338444c061aSmrg    LOCK_PROCESS;
339444c061aSmrg    (void)XSaveContext(dpy, (Window)selection, selectContext, (char *)ctx);
340444c061aSmrg    UNLOCK_PROCESS;
341444c061aSmrg    return ctx;
342444c061aSmrg}
343444c061aSmrg
344444c061aSmrgstatic Select FindCtx(
345444c061aSmrg    Display *dpy,
346444c061aSmrg    Atom selection)
347444c061aSmrg{
348444c061aSmrg    Select ctx;
349444c061aSmrg
350444c061aSmrg    LOCK_PROCESS;
351444c061aSmrg    if (selectContext == 0)
352444c061aSmrg	selectContext = XUniqueContext();
353444c061aSmrg    if (XFindContext(dpy, (Window)selection, selectContext, (XPointer *)&ctx))
354444c061aSmrg	ctx = NewContext(dpy, selection);
355444c061aSmrg    UNLOCK_PROCESS;
356444c061aSmrg    return ctx;
357444c061aSmrg}
358444c061aSmrg
359444c061aSmrg/*ARGSUSED*/
360444c061aSmrgstatic void WidgetDestroyed(
361444c061aSmrg    Widget widget,
362444c061aSmrg    XtPointer closure, XtPointer data)
363444c061aSmrg{
364444c061aSmrg    Select ctx = (Select) closure;
365444c061aSmrg    if (ctx->widget == widget) {
366444c061aSmrg	if (ctx->free_when_done)
367444c061aSmrg	    XtFree((char*)ctx);
368444c061aSmrg	else
369444c061aSmrg	    ctx->widget = NULL;
370444c061aSmrg    }
371444c061aSmrg}
372444c061aSmrg
373444c061aSmrg/* Selection Owner code */
374444c061aSmrg
375444c061aSmrgstatic void HandleSelectionEvents(Widget, XtPointer, XEvent *, Boolean *);
376444c061aSmrg
377444c061aSmrgstatic Boolean LoseSelection(
378444c061aSmrg    Select ctx,
379444c061aSmrg    Widget widget,
380444c061aSmrg    Atom selection,
381444c061aSmrg    Time time)
382444c061aSmrg{
383444c061aSmrg    if ((ctx->widget == widget) &&
384444c061aSmrg	(ctx->selection == selection) && /* paranoia */
385444c061aSmrg	!ctx->was_disowned &&
386444c061aSmrg	((time == CurrentTime) || (time >= ctx->time)))
387444c061aSmrg    {
388444c061aSmrg	XtRemoveEventHandler(widget, (EventMask)0, TRUE,
389444c061aSmrg			     HandleSelectionEvents, (XtPointer)ctx);
390444c061aSmrg	XtRemoveCallback(widget, XtNdestroyCallback,
391444c061aSmrg			 WidgetDestroyed, (XtPointer)ctx);
392444c061aSmrg	ctx->was_disowned = TRUE; /* widget officially loses ownership */
393444c061aSmrg	/* now inform widget */
394444c061aSmrg	if (ctx->loses) {
395444c061aSmrg	    if (ctx->incremental)
396444c061aSmrg	       (*(XtLoseSelectionIncrProc)ctx->loses)
397444c061aSmrg		   (widget, &ctx->selection, ctx->owner_closure);
398444c061aSmrg	    else  (*ctx->loses)(widget, &ctx->selection);
399444c061aSmrg	}
400444c061aSmrg	return(TRUE);
401444c061aSmrg    }
402444c061aSmrg    else return(FALSE);
403444c061aSmrg}
404444c061aSmrg
405444c061aSmrgstatic XContext selectWindowContext = 0;
406444c061aSmrg
407444c061aSmrg/* %%% Xlib.h should make this public! */
408444c061aSmrgtypedef int (*xErrorHandler)(Display*, XErrorEvent*);
409444c061aSmrg
410444c061aSmrgstatic xErrorHandler oldErrorHandler = NULL;
411444c061aSmrgstatic unsigned long firstProtectRequest;
412444c061aSmrgstatic Window errorWindow;
413444c061aSmrg
414444c061aSmrgstatic int LocalErrorHandler (
415444c061aSmrg    Display *dpy,
416444c061aSmrg    XErrorEvent *error)
417444c061aSmrg{
418444c061aSmrg    int retval;
419444c061aSmrg
420444c061aSmrg    /* If BadWindow error on selection requestor, nothing to do but let
421444c061aSmrg     * the transfer timeout.  Otherwise, invoke saved error handler. */
422444c061aSmrg
423444c061aSmrg    LOCK_PROCESS;
424444c061aSmrg
425444c061aSmrg    if (error->error_code == BadWindow && error->resourceid == errorWindow &&
426444c061aSmrg	error->serial >= firstProtectRequest) {
427444c061aSmrg	UNLOCK_PROCESS;
428444c061aSmrg	return 0;
429444c061aSmrg    }
430444c061aSmrg
431444c061aSmrg    if (oldErrorHandler == NULL) {
432444c061aSmrg	UNLOCK_PROCESS;
433444c061aSmrg	return 0;  /* should never happen */
434444c061aSmrg    }
435444c061aSmrg
436444c061aSmrg    retval = (*oldErrorHandler)(dpy, error);
437444c061aSmrg    UNLOCK_PROCESS;
438444c061aSmrg    return retval;
439444c061aSmrg}
440444c061aSmrg
441444c061aSmrgstatic void StartProtectedSection(
442444c061aSmrg    Display *dpy,
443444c061aSmrg    Window window)
444444c061aSmrg{
445444c061aSmrg    /* protect ourselves against request window being destroyed
446444c061aSmrg     * before completion of transfer */
447444c061aSmrg
448444c061aSmrg    LOCK_PROCESS;
449444c061aSmrg    oldErrorHandler = XSetErrorHandler(LocalErrorHandler);
450444c061aSmrg    firstProtectRequest = NextRequest(dpy);
451444c061aSmrg    errorWindow = window;
452444c061aSmrg    UNLOCK_PROCESS;
453444c061aSmrg}
454444c061aSmrg
455444c061aSmrgstatic void EndProtectedSection(
456444c061aSmrg    Display *dpy)
457444c061aSmrg{
458444c061aSmrg    /* flush any generated errors on requestor and
459444c061aSmrg     * restore original error handler */
460444c061aSmrg
461444c061aSmrg    XSync(dpy, False);
462444c061aSmrg
463444c061aSmrg    LOCK_PROCESS;
464444c061aSmrg    XSetErrorHandler(oldErrorHandler);
465444c061aSmrg    oldErrorHandler = NULL;
466444c061aSmrg    UNLOCK_PROCESS;
467444c061aSmrg}
468444c061aSmrg
469444c061aSmrgstatic void AddHandler(
470444c061aSmrg    Request req,
471444c061aSmrg    EventMask mask,
472444c061aSmrg    XtEventHandler proc,
473444c061aSmrg    XtPointer closure)
474444c061aSmrg{
475444c061aSmrg    Display *dpy = req->ctx->dpy;
476444c061aSmrg    Window window = req->requestor;
477444c061aSmrg    Widget widget = XtWindowToWidget(dpy, window);
478444c061aSmrg
479444c061aSmrg    if (widget != NULL) req->widget = widget;
480444c061aSmrg    else widget = req->widget;
481444c061aSmrg
482444c061aSmrg    if (XtWindow(widget) == window)
483444c061aSmrg	XtAddEventHandler(widget, mask, False, proc, closure);
484444c061aSmrg    else {
485444c061aSmrg	RequestWindowRec *requestWindowRec;
486444c061aSmrg	LOCK_PROCESS;
487444c061aSmrg	if (selectWindowContext == 0)
488444c061aSmrg	    selectWindowContext = XUniqueContext();
489444c061aSmrg	if (XFindContext(dpy, window, selectWindowContext,
490444c061aSmrg			 (XPointer *)&requestWindowRec)) {
491444c061aSmrg	    requestWindowRec = XtNew(RequestWindowRec);
492444c061aSmrg	    requestWindowRec->active_transfer_count = 0;
493444c061aSmrg	    (void)XSaveContext(dpy, window, selectWindowContext,
494444c061aSmrg			       (char *)requestWindowRec);
495444c061aSmrg	}
496444c061aSmrg	UNLOCK_PROCESS;
497444c061aSmrg	if (requestWindowRec->active_transfer_count++ == 0) {
498444c061aSmrg	    XtRegisterDrawable(dpy, window, widget);
499444c061aSmrg	    XSelectInput(dpy, window, mask);
500444c061aSmrg	}
501444c061aSmrg	XtAddRawEventHandler(widget, mask, FALSE, proc, closure);
502444c061aSmrg    }
503444c061aSmrg}
504444c061aSmrg
505444c061aSmrgstatic void RemoveHandler(
506444c061aSmrg    Request req,
507444c061aSmrg    EventMask mask,
508444c061aSmrg    XtEventHandler proc,
509444c061aSmrg    XtPointer closure)
510444c061aSmrg{
511444c061aSmrg    Display *dpy = req->ctx->dpy;
512444c061aSmrg    Window window = req->requestor;
513444c061aSmrg    Widget widget = req->widget;
514444c061aSmrg
515444c061aSmrg    if ((XtWindowToWidget(dpy, window) == widget) &&
516444c061aSmrg        (XtWindow(widget) != window)) {
517444c061aSmrg	/* we had to hang this window onto our widget; take it off */
518444c061aSmrg	RequestWindowRec* requestWindowRec;
519444c061aSmrg	XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure);
520444c061aSmrg	LOCK_PROCESS;
521444c061aSmrg	(void)XFindContext(dpy, window, selectWindowContext,
522444c061aSmrg			   (XPointer *)&requestWindowRec);
523444c061aSmrg	UNLOCK_PROCESS;
524444c061aSmrg	if (--requestWindowRec->active_transfer_count == 0) {
525444c061aSmrg	    XtUnregisterDrawable(dpy, window);
526444c061aSmrg	    StartProtectedSection(dpy, window);
527444c061aSmrg	    XSelectInput(dpy, window, 0L);
528444c061aSmrg	    EndProtectedSection(dpy);
529444c061aSmrg	    LOCK_PROCESS;
530444c061aSmrg	    (void)XDeleteContext(dpy, window, selectWindowContext);
531444c061aSmrg	    UNLOCK_PROCESS;
532444c061aSmrg	    XtFree((char*)requestWindowRec);
533444c061aSmrg	}
534444c061aSmrg    } else {
535444c061aSmrg        XtRemoveEventHandler(widget, mask, TRUE,  proc, closure);
536444c061aSmrg    }
537444c061aSmrg}
538444c061aSmrg
539444c061aSmrg/* ARGSUSED */
540444c061aSmrgstatic void OwnerTimedOut(
541444c061aSmrg    XtPointer closure,
542444c061aSmrg    XtIntervalId   *id)
543444c061aSmrg{
544444c061aSmrg    Request req = (Request)closure;
545444c061aSmrg    Select ctx = req->ctx;
546444c061aSmrg
547444c061aSmrg    if (ctx->incremental && (ctx->owner_cancel != NULL)) {
548444c061aSmrg	(*ctx->owner_cancel)(ctx->widget, &ctx->selection,
549444c061aSmrg			     &req->target, (XtRequestId*)&req,
550444c061aSmrg			     ctx->owner_closure);
551444c061aSmrg    } else {
552444c061aSmrg	if (ctx->notify == NULL)
553444c061aSmrg	    XtFree((char*)req->value);
554444c061aSmrg	else {
555444c061aSmrg	    /* the requestor hasn't deleted the property, but
556444c061aSmrg	     * the owner needs to free the value.
557444c061aSmrg	     */
558444c061aSmrg	    if (ctx->incremental)
559444c061aSmrg		(*(XtSelectionDoneIncrProc)ctx->notify)
560444c061aSmrg			      (ctx->widget, &ctx->selection, &req->target,
561444c061aSmrg			       (XtRequestId*)&req, ctx->owner_closure);
562444c061aSmrg	    else
563444c061aSmrg		(*ctx->notify)(ctx->widget, &ctx->selection, &req->target);
564444c061aSmrg	}
565444c061aSmrg    }
566444c061aSmrg
567444c061aSmrg    RemoveHandler(req, (EventMask)PropertyChangeMask,
568444c061aSmrg		  HandlePropertyGone, closure);
569444c061aSmrg    XtFree((char*)req);
570444c061aSmrg    if (--ctx->ref_count == 0 && ctx->free_when_done)
571444c061aSmrg	XtFree((char*)ctx);
572444c061aSmrg}
573444c061aSmrg
574444c061aSmrgstatic void SendIncrement(
575444c061aSmrg    Request incr)
576444c061aSmrg{
577444c061aSmrg    Display *dpy = incr->ctx->dpy;
578444c061aSmrg
579444c061aSmrg    unsigned long incrSize = MAX_SELECTION_INCR(dpy);
580444c061aSmrg    if (incrSize > incr->bytelength - incr->offset)
581444c061aSmrg        incrSize = incr->bytelength - incr->offset;
582444c061aSmrg    StartProtectedSection(dpy, incr->requestor);
583444c061aSmrg    XChangeProperty(dpy, incr->requestor, incr->property,
584444c061aSmrg    	    incr->type, incr->format, PropModeReplace,
585444c061aSmrg	    (unsigned char *)incr->value + incr->offset,
586444c061aSmrg	    NUMELEM((int)incrSize, incr->format));
587444c061aSmrg    EndProtectedSection(dpy);
588444c061aSmrg    incr->offset += incrSize;
589444c061aSmrg}
590444c061aSmrg
591444c061aSmrgstatic void AllSent(
592444c061aSmrg    Request req)
593444c061aSmrg{
594444c061aSmrg    Select ctx = req->ctx;
595444c061aSmrg    StartProtectedSection(ctx->dpy, req->requestor);
596444c061aSmrg    XChangeProperty(ctx->dpy, req->requestor,
597444c061aSmrg		    req->property, req->type,  req->format,
598444c061aSmrg		    PropModeReplace, (unsigned char *) NULL, 0);
599444c061aSmrg    EndProtectedSection(ctx->dpy);
600444c061aSmrg    req->allSent = TRUE;
601444c061aSmrg
602444c061aSmrg    if (ctx->notify == NULL) XtFree((char*)req->value);
603444c061aSmrg}
604444c061aSmrg
605444c061aSmrg/*ARGSUSED*/
606444c061aSmrgstatic void HandlePropertyGone(
607444c061aSmrg    Widget widget,
608444c061aSmrg    XtPointer closure,
609444c061aSmrg    XEvent *ev,
610444c061aSmrg    Boolean *cont)
611444c061aSmrg{
612444c061aSmrg    XPropertyEvent *event = (XPropertyEvent *) ev;
613444c061aSmrg    Request req = (Request)closure;
614444c061aSmrg    Select ctx = req->ctx;
615444c061aSmrg
616444c061aSmrg    if ((event->type != PropertyNotify) ||
617444c061aSmrg        (event->state != PropertyDelete) ||
618444c061aSmrg	(event->atom != req->property) ||
619444c061aSmrg	(event->window != req->requestor))
620444c061aSmrg      return;
621444c061aSmrg#ifndef DEBUG_WO_TIMERS
622444c061aSmrg    XtRemoveTimeOut(req->timeout);
623444c061aSmrg#endif
624444c061aSmrg    if (req->allSent) {
625444c061aSmrg	if (ctx->notify) {
626444c061aSmrg	    if (ctx->incremental) {
627444c061aSmrg		(*(XtSelectionDoneIncrProc)ctx->notify)
628444c061aSmrg			      (ctx->widget, &ctx->selection, &req->target,
629444c061aSmrg			       (XtRequestId*)&req, ctx->owner_closure);
630444c061aSmrg	    }
631444c061aSmrg	    else (*ctx->notify)(ctx->widget, &ctx->selection, &req->target);
632444c061aSmrg	}
633444c061aSmrg	RemoveHandler(req, (EventMask)PropertyChangeMask,
634444c061aSmrg		      HandlePropertyGone, closure);
635444c061aSmrg	XtFree((char*)req);
636444c061aSmrg	if (--ctx->ref_count == 0 && ctx->free_when_done)
637444c061aSmrg	    XtFree((char*)ctx);
638444c061aSmrg    } else  { /* is this part of an incremental transfer? */
639444c061aSmrg	if (ctx->incremental) {
640444c061aSmrg	     if (req->bytelength == 0)
641444c061aSmrg		AllSent(req);
642444c061aSmrg	     else {
643444c061aSmrg		unsigned long size = MAX_SELECTION_INCR(ctx->dpy);
644444c061aSmrg    		SendIncrement(req);
645444c061aSmrg		(*(XtConvertSelectionIncrProc)ctx->convert)
646444c061aSmrg			   (ctx->widget, &ctx->selection, &req->target,
647444c061aSmrg			    &req->type, &req->value,
648444c061aSmrg			    &req->bytelength, &req->format,
649444c061aSmrg			    &size, ctx->owner_closure, (XtPointer*)&req);
650444c061aSmrg		if (req->bytelength)
651444c061aSmrg		    req->bytelength = BYTELENGTH(req->bytelength, req->format);
652444c061aSmrg		req->offset = 0;
653444c061aSmrg	    }
654444c061aSmrg	} else {
655444c061aSmrg	    if (req->offset < req->bytelength)
656444c061aSmrg		SendIncrement(req);
657444c061aSmrg	    else AllSent(req);
658444c061aSmrg	}
659444c061aSmrg#ifndef DEBUG_WO_TIMERS
660444c061aSmrg	{
661444c061aSmrg	  XtAppContext app = XtWidgetToApplicationContext(req->widget);
662444c061aSmrg	  req->timeout = XtAppAddTimeOut(app,
663444c061aSmrg			 app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
664444c061aSmrg	}
665444c061aSmrg#endif
666444c061aSmrg    }
667444c061aSmrg}
668444c061aSmrg
669444c061aSmrgstatic void PrepareIncremental(
670444c061aSmrg    Request req,
671444c061aSmrg    Widget widget,
672444c061aSmrg    Window window,
673444c061aSmrg    Atom property,
674444c061aSmrg    Atom target,
675444c061aSmrg    Atom targetType,
676444c061aSmrg    XtPointer value,
677444c061aSmrg    unsigned long length,
678444c061aSmrg    int format)
679444c061aSmrg{
680444c061aSmrg	req->type = targetType;
681444c061aSmrg	req->value = value;
682444c061aSmrg	req->bytelength = BYTELENGTH(length,format);
683444c061aSmrg	req->format = format;
684444c061aSmrg	req->offset = 0;
685444c061aSmrg	req->target = target;
686444c061aSmrg	req->widget = widget;
687444c061aSmrg	req->allSent = FALSE;
688444c061aSmrg#ifndef DEBUG_WO_TIMERS
689444c061aSmrg	{
690444c061aSmrg	XtAppContext app = XtWidgetToApplicationContext(widget);
691444c061aSmrg	req->timeout = XtAppAddTimeOut(app,
692444c061aSmrg			 app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
693444c061aSmrg	}
694444c061aSmrg#endif
695444c061aSmrg	AddHandler(req, (EventMask)PropertyChangeMask,
696444c061aSmrg		   HandlePropertyGone, (XtPointer)req);
697444c061aSmrg/* now send client INCR property */
698444c061aSmrg	XChangeProperty(req->ctx->dpy, window, req->property,
699444c061aSmrg			req->ctx->prop_list->incr_atom,
700444c061aSmrg			32, PropModeReplace,
701444c061aSmrg			(unsigned char *)&req->bytelength, 1);
702444c061aSmrg}
703444c061aSmrg
704444c061aSmrgstatic Boolean GetConversion(
705444c061aSmrg    Select ctx,			/* logical owner */
706444c061aSmrg    XSelectionRequestEvent* event,
707444c061aSmrg    Atom target,
708444c061aSmrg    Atom property,		/* requestor's property */
709444c061aSmrg    Widget widget)		/* physical owner (receives events) */
710444c061aSmrg{
711444c061aSmrg    XtPointer value = NULL;
712444c061aSmrg    unsigned long length;
713444c061aSmrg    int format;
714444c061aSmrg    Atom targetType;
715444c061aSmrg    Request req = XtNew(RequestRec);
716444c061aSmrg    Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom);
717444c061aSmrg
718444c061aSmrg    req->ctx = ctx;
719444c061aSmrg    req->event = *event;
720444c061aSmrg    req->property = property;
721444c061aSmrg    req->requestor = event->requestor;
722444c061aSmrg
723444c061aSmrg    if (timestamp_target) {
724444c061aSmrg	value = __XtMalloc(sizeof(long));
725444c061aSmrg	*(long*)value = ctx->time;
726444c061aSmrg	targetType = XA_INTEGER;
727444c061aSmrg	length = 1;
728444c061aSmrg	format = 32;
729444c061aSmrg    }
730444c061aSmrg    else {
731444c061aSmrg	ctx->ref_count++;
732444c061aSmrg	if (ctx->incremental == TRUE) {
733444c061aSmrg	     unsigned long size = MAX_SELECTION_INCR(ctx->dpy);
734444c061aSmrg	     if ((*(XtConvertSelectionIncrProc)ctx->convert)
735444c061aSmrg			       (ctx->widget, &event->selection, &target,
736444c061aSmrg				&targetType, &value, &length, &format,
737444c061aSmrg				&size, ctx->owner_closure, (XtRequestId*)&req)
738444c061aSmrg		     == FALSE) {
739444c061aSmrg		 XtFree((char*)req);
740444c061aSmrg		 ctx->ref_count--;
741444c061aSmrg		 return(FALSE);
742444c061aSmrg	     }
743444c061aSmrg	     StartProtectedSection(ctx->dpy, event->requestor);
744444c061aSmrg	     PrepareIncremental(req, widget, event->requestor, property,
745444c061aSmrg				target, targetType, value, length, format);
746444c061aSmrg	     return(TRUE);
747444c061aSmrg	}
748444c061aSmrg	ctx->req = req;
749444c061aSmrg	if ((*ctx->convert)(ctx->widget, &event->selection, &target,
750444c061aSmrg			    &targetType, &value, &length, &format) == FALSE) {
751444c061aSmrg	    XtFree((char*)req);
752444c061aSmrg	    ctx->req = NULL;
753444c061aSmrg	    ctx->ref_count--;
754444c061aSmrg	    return(FALSE);
755444c061aSmrg	}
756444c061aSmrg	ctx->req = NULL;
757444c061aSmrg    }
758444c061aSmrg    StartProtectedSection(ctx->dpy, event->requestor);
759444c061aSmrg    if (BYTELENGTH(length,format) <= (unsigned long) MAX_SELECTION_INCR(ctx->dpy)) {
760444c061aSmrg	if (! timestamp_target) {
761444c061aSmrg	    if (ctx->notify != NULL) {
762444c061aSmrg		  req->target = target;
763444c061aSmrg		  req->widget = widget;
764444c061aSmrg		  req->allSent = TRUE;
765444c061aSmrg#ifndef DEBUG_WO_TIMERS
766444c061aSmrg		  {
767444c061aSmrg		  XtAppContext app = XtWidgetToApplicationContext(req->widget);
768444c061aSmrg		  req->timeout = XtAppAddTimeOut(app,
769444c061aSmrg			 app->selectionTimeout, OwnerTimedOut, (XtPointer)req);
770444c061aSmrg		  }
771444c061aSmrg#endif
772444c061aSmrg	          AddHandler(req, (EventMask)PropertyChangeMask,
773444c061aSmrg			     HandlePropertyGone, (XtPointer)req);
774444c061aSmrg	      }
775444c061aSmrg	      else ctx->ref_count--;
776444c061aSmrg        }
777444c061aSmrg	XChangeProperty(ctx->dpy, event->requestor, property,
778444c061aSmrg			targetType, format, PropModeReplace,
779444c061aSmrg			(unsigned char *)value, (int)length);
780444c061aSmrg	/* free storage for client if no notify proc */
781444c061aSmrg	if (timestamp_target || ctx->notify == NULL) {
782444c061aSmrg	    XtFree((char*)value);
783444c061aSmrg	    XtFree((char*)req);
784444c061aSmrg	}
785444c061aSmrg    } else {
786444c061aSmrg	 PrepareIncremental(req, widget, event->requestor, property,
787444c061aSmrg			    target, targetType, value, length, format);
788444c061aSmrg    }
789444c061aSmrg    return(TRUE);
790444c061aSmrg}
791444c061aSmrg
792444c061aSmrg/*ARGSUSED*/
793444c061aSmrgstatic void HandleSelectionEvents(
794444c061aSmrg    Widget widget,
795444c061aSmrg    XtPointer closure,
796444c061aSmrg    XEvent *event,
797444c061aSmrg    Boolean *cont)
798444c061aSmrg{
799444c061aSmrg    Select ctx;
800444c061aSmrg    XSelectionEvent ev;
801444c061aSmrg    Atom target;
802444c061aSmrg    int count;
803444c061aSmrg    Boolean writeback = FALSE;
804444c061aSmrg
805444c061aSmrg    ctx = (Select) closure;
806444c061aSmrg    switch (event->type) {
807444c061aSmrg      case SelectionClear:
808444c061aSmrg	/* if this event is not for the selection we registered for,
809444c061aSmrg	 * don't do anything */
810444c061aSmrg	if (ctx->selection != event->xselectionclear.selection ||
811444c061aSmrg	    ctx->serial > event->xselectionclear.serial)
812444c061aSmrg	    break;
813444c061aSmrg	(void) LoseSelection(ctx, widget, event->xselectionclear.selection,
814444c061aSmrg			event->xselectionclear.time);
815444c061aSmrg	break;
816444c061aSmrg      case SelectionRequest:
817444c061aSmrg	/* if this event is not for the selection we registered for,
818444c061aSmrg	 * don't do anything */
819444c061aSmrg	if (ctx->selection != event->xselectionrequest.selection)
820444c061aSmrg	    break;
821444c061aSmrg	ev.type = SelectionNotify;
822444c061aSmrg	ev.display = event->xselectionrequest.display;
823444c061aSmrg	ev.requestor = event->xselectionrequest.requestor;
824444c061aSmrg	ev.selection = event->xselectionrequest.selection;
825444c061aSmrg	ev.time = event->xselectionrequest.time;
826444c061aSmrg	ev.target = event->xselectionrequest.target;
827444c061aSmrg	if (event->xselectionrequest.property == None) /* obsolete requestor */
828444c061aSmrg	   event->xselectionrequest.property = event->xselectionrequest.target;
829444c061aSmrg	if (ctx->widget != widget || ctx->was_disowned
830444c061aSmrg	   || ((event->xselectionrequest.time != CurrentTime)
831249c3046Smrg	        && (event->xselectionrequest.time < ctx->time))) {
832444c061aSmrg	    ev.property = None;
833249c3046Smrg	    StartProtectedSection(ev.display, ev.requestor);
834249c3046Smrg	} else {
835444c061aSmrg	   if (ev.target == ctx->prop_list->indirect_atom) {
836444c061aSmrg	      IndirectPair *p;
837444c061aSmrg	      int format;
838444c061aSmrg	      unsigned long bytesafter, length;
839444c061aSmrg	      unsigned char *value;
840444c061aSmrg	      ev.property = event->xselectionrequest.property;
841444c061aSmrg	      StartProtectedSection(ev.display, ev.requestor);
842444c061aSmrg	      (void) XGetWindowProperty(ev.display, ev.requestor,
843444c061aSmrg			event->xselectionrequest.property, 0L, 1000000,
844444c061aSmrg			False,(Atom)AnyPropertyType, &target, &format, &length,
845444c061aSmrg			&bytesafter, &value);
846444c061aSmrg	      count = BYTELENGTH(length, format) / sizeof(IndirectPair);
847444c061aSmrg	      for (p = (IndirectPair *)value; count; p++, count--) {
848444c061aSmrg		  EndProtectedSection(ctx->dpy);
849444c061aSmrg		  if (!GetConversion(ctx, (XSelectionRequestEvent*)event,
850444c061aSmrg				     p->target, p->property, widget)) {
851444c061aSmrg
852444c061aSmrg			p->target = None;
853444c061aSmrg			writeback = TRUE;
854444c061aSmrg			StartProtectedSection(ctx->dpy, ev.requestor);
855444c061aSmrg		  }
856444c061aSmrg	      }
857444c061aSmrg	      if (writeback)
858444c061aSmrg		XChangeProperty(ev.display, ev.requestor,
859444c061aSmrg			event->xselectionrequest.property, target,
860444c061aSmrg			format, PropModeReplace, value, (int)length);
861444c061aSmrg	      XFree((char *)value);
862444c061aSmrg	  } else /* not multiple */ {
863444c061aSmrg	       if (GetConversion(ctx, (XSelectionRequestEvent*)event,
864444c061aSmrg				 event->xselectionrequest.target,
865444c061aSmrg				 event->xselectionrequest.property,
866444c061aSmrg				 widget))
867444c061aSmrg		   ev.property = event->xselectionrequest.property;
868444c061aSmrg	       else {
869444c061aSmrg		   ev.property = None;
870444c061aSmrg		   StartProtectedSection(ctx->dpy, ev.requestor);
871444c061aSmrg	       }
872444c061aSmrg	   }
873444c061aSmrg      }
874444c061aSmrg      (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long)NULL,
875444c061aSmrg		   (XEvent *) &ev);
876444c061aSmrg
877444c061aSmrg      EndProtectedSection(ctx->dpy);
878444c061aSmrg
879444c061aSmrg      break;
880444c061aSmrg    }
881444c061aSmrg}
882444c061aSmrg
883444c061aSmrgstatic Boolean OwnSelection(
884444c061aSmrg    Widget widget,
885444c061aSmrg    Atom selection,
886444c061aSmrg    Time time,
887444c061aSmrg    XtConvertSelectionProc convert,
888444c061aSmrg    XtLoseSelectionProc lose,
889444c061aSmrg    XtSelectionDoneProc notify,
890444c061aSmrg    XtCancelConvertSelectionProc cancel,
891444c061aSmrg    XtPointer closure,
892444c061aSmrg    Boolean incremental)
893444c061aSmrg{
894444c061aSmrg    Select ctx;
895444c061aSmrg    Select oldctx = NULL;
896444c061aSmrg
897444c061aSmrg    if (!XtIsRealized(widget)) return False;
898444c061aSmrg
899444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
900444c061aSmrg    if (ctx->widget != widget || ctx->time != time ||
901444c061aSmrg	ctx->ref_count || ctx->was_disowned)
902444c061aSmrg    {
903444c061aSmrg	Boolean replacement = FALSE;
904444c061aSmrg	Window window = XtWindow(widget);
905444c061aSmrg	unsigned long serial = XNextRequest(ctx->dpy);
906444c061aSmrg        XSetSelectionOwner(ctx->dpy, selection, window, time);
907444c061aSmrg        if (XGetSelectionOwner(ctx->dpy, selection) != window)
908444c061aSmrg	    return FALSE;
909444c061aSmrg	if (ctx->ref_count) {	/* exchange is in-progress */
910444c061aSmrg#ifdef DEBUG_ACTIVE
911444c061aSmrg	    printf( "Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n",
912444c061aSmrg		    XtName(widget), (long)selection, ctx->ref_count );
913444c061aSmrg#endif
914444c061aSmrg	    if (ctx->widget != widget ||
915444c061aSmrg		ctx->convert != convert ||
916444c061aSmrg		ctx->loses != lose ||
917444c061aSmrg		ctx->notify != notify ||
918444c061aSmrg		ctx->owner_cancel != cancel ||
919444c061aSmrg		ctx->incremental != incremental ||
920444c061aSmrg		ctx->owner_closure != closure)
921444c061aSmrg	    {
922444c061aSmrg		if (ctx->widget == widget) {
923444c061aSmrg		    XtRemoveEventHandler(widget, (EventMask)0, TRUE,
924444c061aSmrg					HandleSelectionEvents, (XtPointer)ctx);
925444c061aSmrg		    XtRemoveCallback(widget, XtNdestroyCallback,
926444c061aSmrg				     WidgetDestroyed, (XtPointer)ctx);
927444c061aSmrg		    replacement = TRUE;
928444c061aSmrg		}
929444c061aSmrg		else if (!ctx->was_disowned) {
930444c061aSmrg		    oldctx = ctx;
931444c061aSmrg		}
932444c061aSmrg		ctx->free_when_done = TRUE;
933444c061aSmrg		ctx = NewContext(XtDisplay(widget), selection);
934444c061aSmrg	    }
935444c061aSmrg	    else if (!ctx->was_disowned) { /* current owner is new owner */
936444c061aSmrg		ctx->time = time;
937444c061aSmrg		return TRUE;
938444c061aSmrg	    }
939444c061aSmrg	}
940444c061aSmrg    	if (ctx->widget != widget || ctx->was_disowned || replacement) {
941444c061aSmrg	    if (ctx->widget && !ctx->was_disowned && !replacement) {
942444c061aSmrg		oldctx = ctx;
943444c061aSmrg		oldctx->free_when_done = TRUE;
944444c061aSmrg		ctx = NewContext(XtDisplay(widget), selection);
945444c061aSmrg	    }
946444c061aSmrg	    XtAddEventHandler(widget, (EventMask)0, TRUE,
947444c061aSmrg			      HandleSelectionEvents, (XtPointer)ctx);
948444c061aSmrg	    XtAddCallback(widget, XtNdestroyCallback,
949444c061aSmrg			  WidgetDestroyed, (XtPointer)ctx);
950444c061aSmrg	}
951444c061aSmrg	ctx->widget = widget;	/* Selection offically changes hands. */
952444c061aSmrg	ctx->time = time;
953444c061aSmrg	ctx->serial = serial;
954444c061aSmrg    }
955444c061aSmrg    ctx->convert = convert;
956444c061aSmrg    ctx->loses = lose;
957444c061aSmrg    ctx->notify = notify;
958444c061aSmrg    ctx->owner_cancel = cancel;
959444c061aSmrg    ctx->incremental = incremental;
960444c061aSmrg    ctx->owner_closure = closure;
961444c061aSmrg    ctx->was_disowned = FALSE;
962444c061aSmrg
963444c061aSmrg    /* Defer calling the previous selection owner's lose selection procedure
964444c061aSmrg     * until the new selection is established, to allow the previous
965444c061aSmrg     * selection owner to ask for the new selection to be converted in
966444c061aSmrg     * the lose selection procedure.  The context pointer is the closure
967444c061aSmrg     * of the event handler and the destroy callback, so the old context
968444c061aSmrg     * pointer and the record contents must be preserved for LoseSelection.
969444c061aSmrg     */
970444c061aSmrg    if (oldctx) {
971444c061aSmrg	(void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time);
972444c061aSmrg	if (!oldctx->ref_count && oldctx->free_when_done)
973444c061aSmrg	    XtFree((char*)oldctx);
974444c061aSmrg    }
975444c061aSmrg    return TRUE;
976444c061aSmrg}
977444c061aSmrg
978444c061aSmrg
979444c061aSmrgBoolean XtOwnSelection(
980444c061aSmrg    Widget widget,
981444c061aSmrg    Atom selection,
982444c061aSmrg    Time time,
983444c061aSmrg    XtConvertSelectionProc convert,
984444c061aSmrg    XtLoseSelectionProc lose,
985444c061aSmrg    XtSelectionDoneProc notify)
986444c061aSmrg{
987444c061aSmrg    Boolean retval;
988444c061aSmrg    WIDGET_TO_APPCON(widget);
989444c061aSmrg
990444c061aSmrg    LOCK_APP(app);
991444c061aSmrg    retval = OwnSelection(widget, selection, time, convert, lose, notify,
992444c061aSmrg			(XtCancelConvertSelectionProc)NULL,
993444c061aSmrg			(XtPointer)NULL, FALSE);
994444c061aSmrg    UNLOCK_APP(app);
995444c061aSmrg    return retval;
996444c061aSmrg}
997444c061aSmrg
998444c061aSmrg
999444c061aSmrgBoolean XtOwnSelectionIncremental(
1000444c061aSmrg    Widget widget,
1001444c061aSmrg    Atom selection,
1002444c061aSmrg    Time time,
1003444c061aSmrg    XtConvertSelectionIncrProc convert,
1004444c061aSmrg    XtLoseSelectionIncrProc lose,
1005444c061aSmrg    XtSelectionDoneIncrProc notify,
1006444c061aSmrg    XtCancelConvertSelectionProc cancel,
1007444c061aSmrg    XtPointer closure)
1008444c061aSmrg{
1009444c061aSmrg    Boolean retval;
1010444c061aSmrg    WIDGET_TO_APPCON(widget);
1011444c061aSmrg
1012444c061aSmrg    LOCK_APP(app);
1013444c061aSmrg    retval = OwnSelection(widget, selection, time,
1014444c061aSmrg			(XtConvertSelectionProc)convert,
1015444c061aSmrg			(XtLoseSelectionProc)lose,
1016444c061aSmrg			(XtSelectionDoneProc)notify,
1017444c061aSmrg			cancel, closure, TRUE);
1018444c061aSmrg    UNLOCK_APP(app);
1019444c061aSmrg    return retval;
1020444c061aSmrg}
1021444c061aSmrg
1022444c061aSmrg
10232265a131Smrgvoid XtDisownSelection(
10242265a131Smrg    Widget widget,
10252265a131Smrg    Atom selection,
10262265a131Smrg    Time time)
1027444c061aSmrg{
1028444c061aSmrg    Select ctx;
1029444c061aSmrg    WIDGET_TO_APPCON(widget);
1030444c061aSmrg
1031444c061aSmrg    LOCK_APP(app);
1032444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1033444c061aSmrg    if (LoseSelection(ctx, widget, selection, time))
1034444c061aSmrg	XSetSelectionOwner(XtDisplay(widget), selection, None, time);
1035444c061aSmrg    UNLOCK_APP(app);
1036444c061aSmrg}
1037444c061aSmrg
1038444c061aSmrg/* Selection Requestor code */
1039444c061aSmrg
1040444c061aSmrgstatic Boolean IsINCRtype(
1041444c061aSmrg    CallBackInfo info,
1042444c061aSmrg    Window window,
1043444c061aSmrg    Atom prop)
1044444c061aSmrg{
1045444c061aSmrg    unsigned long bytesafter;
1046444c061aSmrg    unsigned long length;
1047444c061aSmrg    int format;
1048444c061aSmrg    Atom type;
1049444c061aSmrg    unsigned char *value;
1050444c061aSmrg
1051444c061aSmrg    if (prop == None) return False;
1052444c061aSmrg
1053444c061aSmrg    (void)XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L,
1054444c061aSmrg			     False, info->ctx->prop_list->incr_atom,
1055444c061aSmrg			     &type, &format, &length, &bytesafter, &value);
1056444c061aSmrg
1057444c061aSmrg    return (type == info->ctx->prop_list->incr_atom);
1058444c061aSmrg}
1059444c061aSmrg
1060444c061aSmrg/*ARGSUSED*/
1061444c061aSmrgstatic void ReqCleanup(
1062444c061aSmrg    Widget widget,
1063444c061aSmrg    XtPointer closure,
1064444c061aSmrg    XEvent *ev,
1065444c061aSmrg    Boolean *cont)
1066444c061aSmrg{
1067444c061aSmrg    CallBackInfo info = (CallBackInfo)closure;
1068444c061aSmrg    unsigned long bytesafter, length;
1069444c061aSmrg    char *value;
1070444c061aSmrg    int format;
1071444c061aSmrg    Atom target;
1072444c061aSmrg
1073444c061aSmrg    if (ev->type == SelectionNotify) {
1074444c061aSmrg	XSelectionEvent *event = (XSelectionEvent *) ev;
1075444c061aSmrg	if (!MATCH_SELECT(event, info)) return; /* not really for us */
1076444c061aSmrg         XtRemoveEventHandler(widget, (EventMask)0, TRUE,
1077444c061aSmrg			   ReqCleanup, (XtPointer) info );
1078444c061aSmrg	if (IsINCRtype(info, XtWindow(widget), event->property)) {
1079444c061aSmrg	    info->proc = HandleGetIncrement;
1080444c061aSmrg	    XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
1081444c061aSmrg			      FALSE, ReqCleanup, (XtPointer) info);
1082444c061aSmrg	} else {
1083444c061aSmrg	   if (event->property != None)
1084444c061aSmrg		XDeleteProperty(event->display, XtWindow(widget),
1085444c061aSmrg				event->property);
1086444c061aSmrg           FreeSelectionProperty(XtDisplay(widget), info->property);
1087444c061aSmrg	   FreeInfo(info);
1088444c061aSmrg	}
1089444c061aSmrg    } else if ((ev->type == PropertyNotify) &&
1090444c061aSmrg		(ev->xproperty.state == PropertyNewValue) &&
1091444c061aSmrg	        (ev->xproperty.atom == info->property)) {
1092444c061aSmrg	XPropertyEvent *event = (XPropertyEvent *) ev;
1093444c061aSmrg        (void) XGetWindowProperty(event->display, XtWindow(widget),
1094444c061aSmrg			   event->atom, 0L, 1000000, True, AnyPropertyType,
1095444c061aSmrg			   &target, &format, &length, &bytesafter,
1096444c061aSmrg			   (unsigned char **) &value);
1097444c061aSmrg	XFree(value);
1098444c061aSmrg	if (length == 0) {
1099444c061aSmrg           XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
1100444c061aSmrg			   ReqCleanup, (XtPointer) info );
1101444c061aSmrg           FreeSelectionProperty(XtDisplay(widget), info->property);
1102444c061aSmrg	   XtFree(info->value);	/* requestor never got this, so free now */
1103444c061aSmrg	   FreeInfo(info);
1104444c061aSmrg	}
1105444c061aSmrg    }
1106444c061aSmrg}
1107444c061aSmrg
1108444c061aSmrg/* ARGSUSED */
1109444c061aSmrgstatic void ReqTimedOut(
1110444c061aSmrg    XtPointer closure,
1111444c061aSmrg    XtIntervalId   *id)
1112444c061aSmrg{
1113444c061aSmrg    XtPointer value = NULL;
1114444c061aSmrg    unsigned long length = 0;
1115444c061aSmrg    int format = 8;
1116444c061aSmrg    Atom resulttype = XT_CONVERT_FAIL;
1117444c061aSmrg    CallBackInfo info = (CallBackInfo)closure;
1118444c061aSmrg    unsigned long bytesafter;
1119444c061aSmrg    unsigned long proplength;
1120444c061aSmrg    Atom type;
1121444c061aSmrg    IndirectPair *pairs;
1122444c061aSmrg    XtPointer *c;
1123444c061aSmrg    int i;
1124444c061aSmrg
1125444c061aSmrg    if (*info->target == info->ctx->prop_list->indirect_atom) {
1126444c061aSmrg        (void) XGetWindowProperty(XtDisplay(info->widget),
1127444c061aSmrg			   XtWindow(info->widget), info->property, 0L,
1128444c061aSmrg			   10000000, True, AnyPropertyType, &type, &format,
1129444c061aSmrg			   &proplength, &bytesafter, (unsigned char **) &pairs);
1130444c061aSmrg       XFree((char*)pairs);
1131444c061aSmrg       for (proplength = proplength / IndirectPairWordSize, i = 0, c = info->req_closure;
1132444c061aSmrg	           proplength; proplength--, c++, i++)
1133444c061aSmrg	    (*info->callbacks[i])(info->widget, *c,
1134444c061aSmrg   	          &info->ctx->selection, &resulttype, value, &length, &format);
1135444c061aSmrg    } else {
1136444c061aSmrg	(*info->callbacks[0])(info->widget, *info->req_closure,
1137444c061aSmrg	    &info->ctx->selection, &resulttype, value, &length, &format);
1138444c061aSmrg    }
1139444c061aSmrg
1140444c061aSmrg    /* change event handlers for straggler events */
1141444c061aSmrg    if (info->proc == (XtEventHandler)HandleSelectionReplies) {
1142444c061aSmrg        XtRemoveEventHandler(info->widget, (EventMask)0,
1143444c061aSmrg			TRUE, info->proc, (XtPointer) info);
1144444c061aSmrg	XtAddEventHandler(info->widget, (EventMask)0, TRUE,
1145444c061aSmrg		ReqCleanup, (XtPointer) info);
1146444c061aSmrg    } else {
1147444c061aSmrg        XtRemoveEventHandler(info->widget,(EventMask) PropertyChangeMask,
1148444c061aSmrg			FALSE, info->proc, (XtPointer) info);
1149444c061aSmrg	XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
1150444c061aSmrg		FALSE, ReqCleanup, (XtPointer) info);
1151444c061aSmrg    }
1152444c061aSmrg
1153444c061aSmrg}
1154444c061aSmrg
1155444c061aSmrg/*ARGSUSED*/
1156444c061aSmrgstatic void HandleGetIncrement(
1157444c061aSmrg    Widget widget,
1158444c061aSmrg    XtPointer closure,
1159444c061aSmrg    XEvent *ev,
1160444c061aSmrg    Boolean *cont)
1161444c061aSmrg{
1162444c061aSmrg    XPropertyEvent *event = (XPropertyEvent *) ev;
1163444c061aSmrg    CallBackInfo info = (CallBackInfo) closure;
1164444c061aSmrg    Select ctx = info->ctx;
1165444c061aSmrg    char *value;
1166444c061aSmrg    unsigned long bytesafter;
1167444c061aSmrg    unsigned long length;
1168444c061aSmrg    int bad;
1169444c061aSmrg    int n = info->current;
1170444c061aSmrg
1171444c061aSmrg    if ((event->state != PropertyNewValue) || (event->atom != info->property))
1172444c061aSmrg	 return;
1173444c061aSmrg
1174444c061aSmrg    bad = XGetWindowProperty(event->display, XtWindow(widget),
1175444c061aSmrg			     event->atom, 0L,
1176444c061aSmrg			     10000000, True, AnyPropertyType, &info->type,
1177444c061aSmrg			     &info->format, &length, &bytesafter,
1178444c061aSmrg			     (unsigned char **) &value);
1179444c061aSmrg    if (bad)
1180444c061aSmrg      return;
1181444c061aSmrg#ifndef DEBUG_WO_TIMERS
1182444c061aSmrg    XtRemoveTimeOut(info->timeout);
1183444c061aSmrg#endif
1184444c061aSmrg    if (length == 0) {
1185444c061aSmrg       unsigned long u_offset = NUMELEM(info->offset, info->format);
1186444c061aSmrg       (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection,
1187444c061aSmrg			     &info->type,
1188444c061aSmrg			     (info->offset == 0 ? value : info->value),
1189444c061aSmrg			     &u_offset, &info->format);
1190444c061aSmrg       /* assert ((info->offset != 0) == (info->incremental[n]) */
1191444c061aSmrg       if (info->offset != 0) XFree(value);
1192444c061aSmrg       XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
1193444c061aSmrg		HandleGetIncrement, (XtPointer) info);
1194444c061aSmrg       FreeSelectionProperty(event->display, info->property);
1195444c061aSmrg       FreeInfo(info);
1196444c061aSmrg    } else { /* add increment to collection */
1197444c061aSmrg      if (info->incremental[n]) {
1198444c061aSmrg#ifdef XT_COPY_SELECTION
1199444c061aSmrg	  int size = BYTELENGTH(length, info->format) + 1;
1200444c061aSmrg	  char *tmp = __XtMalloc((Cardinal) size);
1201444c061aSmrg	  (void) memmove(tmp, value, size);
1202444c061aSmrg	  XFree(value);
1203444c061aSmrg	  value = tmp;
1204444c061aSmrg#endif
1205444c061aSmrg        (*info->callbacks[n])(widget, *info->req_closure, &ctx->selection,
1206444c061aSmrg			      &info->type, value, &length, &info->format);
1207444c061aSmrg      } else {
1208444c061aSmrg	  int size = BYTELENGTH(length, info->format);
1209444c061aSmrg	  if (info->offset + size > info->bytelength) {
1210444c061aSmrg	      /* allocate enough for this and the next increment */
1211444c061aSmrg	      info->bytelength = info->offset + size * 2;
1212444c061aSmrg	      info->value = XtRealloc(info->value,
1213444c061aSmrg				      (Cardinal) info->bytelength);
1214444c061aSmrg	  }
1215444c061aSmrg	  (void) memmove(&info->value[info->offset], value, size);
1216444c061aSmrg	  info->offset += size;
1217444c061aSmrg	  XFree(value);
1218444c061aSmrg      }
1219444c061aSmrg     /* reset timer */
1220444c061aSmrg#ifndef DEBUG_WO_TIMERS
1221444c061aSmrg     {
1222444c061aSmrg     XtAppContext app = XtWidgetToApplicationContext(info->widget);
1223444c061aSmrg     info->timeout = XtAppAddTimeOut(app,
1224444c061aSmrg			 app->selectionTimeout, ReqTimedOut, (XtPointer) info);
1225444c061aSmrg     }
1226444c061aSmrg#endif
1227444c061aSmrg   }
1228444c061aSmrg}
1229444c061aSmrg
1230444c061aSmrg
1231444c061aSmrgstatic void HandleNone(
1232444c061aSmrg    Widget widget,
1233444c061aSmrg    XtSelectionCallbackProc callback,
1234444c061aSmrg    XtPointer closure,
1235444c061aSmrg    Atom selection)
1236444c061aSmrg{
1237444c061aSmrg    unsigned long length = 0;
1238444c061aSmrg    int format = 8;
1239444c061aSmrg    Atom type = None;
1240444c061aSmrg
1241444c061aSmrg    (*callback)(widget, closure, &selection,
1242444c061aSmrg		&type, NULL, &length, &format);
1243444c061aSmrg}
1244444c061aSmrg
1245444c061aSmrg
1246444c061aSmrgstatic long IncrPropSize(
1247444c061aSmrg     Widget widget,
1248444c061aSmrg     unsigned char* value,
1249444c061aSmrg     int format,
1250444c061aSmrg     unsigned long length)
1251444c061aSmrg{
1252444c061aSmrg    unsigned long size;
1253444c061aSmrg    if (format == 32) {
1254444c061aSmrg	size = ((long*)value)[length-1]; /* %%% what order for longs? */
1255444c061aSmrg	return size;
1256444c061aSmrg    }
1257444c061aSmrg    else {
1258444c061aSmrg	XtAppWarningMsg( XtWidgetToApplicationContext(widget),
1259444c061aSmrg			"badFormat","xtGetSelectionValue",XtCXtToolkitError,
1260444c061aSmrg	"Selection owner returned type INCR property with format != 32",
1261444c061aSmrg			(String*)NULL, (Cardinal*)NULL );
1262444c061aSmrg	return 0;
1263444c061aSmrg    }
1264444c061aSmrg}
1265444c061aSmrg
1266444c061aSmrg
1267444c061aSmrgstatic
1268444c061aSmrgBoolean HandleNormal(
1269444c061aSmrg    Display *dpy,
1270444c061aSmrg    Widget widget,
1271444c061aSmrg    Atom property,
1272444c061aSmrg    CallBackInfo info,
1273444c061aSmrg    XtPointer closure,
1274444c061aSmrg    Atom selection)
1275444c061aSmrg{
1276444c061aSmrg    unsigned long bytesafter;
1277444c061aSmrg    unsigned long length;
1278444c061aSmrg    int format;
1279444c061aSmrg    Atom type;
1280444c061aSmrg    unsigned char *value;
1281444c061aSmrg    int number = info->current;
1282444c061aSmrg
1283444c061aSmrg    (void) XGetWindowProperty(dpy, XtWindow(widget), property, 0L,
1284444c061aSmrg			      10000000, False, AnyPropertyType,
1285444c061aSmrg			      &type, &format, &length, &bytesafter, &value);
1286444c061aSmrg
1287444c061aSmrg    if (type == info->ctx->prop_list->incr_atom) {
1288444c061aSmrg	unsigned long size = IncrPropSize(widget, value, format, length);
1289444c061aSmrg	XFree((char *)value);
1290444c061aSmrg	if (info->property != property) {
1291444c061aSmrg	    /* within MULTIPLE */
1292444c061aSmrg	    CallBackInfo ninfo;
1293444c061aSmrg	    ninfo = MakeInfo(info->ctx, &info->callbacks[number],
1294444c061aSmrg			     &info->req_closure[number], 1, widget,
1295444c061aSmrg			     info->time, &info->incremental[number], &property);
1296444c061aSmrg	    ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom));
1297444c061aSmrg	    *ninfo->target = info->target[number + 1];
1298444c061aSmrg	    info = ninfo;
1299444c061aSmrg	}
1300444c061aSmrg	HandleIncremental(dpy, widget, property, info, size);
1301444c061aSmrg	return FALSE;
1302444c061aSmrg    }
1303444c061aSmrg
1304444c061aSmrg    XDeleteProperty(dpy, XtWindow(widget), property);
1305444c061aSmrg#ifdef XT_COPY_SELECTION
1306444c061aSmrg    if (value) {   /* it could have been deleted after the SelectionNotify */
1307444c061aSmrg	int size = BYTELENGTH(length, info->format) + 1;
1308444c061aSmrg	char *tmp = __XtMalloc((Cardinal) size);
1309444c061aSmrg	(void) memmove(tmp, value, size);
1310444c061aSmrg	XFree(value);
1311444c061aSmrg	value = (unsigned char *) tmp;
1312444c061aSmrg    }
1313444c061aSmrg#endif
1314444c061aSmrg    (*info->callbacks[number])(widget, closure, &selection,
1315444c061aSmrg			       &type, (XtPointer)value, &length, &format);
1316444c061aSmrg
1317444c061aSmrg    if (info->incremental[number]) {
1318444c061aSmrg	/* let requestor know the whole thing has been received */
1319444c061aSmrg	value = (unsigned char*)__XtMalloc((unsigned)1);
1320444c061aSmrg	length = 0;
1321444c061aSmrg	(*info->callbacks[number])(widget, closure, &selection,
1322444c061aSmrg				   &type, (XtPointer)value, &length, &format);
1323444c061aSmrg    }
1324444c061aSmrg    return TRUE;
1325444c061aSmrg}
1326444c061aSmrg
1327444c061aSmrgstatic void HandleIncremental(
1328444c061aSmrg    Display *dpy,
1329444c061aSmrg    Widget widget,
1330444c061aSmrg    Atom property,
1331444c061aSmrg    CallBackInfo info,
1332444c061aSmrg    unsigned long size)
1333444c061aSmrg{
1334444c061aSmrg    XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
1335444c061aSmrg		      HandleGetIncrement, (XtPointer) info);
1336444c061aSmrg
1337444c061aSmrg    /* now start the transfer */
1338444c061aSmrg    XDeleteProperty(dpy, XtWindow(widget), property);
1339444c061aSmrg    XFlush(dpy);
1340444c061aSmrg
1341444c061aSmrg    info->bytelength = size;
1342444c061aSmrg    if (info->incremental[info->current]) /* requestor wants incremental too */
1343444c061aSmrg	info->value = NULL;	/* so no need for buffer to assemble value */
1344444c061aSmrg    else
1345444c061aSmrg	info->value = (char *) __XtMalloc((unsigned) info->bytelength);
1346444c061aSmrg    info->offset = 0;
1347444c061aSmrg
1348444c061aSmrg    /* reset the timer */
1349444c061aSmrg    info->proc = HandleGetIncrement;
1350444c061aSmrg#ifndef DEBUG_WO_TIMERS
1351444c061aSmrg    {
1352444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(info->widget);
1353444c061aSmrg    info->timeout = XtAppAddTimeOut(app,
1354444c061aSmrg			 app->selectionTimeout, ReqTimedOut, (XtPointer) info);
1355444c061aSmrg    }
1356444c061aSmrg#endif
1357444c061aSmrg}
1358444c061aSmrg
1359444c061aSmrg/*ARGSUSED*/
1360444c061aSmrgstatic void HandleSelectionReplies(
1361444c061aSmrg    Widget widget,
1362444c061aSmrg    XtPointer closure,
1363444c061aSmrg    XEvent *ev,
1364444c061aSmrg    Boolean *cont)
1365444c061aSmrg{
1366444c061aSmrg    XSelectionEvent *event = (XSelectionEvent *) ev;
1367444c061aSmrg    Display *dpy = event->display;
1368444c061aSmrg    CallBackInfo info = (CallBackInfo) closure;
1369444c061aSmrg    Select ctx = info->ctx;
1370444c061aSmrg    IndirectPair *pairs, *p;
1371444c061aSmrg    unsigned long bytesafter;
1372444c061aSmrg    unsigned long length;
1373444c061aSmrg    int format;
1374444c061aSmrg    Atom type;
1375444c061aSmrg    XtPointer *c;
1376444c061aSmrg
1377444c061aSmrg    if (event->type != SelectionNotify) return;
1378444c061aSmrg    if (!MATCH_SELECT(event, info)) return; /* not really for us */
1379444c061aSmrg#ifndef DEBUG_WO_TIMERS
1380444c061aSmrg    XtRemoveTimeOut(info->timeout);
1381444c061aSmrg#endif
1382444c061aSmrg    XtRemoveEventHandler(widget, (EventMask)0, TRUE,
1383444c061aSmrg		HandleSelectionReplies, (XtPointer) info );
1384444c061aSmrg    if (event->target == ctx->prop_list->indirect_atom) {
1385444c061aSmrg        (void) XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L,
1386444c061aSmrg			   10000000, True, AnyPropertyType, &type, &format,
1387444c061aSmrg			   &length, &bytesafter, (unsigned char **) &pairs);
1388444c061aSmrg       for (length = length / IndirectPairWordSize, p = pairs,
1389444c061aSmrg	    c = info->req_closure;
1390444c061aSmrg	    length; length--, p++, c++, info->current++) {
1391444c061aSmrg	    if (event->property == None || format != 32 || p->target == None
1392444c061aSmrg		|| /* bug compatibility */ p->property == None) {
1393444c061aSmrg		HandleNone(widget, info->callbacks[info->current],
1394444c061aSmrg			   *c, event->selection);
1395444c061aSmrg		if (p->property != None)
1396444c061aSmrg                    FreeSelectionProperty(XtDisplay(widget), p->property);
1397444c061aSmrg	    } else {
1398444c061aSmrg		if (HandleNormal(dpy, widget, p->property, info, *c,
1399444c061aSmrg				 event->selection)) {
1400444c061aSmrg		    FreeSelectionProperty(XtDisplay(widget), p->property);
1401444c061aSmrg		}
1402444c061aSmrg	    }
1403444c061aSmrg       }
1404444c061aSmrg       XFree((char*)pairs);
1405444c061aSmrg       FreeSelectionProperty(dpy, info->property);
1406444c061aSmrg       FreeInfo(info);
1407444c061aSmrg    } else if (event->property == None) {
1408444c061aSmrg	HandleNone(widget, info->callbacks[0], *info->req_closure, event->selection);
1409444c061aSmrg        FreeSelectionProperty(XtDisplay(widget), info->property);
1410444c061aSmrg	FreeInfo(info);
1411444c061aSmrg    } else {
1412444c061aSmrg	if (HandleNormal(dpy, widget, event->property, info,
1413444c061aSmrg			 *info->req_closure, event->selection)) {
1414444c061aSmrg	    FreeSelectionProperty(XtDisplay(widget), info->property);
1415444c061aSmrg	    FreeInfo(info);
1416444c061aSmrg	}
1417444c061aSmrg    }
1418444c061aSmrg}
1419444c061aSmrg
1420444c061aSmrgstatic void DoLocalTransfer(
1421444c061aSmrg    Request req,
1422444c061aSmrg    Atom selection,
1423444c061aSmrg    Atom target,
1424444c061aSmrg    Widget widget,		/* The widget requesting the value. */
1425444c061aSmrg    XtSelectionCallbackProc callback,
1426444c061aSmrg    XtPointer closure,	/* the closure for the callback, not the conversion */
1427444c061aSmrg    Boolean incremental,
1428444c061aSmrg    Atom property)
1429444c061aSmrg{
1430444c061aSmrg    Select ctx = req->ctx;
1431444c061aSmrg    XtPointer value = NULL, temp, total = NULL;
1432444c061aSmrg    unsigned long length;
1433444c061aSmrg    int format;
1434444c061aSmrg    Atom resulttype;
1435444c061aSmrg    unsigned long totallength = 0;
1436444c061aSmrg
1437444c061aSmrg        req->event.type = 0;
1438444c061aSmrg        req->event.target = target;
1439444c061aSmrg        req->event.property = req->property = property;
1440444c061aSmrg        req->event.requestor = req->requestor = XtWindow(widget);
1441444c061aSmrg
1442444c061aSmrg	if (ctx->incremental) {
1443444c061aSmrg	   unsigned long size = MAX_SELECTION_INCR(ctx->dpy);
1444444c061aSmrg	   if (!(*(XtConvertSelectionIncrProc)ctx->convert)
1445444c061aSmrg			   (ctx->widget, &selection, &target,
1446444c061aSmrg			    &resulttype, &value, &length, &format,
1447444c061aSmrg			    &size, ctx->owner_closure, (XtRequestId*)&req)) {
1448444c061aSmrg	       HandleNone(widget, callback, closure, selection);
1449444c061aSmrg	   }
1450444c061aSmrg	   else {
1451444c061aSmrg		if (incremental) {
1452444c061aSmrg		  Boolean allSent = FALSE;
1453444c061aSmrg	          while (!allSent) {
1454444c061aSmrg	    	      if (ctx->notify && (value != NULL)) {
1455444c061aSmrg              	        int bytelength = BYTELENGTH(length,format);
1456444c061aSmrg	                /* both sides think they own this storage */
1457444c061aSmrg	                temp = __XtMalloc((unsigned)bytelength);
1458444c061aSmrg	                (void) memmove(temp, value, bytelength);
1459444c061aSmrg	                value = temp;
1460444c061aSmrg	              }
1461444c061aSmrg		      /* use care; older clients were never warned that
1462444c061aSmrg		       * they must return a value even if length==0
1463444c061aSmrg		       */
1464444c061aSmrg		     if (value == NULL) value = __XtMalloc((unsigned)1);
1465444c061aSmrg		     (*callback)(widget, closure, &selection,
1466444c061aSmrg			&resulttype, value, &length, &format);
1467444c061aSmrg		     if (length) {
1468444c061aSmrg			 /* should owner be notified on end-of-piece?
1469444c061aSmrg			  * Spec is unclear, but non-local transfers don't.
1470444c061aSmrg			  */
1471444c061aSmrg			 (*(XtConvertSelectionIncrProc)ctx->convert)
1472444c061aSmrg					(ctx->widget, &selection, &target,
1473444c061aSmrg					 &resulttype, &value, &length, &format,
1474444c061aSmrg					 &size, ctx->owner_closure,
1475444c061aSmrg					 (XtRequestId*)&req);
1476444c061aSmrg		     }
1477444c061aSmrg		     else allSent = TRUE;
1478444c061aSmrg		  }
1479444c061aSmrg	        } else {
1480444c061aSmrg	          while (length) {
1481444c061aSmrg		    int bytelength = BYTELENGTH(length, format);
1482444c061aSmrg		    total = XtRealloc(total,
1483444c061aSmrg			    (unsigned) (totallength += bytelength));
1484444c061aSmrg		    (void) memmove((char*)total + totallength - bytelength,
1485444c061aSmrg			    value,
1486444c061aSmrg			    bytelength);
1487444c061aSmrg		    (*(XtConvertSelectionIncrProc)ctx->convert)
1488444c061aSmrg			   (ctx->widget, &selection, &target,
1489444c061aSmrg			    &resulttype, &value, &length, &format,
1490444c061aSmrg			    &size, ctx->owner_closure, (XtRequestId*)&req);
1491444c061aSmrg		  }
1492444c061aSmrg		  if (total == NULL) total = __XtMalloc(1);
1493444c061aSmrg		  totallength = NUMELEM(totallength, format);
1494444c061aSmrg		  (*callback)(widget, closure, &selection, &resulttype,
1495444c061aSmrg		    total,  &totallength, &format);
1496444c061aSmrg	      }
1497444c061aSmrg	      if (ctx->notify)
1498444c061aSmrg		  (*(XtSelectionDoneIncrProc)ctx->notify)
1499444c061aSmrg				(ctx->widget, &selection, &target,
1500444c061aSmrg				 (XtRequestId*)&req, ctx->owner_closure);
1501444c061aSmrg	      else XtFree((char*)value);
1502444c061aSmrg	  }
1503444c061aSmrg	} else { /* not incremental owner */
1504444c061aSmrg	  if (!(*ctx->convert)(ctx->widget, &selection, &target,
1505444c061aSmrg			     &resulttype, &value, &length, &format)) {
1506444c061aSmrg	    HandleNone(widget, callback, closure, selection);
1507444c061aSmrg	  } else {
1508444c061aSmrg	      if (ctx->notify && (value != NULL)) {
1509444c061aSmrg                int bytelength = BYTELENGTH(length,format);
1510444c061aSmrg	        /* both sides think they own this storage; better copy */
1511444c061aSmrg	        temp = __XtMalloc((unsigned)bytelength);
1512444c061aSmrg	        (void) memmove(temp, value, bytelength);
1513444c061aSmrg	        value = temp;
1514444c061aSmrg	      }
1515444c061aSmrg	      if (value == NULL) value = __XtMalloc((unsigned)1);
1516444c061aSmrg	      (*callback)(widget, closure, &selection, &resulttype,
1517444c061aSmrg			  value, &length, &format);
1518444c061aSmrg	      if (ctx->notify)
1519444c061aSmrg	         (*ctx->notify)(ctx->widget, &selection, &target);
1520444c061aSmrg	  }
1521444c061aSmrg      }
1522444c061aSmrg}
1523444c061aSmrg
1524444c061aSmrgstatic void GetSelectionValue(
1525444c061aSmrg    Widget widget,
1526444c061aSmrg    Atom selection,
1527444c061aSmrg    Atom target,
1528444c061aSmrg    XtSelectionCallbackProc callback,
1529444c061aSmrg    XtPointer closure,
1530444c061aSmrg    Time time,
1531444c061aSmrg    Boolean incremental,
1532444c061aSmrg    Atom property)
1533444c061aSmrg{
1534444c061aSmrg    Select ctx;
1535444c061aSmrg    CallBackInfo info;
1536444c061aSmrg    Atom properties[1];
1537444c061aSmrg
1538444c061aSmrg    properties[0] = property;
1539444c061aSmrg
1540444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1541444c061aSmrg    if (ctx->widget && !ctx->was_disowned) {
1542444c061aSmrg	RequestRec req;
1543444c061aSmrg	ctx->req = &req;
1544444c061aSmrg	req.ctx = ctx;
1545444c061aSmrg	req.event.time = time;
1546444c061aSmrg	ctx->ref_count++;
1547444c061aSmrg	DoLocalTransfer(&req, selection, target, widget,
1548444c061aSmrg			callback, closure, incremental, property);
1549444c061aSmrg	if (--ctx->ref_count == 0 && ctx->free_when_done)
1550444c061aSmrg	    XtFree((char*)ctx);
1551444c061aSmrg	else
1552444c061aSmrg	    ctx->req = NULL;
1553444c061aSmrg    }
1554444c061aSmrg    else {
1555444c061aSmrg	info = MakeInfo(ctx, &callback, &closure, 1, widget,
1556444c061aSmrg			time, &incremental, properties);
1557444c061aSmrg	info->target = (Atom *)__XtMalloc((unsigned) sizeof(Atom));
1558444c061aSmrg	 *(info->target) = target;
1559444c061aSmrg	RequestSelectionValue(info, selection, target);
1560444c061aSmrg    }
1561444c061aSmrg}
1562444c061aSmrg
1563444c061aSmrg
1564444c061aSmrgvoid XtGetSelectionValue(
1565444c061aSmrg    Widget widget,
1566444c061aSmrg    Atom selection,
1567444c061aSmrg    Atom target,
1568444c061aSmrg    XtSelectionCallbackProc callback,
1569444c061aSmrg    XtPointer closure,
1570444c061aSmrg    Time time)
1571444c061aSmrg{
1572444c061aSmrg    Atom property;
1573444c061aSmrg    Boolean incr = False;
1574444c061aSmrg    WIDGET_TO_APPCON(widget);
1575444c061aSmrg
1576444c061aSmrg    LOCK_APP(app);
1577444c061aSmrg    property = GetParamInfo(widget, selection);
1578444c061aSmrg    RemoveParamInfo(widget, selection);
1579444c061aSmrg
1580444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1581444c061aSmrg      AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
1582444c061aSmrg			   &closure, &incr, &property);
1583444c061aSmrg    } else {
1584444c061aSmrg      GetSelectionValue(widget, selection, target, callback,
1585444c061aSmrg			closure, time, FALSE, property);
1586444c061aSmrg    }
1587444c061aSmrg    UNLOCK_APP(app);
1588444c061aSmrg}
1589444c061aSmrg
1590444c061aSmrg
1591444c061aSmrgvoid XtGetSelectionValueIncremental(
1592444c061aSmrg    Widget widget,
1593444c061aSmrg    Atom selection,
1594444c061aSmrg    Atom target,
1595444c061aSmrg    XtSelectionCallbackProc callback,
1596444c061aSmrg    XtPointer closure,
1597444c061aSmrg    Time time)
1598444c061aSmrg{
1599444c061aSmrg    Atom property;
1600444c061aSmrg    Boolean incr = TRUE;
1601444c061aSmrg    WIDGET_TO_APPCON(widget);
1602444c061aSmrg
1603444c061aSmrg    LOCK_APP(app);
1604444c061aSmrg    property = GetParamInfo(widget, selection);
1605444c061aSmrg    RemoveParamInfo(widget, selection);
1606444c061aSmrg
1607444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1608444c061aSmrg      AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
1609444c061aSmrg			   &closure, &incr, &property);
1610444c061aSmrg    } else {
1611444c061aSmrg      GetSelectionValue(widget, selection, target, callback,
1612444c061aSmrg			closure, time, TRUE, property);
1613444c061aSmrg    }
1614444c061aSmrg
1615444c061aSmrg    UNLOCK_APP(app);
1616444c061aSmrg}
1617444c061aSmrg
1618444c061aSmrg
1619444c061aSmrgstatic void GetSelectionValues(
1620444c061aSmrg    Widget widget,
1621444c061aSmrg    Atom selection,
1622444c061aSmrg    Atom *targets,
1623444c061aSmrg    int count,
1624444c061aSmrg    XtSelectionCallbackProc *callbacks,
1625444c061aSmrg    int num_callbacks,
1626444c061aSmrg    XtPointer *closures,
1627444c061aSmrg    Time time,
1628444c061aSmrg    Boolean *incremental,
1629444c061aSmrg    Atom *properties)
1630444c061aSmrg{
1631444c061aSmrg    Select ctx;
1632444c061aSmrg    CallBackInfo info;
1633444c061aSmrg    IndirectPair *pairs, *p;
1634444c061aSmrg    Atom *t;
1635444c061aSmrg
1636444c061aSmrg    if (count == 0) return;
1637444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1638444c061aSmrg    if (ctx->widget && !ctx->was_disowned) {
1639444c061aSmrg        int j, i;
1640444c061aSmrg	RequestRec req;
1641444c061aSmrg	ctx->req = &req;
1642444c061aSmrg	req.ctx = ctx;
1643444c061aSmrg	req.event.time = time;
1644444c061aSmrg	ctx->ref_count++;
1645444c061aSmrg	for (i = 0, j = 0; count; count--, i++, j++ ) {
1646444c061aSmrg	  if (j >= num_callbacks) j = 0;
1647444c061aSmrg
1648444c061aSmrg	  DoLocalTransfer(&req, selection, targets[i], widget,
1649444c061aSmrg			  callbacks[j], closures[i], incremental[i],
1650444c061aSmrg			  properties ? properties[i] : None);
1651444c061aSmrg
1652444c061aSmrg	}
1653444c061aSmrg	if (--ctx->ref_count == 0 && ctx->free_when_done)
1654444c061aSmrg	    XtFree((char*)ctx);
1655444c061aSmrg	else
1656444c061aSmrg	    ctx->req = NULL;
1657444c061aSmrg    } else {
1658444c061aSmrg        XtSelectionCallbackProc *passed_callbacks;
1659444c061aSmrg	XtSelectionCallbackProc stack_cbs[32];
1660444c061aSmrg        int i = 0, j = 0;
1661444c061aSmrg
1662444c061aSmrg	passed_callbacks = (XtSelectionCallbackProc *)
1663444c061aSmrg	  XtStackAlloc(sizeof(XtSelectionCallbackProc) * count, stack_cbs);
1664444c061aSmrg
1665444c061aSmrg	/* To deal with the old calls from XtGetSelectionValues* we
1666444c061aSmrg	   will repeat however many callbacks have been passed into
1667444c061aSmrg	   the array */
1668444c061aSmrg	for(i = 0; i < count; i++) {
1669444c061aSmrg	  if (j >= num_callbacks) j = 0;
1670444c061aSmrg	  passed_callbacks[i] = callbacks[j];
1671444c061aSmrg	  j++;
1672444c061aSmrg	}
1673444c061aSmrg	info = MakeInfo(ctx, passed_callbacks, closures, count, widget,
1674444c061aSmrg			time, incremental, properties);
1675444c061aSmrg	XtStackFree((XtPointer) passed_callbacks, stack_cbs);
1676444c061aSmrg
1677444c061aSmrg	info->target = (Atom *)__XtMalloc((unsigned) ((count+1) * sizeof(Atom)));
1678444c061aSmrg        (*info->target) = ctx->prop_list->indirect_atom;
1679444c061aSmrg	(void) memmove((char *) info->target+sizeof(Atom), (char *) targets,
1680444c061aSmrg		       count * sizeof(Atom));
1681444c061aSmrg	pairs = (IndirectPair*)__XtMalloc((unsigned)(count*sizeof(IndirectPair)));
1682444c061aSmrg	for (p = &pairs[count-1], t = &targets[count-1], i = count - 1;
1683444c061aSmrg	     p >= pairs;  p--, t--, i--) {
1684444c061aSmrg	   p->target = *t;
1685444c061aSmrg	   if (properties == NULL || properties[i] == None) {
1686444c061aSmrg	     p->property = GetSelectionProperty(XtDisplay(widget));
1687444c061aSmrg	     XDeleteProperty(XtDisplay(widget), XtWindow(widget),
1688444c061aSmrg			     p->property);
1689444c061aSmrg	   } else {
1690444c061aSmrg	     p->property = properties[i];
1691444c061aSmrg	   }
1692444c061aSmrg	}
1693444c061aSmrg	XChangeProperty(XtDisplay(widget), XtWindow(widget),
1694444c061aSmrg			info->property, info->property,
1695444c061aSmrg			32, PropModeReplace, (unsigned char *) pairs,
1696444c061aSmrg			count * IndirectPairWordSize);
1697444c061aSmrg	XtFree((char*)pairs);
1698444c061aSmrg	RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom);
1699444c061aSmrg    }
1700444c061aSmrg}
1701444c061aSmrg
1702444c061aSmrg
1703444c061aSmrgvoid XtGetSelectionValues(
1704444c061aSmrg    Widget widget,
1705444c061aSmrg    Atom selection,
1706444c061aSmrg    Atom *targets,
1707444c061aSmrg    int count,
1708444c061aSmrg    XtSelectionCallbackProc callback,
1709444c061aSmrg    XtPointer *closures,
1710444c061aSmrg    Time time)
1711444c061aSmrg{
1712444c061aSmrg    Boolean incremental_values[32];
1713444c061aSmrg    Boolean *incremental;
1714444c061aSmrg    int i;
1715444c061aSmrg    WIDGET_TO_APPCON(widget);
1716444c061aSmrg
1717444c061aSmrg    LOCK_APP(app);
1718444c061aSmrg    incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values);
1719444c061aSmrg    for(i = 0; i < count; i++) incremental[i] = FALSE;
1720444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1721444c061aSmrg      AddSelectionRequests(widget, selection, count, targets, &callback,
1722444c061aSmrg			   1, closures, incremental, NULL);
1723444c061aSmrg    } else {
1724444c061aSmrg      GetSelectionValues(widget, selection, targets, count, &callback, 1,
1725444c061aSmrg			 closures, time, incremental, NULL);
1726444c061aSmrg    }
1727444c061aSmrg    XtStackFree((XtPointer) incremental, incremental_values);
1728444c061aSmrg    UNLOCK_APP(app);
1729444c061aSmrg}
1730444c061aSmrg
1731444c061aSmrg
1732444c061aSmrgvoid XtGetSelectionValuesIncremental(
1733444c061aSmrg    Widget widget,
1734444c061aSmrg    Atom selection,
1735444c061aSmrg    Atom *targets,
1736444c061aSmrg    int count,
1737444c061aSmrg    XtSelectionCallbackProc callback,
1738444c061aSmrg    XtPointer *closures,
1739444c061aSmrg    Time time)
1740444c061aSmrg{
1741444c061aSmrg    Boolean incremental_values[32];
1742444c061aSmrg    Boolean *incremental;
1743444c061aSmrg    int i;
1744444c061aSmrg    WIDGET_TO_APPCON(widget);
1745444c061aSmrg
1746444c061aSmrg    LOCK_APP(app);
1747444c061aSmrg    incremental = XtStackAlloc(count * sizeof(Boolean), incremental_values);
1748444c061aSmrg    for(i = 0; i < count; i++) incremental[i] = TRUE;
1749444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1750444c061aSmrg      AddSelectionRequests(widget, selection, count, targets, &callback,
1751444c061aSmrg			   1, closures, incremental, NULL);
1752444c061aSmrg    } else {
1753444c061aSmrg      GetSelectionValues(widget, selection, targets, count,
1754444c061aSmrg			 &callback, 1, closures, time, incremental, NULL);
1755444c061aSmrg    }
1756444c061aSmrg    XtStackFree((XtPointer) incremental, incremental_values);
1757444c061aSmrg    UNLOCK_APP(app);
1758444c061aSmrg}
1759444c061aSmrg
1760444c061aSmrg
1761444c061aSmrgstatic Request GetRequestRecord(
1762444c061aSmrg    Widget widget,
1763444c061aSmrg    Atom selection,
1764444c061aSmrg    XtRequestId id)
1765444c061aSmrg{
1766444c061aSmrg    Request req = (Request)id;
1767444c061aSmrg    Select ctx = NULL;
1768444c061aSmrg
1769444c061aSmrg    if (   (req == NULL
1770444c061aSmrg	    && ((ctx = FindCtx( XtDisplay(widget), selection )) == NULL
1771444c061aSmrg		|| ctx->req == NULL
1772444c061aSmrg		|| ctx->selection != selection
1773444c061aSmrg		|| ctx->widget == NULL))
1774444c061aSmrg	|| (req != NULL
1775444c061aSmrg	    && (req->ctx == NULL
1776444c061aSmrg		|| req->ctx->selection != selection
1777444c061aSmrg		|| req->ctx->widget != widget)))
1778444c061aSmrg    {
1779444c061aSmrg	String params = XtName(widget);
1780444c061aSmrg	Cardinal num_params = 1;
1781444c061aSmrg	XtAppWarningMsg(XtWidgetToApplicationContext(widget),
1782444c061aSmrg			 "notInConvertSelection", "xtGetSelectionRequest",
1783444c061aSmrg			 XtCXtToolkitError,
1784444c061aSmrg			 "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc",
1785444c061aSmrg			 &params, &num_params
1786444c061aSmrg		       );
1787444c061aSmrg	return NULL;
1788444c061aSmrg    }
1789444c061aSmrg
1790444c061aSmrg    if (req == NULL) {
1791444c061aSmrg	/* non-incremental owner; only one request can be
1792444c061aSmrg	 * outstanding at a time, so it's safe to keep ptr in ctx */
1793444c061aSmrg	req = ctx->req;
1794444c061aSmrg    }
1795444c061aSmrg    return req;
1796444c061aSmrg}
1797444c061aSmrg
1798444c061aSmrgXSelectionRequestEvent *XtGetSelectionRequest(
1799444c061aSmrg    Widget widget,
1800444c061aSmrg    Atom selection,
1801444c061aSmrg    XtRequestId id)
1802444c061aSmrg{
1803444c061aSmrg    Request req = (Request)id;
1804444c061aSmrg    WIDGET_TO_APPCON(widget);
1805444c061aSmrg
1806444c061aSmrg    LOCK_APP(app);
1807444c061aSmrg
1808444c061aSmrg    req = GetRequestRecord(widget, selection, id);
1809444c061aSmrg
1810444c061aSmrg    if (! req) {
1811444c061aSmrg	UNLOCK_APP(app);
1812444c061aSmrg	return (XSelectionRequestEvent*) NULL;
1813444c061aSmrg    }
1814444c061aSmrg
1815444c061aSmrg    if (req->event.type == 0) {
1816444c061aSmrg	/* owner is local; construct the remainder of the event */
1817444c061aSmrg	req->event.type = SelectionRequest;
1818444c061aSmrg	req->event.serial = LastKnownRequestProcessed(XtDisplay(widget));
1819444c061aSmrg	req->event.send_event = True;
1820444c061aSmrg	req->event.display = XtDisplay(widget);
1821444c061aSmrg	req->event.owner = XtWindow(req->ctx->widget);
1822444c061aSmrg	req->event.selection = selection;
1823444c061aSmrg    }
1824444c061aSmrg    UNLOCK_APP(app);
1825444c061aSmrg    return &req->event;
1826444c061aSmrg}
1827444c061aSmrg
1828444c061aSmrg/* Property atom access */
1829444c061aSmrgAtom XtReservePropertyAtom(
1830444c061aSmrg     Widget w)
1831444c061aSmrg{
1832444c061aSmrg  return(GetSelectionProperty(XtDisplay(w)));
1833444c061aSmrg}
1834444c061aSmrg
1835444c061aSmrgvoid XtReleasePropertyAtom(
1836444c061aSmrg     Widget w,
1837444c061aSmrg     Atom atom)
1838444c061aSmrg{
1839444c061aSmrg  FreeSelectionProperty(XtDisplay(w), atom);
1840444c061aSmrg}
1841444c061aSmrg
1842444c061aSmrg
1843444c061aSmrg/* Multiple utilities */
1844444c061aSmrg
1845444c061aSmrg/* All requests are put in a single list per widget.  It is
1846444c061aSmrg   very unlikely anyone will be gathering multiple MULTIPLE
1847444c061aSmrg   requests at the same time,  so the loss in efficiency for
1848444c061aSmrg   this case is acceptable */
1849444c061aSmrg
1850444c061aSmrg/* Queue one or more requests to the one we're gathering */
1851444c061aSmrgstatic void AddSelectionRequests(
1852444c061aSmrg     Widget wid,
1853444c061aSmrg     Atom sel,
1854444c061aSmrg     int count,
1855444c061aSmrg     Atom *targets,
1856444c061aSmrg     XtSelectionCallbackProc *callbacks,
1857444c061aSmrg     int num_cb,
1858444c061aSmrg     XtPointer *closures,
1859444c061aSmrg     Boolean *incrementals,
1860444c061aSmrg     Atom *properties)
1861444c061aSmrg{
1862444c061aSmrg  QueuedRequestInfo qi;
1863444c061aSmrg  Window window = XtWindow(wid);
1864444c061aSmrg  Display *dpy = XtDisplay(wid);
1865444c061aSmrg
1866444c061aSmrg  LOCK_PROCESS;
1867444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
1868444c061aSmrg
1869444c061aSmrg  qi = NULL;
1870444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi);
1871444c061aSmrg
1872444c061aSmrg  if (qi != NULL) {
1873444c061aSmrg    QueuedRequest *req = qi->requests;
1874444c061aSmrg    int start = qi->count;
1875444c061aSmrg    int i = 0;
1876444c061aSmrg    int j = 0;
1877444c061aSmrg
1878444c061aSmrg    qi->count += count;
1879444c061aSmrg    req = (QueuedRequest*) XtRealloc((char*) req,
1880444c061aSmrg				     (start + count) *
1881444c061aSmrg				     sizeof(QueuedRequest));
1882444c061aSmrg    while(i < count) {
1883444c061aSmrg      QueuedRequest newreq = (QueuedRequest)
1884444c061aSmrg	__XtMalloc(sizeof(QueuedRequestRec));
1885444c061aSmrg      newreq->selection = sel;
1886444c061aSmrg      newreq->target = targets[i];
1887444c061aSmrg      if (properties != NULL)
1888444c061aSmrg	newreq->param = properties[i];
1889444c061aSmrg      else {
1890444c061aSmrg	newreq->param = GetSelectionProperty(dpy);
1891444c061aSmrg	XDeleteProperty(dpy, window, newreq->param);
1892444c061aSmrg      }
1893444c061aSmrg      newreq->callback = callbacks[j];
1894444c061aSmrg      newreq->closure = closures[i];
1895444c061aSmrg      newreq->incremental = incrementals[i];
1896444c061aSmrg
1897444c061aSmrg      req[start] = newreq;
1898444c061aSmrg      start++;
1899444c061aSmrg      i++;
1900444c061aSmrg      j++;
1901444c061aSmrg      if (j > num_cb) j = 0;
1902444c061aSmrg    }
1903444c061aSmrg
1904444c061aSmrg    qi->requests = req;
1905444c061aSmrg  } else {
1906444c061aSmrg    /* Impossible */
1907444c061aSmrg  }
1908444c061aSmrg
1909444c061aSmrg  UNLOCK_PROCESS;
1910444c061aSmrg}
1911444c061aSmrg
1912444c061aSmrg/* Only call IsGatheringRequest when we have a lock already */
1913444c061aSmrg
1914444c061aSmrgstatic Boolean IsGatheringRequest(
1915444c061aSmrg     Widget wid,
1916444c061aSmrg     Atom sel)
1917444c061aSmrg{
1918444c061aSmrg  QueuedRequestInfo qi;
1919444c061aSmrg  Window window = XtWindow(wid);
1920444c061aSmrg  Display *dpy = XtDisplay(wid);
1921444c061aSmrg  Boolean found = False;
1922444c061aSmrg  int i;
1923444c061aSmrg
1924444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
1925444c061aSmrg
1926444c061aSmrg  qi = NULL;
1927444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &qi);
1928444c061aSmrg
1929444c061aSmrg  if (qi != NULL) {
1930444c061aSmrg    i = 0;
1931444c061aSmrg    while(qi->selections[i] != None) {
1932444c061aSmrg      if (qi->selections[i] == sel) {
1933444c061aSmrg	found = True;
1934444c061aSmrg	break;
1935444c061aSmrg      }
1936444c061aSmrg      i++;
1937444c061aSmrg    }
1938444c061aSmrg  }
1939444c061aSmrg
1940444c061aSmrg  return(found);
1941444c061aSmrg}
1942444c061aSmrg
1943444c061aSmrg/* Cleanup request scans the request queue and releases any
1944444c061aSmrg   properties queued, and removes any requests queued */
1945444c061aSmrgstatic void CleanupRequest(
1946444c061aSmrg     Display *dpy,
1947444c061aSmrg     QueuedRequestInfo qi,
1948444c061aSmrg     Atom sel)
1949444c061aSmrg{
1950444c061aSmrg  int i, j, n;
1951444c061aSmrg
1952444c061aSmrg  i = 0;
1953444c061aSmrg
1954444c061aSmrg  /* Remove this selection from the list */
1955444c061aSmrg  n = 0;
1956444c061aSmrg  while(qi->selections[n] != sel &&
1957444c061aSmrg	qi->selections[n] != None) n++;
1958444c061aSmrg  if (qi->selections[n] == sel) {
1959444c061aSmrg    while(qi->selections[n] != None) {
1960444c061aSmrg      qi->selections[n] = qi->selections[n + 1];
1961444c061aSmrg      n++;
1962444c061aSmrg    }
1963444c061aSmrg  }
1964444c061aSmrg
1965444c061aSmrg  while(i < qi->count) {
1966444c061aSmrg    QueuedRequest req = qi->requests[i];
1967444c061aSmrg
1968444c061aSmrg    if (req->selection == sel) {
1969444c061aSmrg      /* Match */
1970444c061aSmrg      if (req->param != None)
1971444c061aSmrg	FreeSelectionProperty(dpy, req->param);
1972444c061aSmrg      qi->count--;
1973444c061aSmrg
1974444c061aSmrg      for(j = i; j < qi->count; j++)
1975444c061aSmrg	qi->requests[j] = qi->requests[j + 1];
1976444c061aSmrg
1977444c061aSmrg      XtFree((char*) req);
1978444c061aSmrg    } else {
1979444c061aSmrg      i++;
1980444c061aSmrg    }
1981444c061aSmrg  }
1982444c061aSmrg}
1983444c061aSmrg
19842265a131Smrgvoid XtCreateSelectionRequest(
1985444c061aSmrg    Widget widget,
1986444c061aSmrg    Atom selection)
1987444c061aSmrg{
1988444c061aSmrg  QueuedRequestInfo queueInfo;
1989444c061aSmrg  Window window = XtWindow(widget);
1990444c061aSmrg  Display *dpy = XtDisplay(widget);
1991444c061aSmrg  int n;
1992444c061aSmrg
1993444c061aSmrg  LOCK_PROCESS;
1994444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
1995444c061aSmrg
1996444c061aSmrg  queueInfo = NULL;
1997444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
1998444c061aSmrg
1999444c061aSmrg  /* If there is one,  then cancel it */
20002265a131Smrg  if (queueInfo != NULL)
2001444c061aSmrg    CleanupRequest(dpy, queueInfo, selection);
2002444c061aSmrg  else {
2003444c061aSmrg    /* Create it */
2004444c061aSmrg    queueInfo = (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec));
2005444c061aSmrg    queueInfo->count = 0;
2006444c061aSmrg    queueInfo->selections = (Atom*) __XtMalloc(sizeof(Atom) * 2);
2007444c061aSmrg    queueInfo->selections[0] = None;
2008444c061aSmrg    queueInfo->requests = (QueuedRequest *)
2009444c061aSmrg      __XtMalloc(sizeof(QueuedRequest));
2010444c061aSmrg  }
2011444c061aSmrg
2012444c061aSmrg  /* Append this selection to list */
2013444c061aSmrg  n = 0;
2014444c061aSmrg  while(queueInfo->selections[n] != None) n++;
2015444c061aSmrg  queueInfo->selections =
2016444c061aSmrg    (Atom*) XtRealloc((char*) queueInfo->selections,
2017444c061aSmrg		      (n + 2) * sizeof(Atom));
2018444c061aSmrg  queueInfo->selections[n] = selection;
2019444c061aSmrg  queueInfo->selections[n + 1] = None;
2020444c061aSmrg
2021444c061aSmrg  (void) XSaveContext(dpy, window, multipleContext, (char*) queueInfo);
2022444c061aSmrg  UNLOCK_PROCESS;
2023444c061aSmrg}
2024444c061aSmrg
20252265a131Smrgvoid XtSendSelectionRequest(
2026444c061aSmrg    Widget widget,
2027444c061aSmrg    Atom selection,
2028444c061aSmrg    Time time)
2029444c061aSmrg{
2030444c061aSmrg  QueuedRequestInfo queueInfo;
2031444c061aSmrg  Window window = XtWindow(widget);
2032444c061aSmrg  Display *dpy = XtDisplay(widget);
2033444c061aSmrg
2034444c061aSmrg  LOCK_PROCESS;
2035444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
2036444c061aSmrg
2037444c061aSmrg  queueInfo = NULL;
2038444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
2039444c061aSmrg  if (queueInfo != NULL) {
2040444c061aSmrg    int count = 0;
2041444c061aSmrg    int i;
2042444c061aSmrg    QueuedRequest *req = queueInfo->requests;
2043444c061aSmrg
2044444c061aSmrg    /* Construct the requests and send it using
2045444c061aSmrg       GetSelectionValues */
2046444c061aSmrg    for(i = 0; i < queueInfo->count; i++)
2047444c061aSmrg      if (req[i]->selection == selection) count++;
2048444c061aSmrg
2049444c061aSmrg    if (count > 0) {
2050444c061aSmrg      if (count == 1) {
2051444c061aSmrg	for(i = 0; i < queueInfo->count; i++)
2052444c061aSmrg	  if (req[i]->selection == selection) break;
2053444c061aSmrg
2054444c061aSmrg	/* special case a multiple which isn't needed */
2055444c061aSmrg	GetSelectionValue(widget, selection, req[i]->target,
2056444c061aSmrg			  req[i]->callback, req[i]->closure, time,
2057444c061aSmrg			  req[i]->incremental, req[i]->param);
2058444c061aSmrg      } else {
2059444c061aSmrg	Atom *targets;
2060444c061aSmrg	Atom t[PREALLOCED];
2061444c061aSmrg	XtSelectionCallbackProc *cbs;
2062444c061aSmrg	XtSelectionCallbackProc c[PREALLOCED];
2063444c061aSmrg	XtPointer *closures;
2064444c061aSmrg	XtPointer cs[PREALLOCED];
2065444c061aSmrg	Boolean *incrs;
2066444c061aSmrg	Boolean ins[PREALLOCED];
2067444c061aSmrg	Atom *props;
2068444c061aSmrg	Atom p[PREALLOCED];
2069444c061aSmrg	int i = 0;
2070444c061aSmrg	int j = 0;
2071444c061aSmrg
2072444c061aSmrg	/* Allocate */
2073444c061aSmrg	targets = (Atom *) XtStackAlloc(count * sizeof(Atom), t);
2074444c061aSmrg	cbs = (XtSelectionCallbackProc *)
2075444c061aSmrg	  XtStackAlloc(count * sizeof(XtSelectionCallbackProc), c);
2076444c061aSmrg	closures = (XtPointer *) XtStackAlloc(count * sizeof(XtPointer), cs);
2077444c061aSmrg	incrs = (Boolean *) XtStackAlloc(count * sizeof(Boolean), ins);
2078444c061aSmrg	props = (Atom *) XtStackAlloc(count * sizeof(Atom), p);
2079444c061aSmrg
2080444c061aSmrg	/* Copy */
2081444c061aSmrg	for(i = 0; i < queueInfo->count; i++) {
2082444c061aSmrg	  if (req[i]->selection == selection) {
2083444c061aSmrg	    targets[j] = req[i]->target;
2084444c061aSmrg	    cbs[j] = req[i]->callback;
2085444c061aSmrg	    closures[j] = req[i]->closure;
2086444c061aSmrg	    incrs[j] = req[i]->incremental;
2087444c061aSmrg	    props[j] = req[i]->param;
2088444c061aSmrg	    j++;
2089444c061aSmrg	  }
2090444c061aSmrg	}
2091444c061aSmrg
2092444c061aSmrg	/* Make the request */
2093444c061aSmrg	GetSelectionValues(widget, selection, targets, count,
2094444c061aSmrg			   cbs, count, closures, time, incrs, props);
2095444c061aSmrg
2096444c061aSmrg	/* Free */
2097444c061aSmrg	XtStackFree((XtPointer) targets, t);
2098444c061aSmrg	XtStackFree((XtPointer) cbs, c);
2099444c061aSmrg	XtStackFree((XtPointer) closures, cs);
2100444c061aSmrg	XtStackFree((XtPointer) incrs, ins);
2101444c061aSmrg	XtStackFree((XtPointer) props, p);
2102444c061aSmrg      }
2103444c061aSmrg    }
2104444c061aSmrg  }
2105444c061aSmrg
2106444c061aSmrg  CleanupRequest(dpy, queueInfo, selection);
2107444c061aSmrg  UNLOCK_PROCESS;
2108444c061aSmrg}
2109444c061aSmrg
21102265a131Smrgvoid XtCancelSelectionRequest(
2111444c061aSmrg    Widget widget,
2112444c061aSmrg    Atom selection)
2113444c061aSmrg{
2114444c061aSmrg  QueuedRequestInfo queueInfo;
2115444c061aSmrg  Window window = XtWindow(widget);
2116444c061aSmrg  Display *dpy = XtDisplay(widget);
2117444c061aSmrg
2118444c061aSmrg  LOCK_PROCESS;
2119444c061aSmrg  if (multipleContext == 0) multipleContext = XUniqueContext();
2120444c061aSmrg
2121444c061aSmrg  queueInfo = NULL;
2122444c061aSmrg  (void) XFindContext(dpy, window, multipleContext, (XPointer*) &queueInfo);
2123444c061aSmrg  /* If there is one,  then cancel it */
21242265a131Smrg  if (queueInfo != NULL)
2125444c061aSmrg    CleanupRequest(dpy, queueInfo, selection);
2126444c061aSmrg  UNLOCK_PROCESS;
2127444c061aSmrg}
2128444c061aSmrg
2129444c061aSmrg/* Parameter utilities */
2130444c061aSmrg
2131444c061aSmrg/* Parameters on a selection request */
2132444c061aSmrg/* Places data on allocated parameter atom,  then records the
2133444c061aSmrg   parameter atom data for use in the next call to one of
2134444c061aSmrg   the XtGetSelectionValue functions. */
2135444c061aSmrgvoid XtSetSelectionParameters(
2136444c061aSmrg    Widget requestor,
2137444c061aSmrg    Atom selection,
2138444c061aSmrg    Atom type,
2139444c061aSmrg    XtPointer value,
2140444c061aSmrg    unsigned long length,
2141444c061aSmrg    int format)
2142444c061aSmrg{
2143444c061aSmrg  Display *dpy = XtDisplay(requestor);
2144444c061aSmrg  Window window = XtWindow(requestor);
2145444c061aSmrg  Atom property = GetParamInfo(requestor, selection);
2146444c061aSmrg
2147444c061aSmrg  if (property == None) {
2148444c061aSmrg    property = GetSelectionProperty(dpy);
2149444c061aSmrg    AddParamInfo(requestor, selection, property);
2150444c061aSmrg  }
2151444c061aSmrg
2152444c061aSmrg  XChangeProperty(dpy, window, property,
2153444c061aSmrg		  type, format, PropModeReplace,
2154444c061aSmrg		  (unsigned char *) value, length);
2155444c061aSmrg}
2156444c061aSmrg
2157444c061aSmrg/* Retrieves data passed in a parameter. Data for this is stored
2158444c061aSmrg   on the originator's window */
2159444c061aSmrgvoid XtGetSelectionParameters(
2160444c061aSmrg    Widget owner,
2161444c061aSmrg    Atom selection,
2162444c061aSmrg    XtRequestId request_id,
2163444c061aSmrg    Atom* type_return,
2164444c061aSmrg    XtPointer* value_return,
2165444c061aSmrg    unsigned long* length_return,
2166444c061aSmrg    int* format_return)
2167444c061aSmrg{
2168444c061aSmrg    Request req;
2169444c061aSmrg    Display *dpy = XtDisplay(owner);
2170444c061aSmrg    WIDGET_TO_APPCON(owner);
2171444c061aSmrg
2172444c061aSmrg    *value_return = NULL;
2173444c061aSmrg    *length_return = *format_return = 0;
2174444c061aSmrg    *type_return = None;
2175444c061aSmrg
2176444c061aSmrg    LOCK_APP(app);
2177444c061aSmrg
2178444c061aSmrg    req = GetRequestRecord(owner, selection, request_id);
2179444c061aSmrg
2180444c061aSmrg    if (req && req->property) {
2181444c061aSmrg	unsigned long bytes_after;	/* unused */
2182444c061aSmrg	StartProtectedSection(dpy, req->requestor);
2183444c061aSmrg	XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000,
2184444c061aSmrg			   False, AnyPropertyType, type_return, format_return,
2185444c061aSmrg			   length_return, &bytes_after,
2186444c061aSmrg			   (unsigned char**) value_return);
2187444c061aSmrg	EndProtectedSection(dpy);
2188444c061aSmrg#ifdef XT_COPY_SELECTION
2189444c061aSmrg	if (*value_return) {
2190444c061aSmrg	    int size = BYTELENGTH(*length_return, *format_return) + 1;
2191444c061aSmrg	    char *tmp = __XtMalloc((Cardinal) size);
2192444c061aSmrg	    (void) memmove(tmp, *value_return, size);
2193444c061aSmrg	    XFree(*value_return);
2194444c061aSmrg	    *value_return = tmp;
2195444c061aSmrg	}
2196444c061aSmrg#endif
2197444c061aSmrg    }
2198444c061aSmrg    UNLOCK_APP(app);
2199444c061aSmrg}
2200444c061aSmrg
2201444c061aSmrg/*  Parameters are temporarily stashed in an XContext.  A list is used because
2202444c061aSmrg *  there may be more than one selection request in progress.  The context
2203444c061aSmrg *  data is deleted when the list is empty.  In the future, the parameter
2204444c061aSmrg *  context could be merged with other contexts used during selections.
2205444c061aSmrg */
2206444c061aSmrg
2207444c061aSmrgstatic void AddParamInfo(
2208444c061aSmrg    Widget w,
2209444c061aSmrg    Atom selection,
2210444c061aSmrg    Atom param_atom)
2211444c061aSmrg{
2212444c061aSmrg    int n;
2213444c061aSmrg    Param p;
2214444c061aSmrg    ParamInfo pinfo;
2215444c061aSmrg
2216444c061aSmrg    LOCK_PROCESS;
2217444c061aSmrg    if (paramPropertyContext == 0)
2218444c061aSmrg	paramPropertyContext = XUniqueContext();
2219444c061aSmrg
2220444c061aSmrg    if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2221444c061aSmrg		     (XPointer *) &pinfo)) {
2222444c061aSmrg	pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec));
2223444c061aSmrg	pinfo->count = 1;
2224444c061aSmrg	pinfo->paramlist = XtNew(ParamRec);
2225444c061aSmrg	p = pinfo->paramlist;
2226444c061aSmrg	(void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2227444c061aSmrg			    (char *)pinfo);
2228444c061aSmrg    }
2229444c061aSmrg    else {
2230444c061aSmrg	for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) {
2231444c061aSmrg	    if (p->selection == None || p->selection == selection)
2232444c061aSmrg		break;
2233444c061aSmrg	}
2234444c061aSmrg	if (n == 0) {
2235444c061aSmrg	    pinfo->count++;
2236444c061aSmrg	    pinfo->paramlist = (Param)
2237444c061aSmrg		XtRealloc((char*) pinfo->paramlist,
2238444c061aSmrg			  pinfo->count * sizeof(ParamRec));
2239444c061aSmrg	    p = &pinfo->paramlist[pinfo->count - 1];
2240444c061aSmrg	    (void) XSaveContext(XtDisplay(w), XtWindow(w),
2241444c061aSmrg				paramPropertyContext, (char *)pinfo);
2242444c061aSmrg	}
2243444c061aSmrg    }
2244444c061aSmrg    p->selection = selection;
2245444c061aSmrg    p->param = param_atom;
2246444c061aSmrg    UNLOCK_PROCESS;
2247444c061aSmrg}
2248444c061aSmrg
2249444c061aSmrgstatic void RemoveParamInfo(
2250444c061aSmrg    Widget w,
2251444c061aSmrg    Atom selection)
2252444c061aSmrg{
2253444c061aSmrg    int n;
2254444c061aSmrg    Param p;
2255444c061aSmrg    ParamInfo pinfo;
2256444c061aSmrg    Boolean retain = False;
2257444c061aSmrg
2258444c061aSmrg    LOCK_PROCESS;
2259444c061aSmrg    if (paramPropertyContext
2260444c061aSmrg	&& (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2261444c061aSmrg			 (XPointer *) &pinfo) == 0)) {
2262444c061aSmrg
2263444c061aSmrg	/* Find and invalidate the parameter data. */
2264444c061aSmrg	for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++) {
2265444c061aSmrg	    if (p->selection != None) {
2266444c061aSmrg		if (p->selection == selection)
2267444c061aSmrg		    p->selection = None;
2268444c061aSmrg		else
2269444c061aSmrg		    retain = True;
2270444c061aSmrg	    }
2271444c061aSmrg	}
2272444c061aSmrg	/* If there's no valid data remaining, release the context entry. */
2273444c061aSmrg	if (! retain) {
2274444c061aSmrg	    XtFree((char*) pinfo->paramlist);
2275444c061aSmrg	    XtFree((char*) pinfo);
2276444c061aSmrg	    XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext);
2277444c061aSmrg	}
2278444c061aSmrg    }
2279444c061aSmrg    UNLOCK_PROCESS;
2280444c061aSmrg}
2281444c061aSmrg
2282444c061aSmrgstatic Atom GetParamInfo(
2283444c061aSmrg    Widget w,
2284444c061aSmrg    Atom selection)
2285444c061aSmrg{
2286444c061aSmrg    int n;
2287444c061aSmrg    Param p;
2288444c061aSmrg    ParamInfo pinfo;
2289444c061aSmrg    Atom atom = None;
2290444c061aSmrg
2291444c061aSmrg    LOCK_PROCESS;
2292444c061aSmrg    if (paramPropertyContext
2293444c061aSmrg	&& (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2294444c061aSmrg			 (XPointer *) &pinfo) == 0)) {
2295444c061aSmrg
2296444c061aSmrg	for (n = pinfo->count, p = pinfo->paramlist; n; n--, p++)
2297444c061aSmrg	    if (p->selection == selection) {
2298444c061aSmrg		atom = p->param;
2299444c061aSmrg		break;
2300444c061aSmrg	    }
2301444c061aSmrg    }
2302444c061aSmrg    UNLOCK_PROCESS;
2303444c061aSmrg    return atom;
2304444c061aSmrg}
2305