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