Selection.c revision a3bd7f05
1444c061aSmrg/***********************************************************
2249c3046SmrgCopyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
31477040fSmrg
41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
51477040fSmrgcopy of this software and associated documentation files (the "Software"),
61477040fSmrgto deal in the Software without restriction, including without limitation
71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
91477040fSmrgSoftware is furnished to do so, subject to the following conditions:
101477040fSmrg
111477040fSmrgThe above copyright notice and this permission notice (including the next
121477040fSmrgparagraph) shall be included in all copies or substantial portions of the
131477040fSmrgSoftware.
141477040fSmrg
151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211477040fSmrgDEALINGS IN THE SOFTWARE.
221477040fSmrg
231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24444c061aSmrg
25444c061aSmrg                        All Rights Reserved
26444c061aSmrg
27444c061aSmrgPermission to use, copy, modify, and distribute this software and its
28444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
29444c061aSmrgprovided that the above copyright notice appear in all copies and that
30444c061aSmrgboth that copyright notice and this permission notice appear in
311477040fSmrgsupporting documentation, and that the name of Digital not be
32444c061aSmrgused in advertising or publicity pertaining to distribution of the
33444c061aSmrgsoftware without specific, written prior permission.
34444c061aSmrg
35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41444c061aSmrgSOFTWARE.
42444c061aSmrg
43444c061aSmrg******************************************************************/
44444c061aSmrg
45444c061aSmrg/*
46444c061aSmrg
47444c061aSmrgCopyright 1987, 1988, 1994, 1998  The Open Group
48444c061aSmrg
49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
51444c061aSmrgthe above copyright notice appear in all copies and that both that
52444c061aSmrgcopyright notice and this permission notice appear in supporting
53444c061aSmrgdocumentation.
54444c061aSmrg
55444c061aSmrgThe above copyright notice and this permission notice shall be included in
56444c061aSmrgall copies or substantial portions of the Software.
57444c061aSmrg
58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64444c061aSmrg
65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
67444c061aSmrgin this Software without prior written authorization from The Open Group.
68444c061aSmrg
69444c061aSmrg*/
70444c061aSmrg
71444c061aSmrg#ifdef HAVE_CONFIG_H
72444c061aSmrg#include <config.h>
73444c061aSmrg#endif
74444c061aSmrg#include "IntrinsicI.h"
75444c061aSmrg#include "StringDefs.h"
76444c061aSmrg#include "SelectionI.h"
77444c061aSmrg#include <X11/Xatom.h>
78444c061aSmrg#include <stdio.h>
79444c061aSmrg
80a3bd7f05Smrgvoid
81a3bd7f05Smrg_XtSetDefaultSelectionTimeout(unsigned long *timeout)
82444c061aSmrg{
83a3bd7f05Smrg    *timeout = 5000;            /* default to 5 seconds */
84444c061aSmrg}
85444c061aSmrg
86a3bd7f05Smrgvoid
87a3bd7f05SmrgXtSetSelectionTimeout(unsigned long timeout)
88444c061aSmrg{
89a3bd7f05Smrg    XtAppSetSelectionTimeout(_XtDefaultAppContext(), timeout);
90444c061aSmrg}
91444c061aSmrg
92a3bd7f05Smrgvoid
93a3bd7f05SmrgXtAppSetSelectionTimeout(XtAppContext app, unsigned long timeout)
94444c061aSmrg{
95a3bd7f05Smrg    LOCK_APP(app);
96a3bd7f05Smrg    app->selectionTimeout = timeout;
97a3bd7f05Smrg    UNLOCK_APP(app);
98444c061aSmrg}
99444c061aSmrg
100a3bd7f05Smrgunsigned long
101a3bd7f05SmrgXtGetSelectionTimeout(void)
102444c061aSmrg{
103a3bd7f05Smrg    return XtAppGetSelectionTimeout(_XtDefaultAppContext());
104444c061aSmrg}
105444c061aSmrg
106a3bd7f05Smrgunsigned long
107a3bd7f05SmrgXtAppGetSelectionTimeout(XtAppContext app)
108444c061aSmrg{
109a3bd7f05Smrg    unsigned long retval;
110444c061aSmrg
111a3bd7f05Smrg    LOCK_APP(app);
112a3bd7f05Smrg    retval = app->selectionTimeout;
113a3bd7f05Smrg    UNLOCK_APP(app);
114a3bd7f05Smrg    return retval;
115444c061aSmrg}
116444c061aSmrg
117444c061aSmrg/* General utilities */
118444c061aSmrg
119444c061aSmrgstatic void HandleSelectionReplies(Widget, XtPointer, XEvent *, Boolean *);
120444c061aSmrgstatic void ReqTimedOut(XtPointer, XtIntervalId *);
121444c061aSmrgstatic void HandlePropertyGone(Widget, XtPointer, XEvent *, Boolean *);
122444c061aSmrgstatic void HandleGetIncrement(Widget, XtPointer, XEvent *, Boolean *);
123a3bd7f05Smrgstatic void HandleIncremental(Display *, Widget, Atom, CallBackInfo,
124a3bd7f05Smrg                              unsigned long);
125444c061aSmrg
126444c061aSmrgstatic XContext selectPropertyContext = 0;
127444c061aSmrgstatic XContext paramPropertyContext = 0;
128444c061aSmrgstatic XContext multipleContext = 0;
129444c061aSmrg
130444c061aSmrg/* Multiple utilities */
131a3bd7f05Smrgstatic void AddSelectionRequests(Widget, Atom, int, Atom *,
132a3bd7f05Smrg                                 XtSelectionCallbackProc *, int, XtPointer *,
133a3bd7f05Smrg                                 Boolean *, Atom *);
134444c061aSmrgstatic Boolean IsGatheringRequest(Widget, Atom);
135444c061aSmrg
136444c061aSmrg#define PREALLOCED 32
137444c061aSmrg
138444c061aSmrg/* Parameter utilities */
139444c061aSmrgstatic void AddParamInfo(Widget, Atom, Atom);
140444c061aSmrgstatic void RemoveParamInfo(Widget, Atom);
141444c061aSmrgstatic Atom GetParamInfo(Widget, Atom);
142444c061aSmrg
143a3bd7f05Smrgstatic int StorageSize[3] = { 1, sizeof(short), sizeof(long) };
144a3bd7f05Smrg
1450568f49bSmrg#define BYTELENGTH(length, format) ((length) * (size_t)StorageSize[(format)>>4])
146444c061aSmrg#define NUMELEM(bytelength, format) ((bytelength) / StorageSize[(format)>>4])
1470568f49bSmrg#define NUMELEM2(bytelength, format) ((unsigned long)(bytelength) / (unsigned long) StorageSize[(format)>>4])
148444c061aSmrg
149444c061aSmrg/* Xlib and Xt are permitted to have different memory allocators, and in the
150444c061aSmrg * XtSelectionCallbackProc the client is instructed to free the selection
151444c061aSmrg * value with XtFree, so the selection value received from XGetWindowProperty
152444c061aSmrg * should be copied to memory allocated through Xt.  But copying is
153444c061aSmrg * undesirable since the selection value may be large, and, under normal
154444c061aSmrg * library configuration copying is unnecessary.
155444c061aSmrg */
156444c061aSmrg#ifdef XTTRACEMEMORY
157a3bd7f05Smrg#define XT_COPY_SELECTION       1
158444c061aSmrg#endif
159444c061aSmrg
160a3bd7f05Smrgstatic void
161a3bd7f05SmrgFreePropList(Widget w _X_UNUSED,
162a3bd7f05Smrg             XtPointer closure,
163a3bd7f05Smrg             XtPointer callData _X_UNUSED)
164444c061aSmrg{
165a3bd7f05Smrg    PropList sarray = (PropList) closure;
166a3bd7f05Smrg
167444c061aSmrg    LOCK_PROCESS;
168444c061aSmrg    XDeleteContext(sarray->dpy, DefaultRootWindow(sarray->dpy),
169a3bd7f05Smrg                   selectPropertyContext);
170444c061aSmrg    UNLOCK_PROCESS;
171a3bd7f05Smrg    XtFree((char *) sarray->list);
172a3bd7f05Smrg    XtFree((char *) closure);
173444c061aSmrg}
174444c061aSmrg
175a3bd7f05Smrgstatic PropList
176a3bd7f05SmrgGetPropList(Display *dpy)
177444c061aSmrg{
178444c061aSmrg    PropList sarray;
179444c061aSmrg
180444c061aSmrg    LOCK_PROCESS;
181444c061aSmrg    if (selectPropertyContext == 0)
182a3bd7f05Smrg        selectPropertyContext = XUniqueContext();
183444c061aSmrg    if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
184a3bd7f05Smrg                     (XPointer *) &sarray)) {
185a3bd7f05Smrg        Atom atoms[4];
186a3bd7f05Smrg
187a3bd7f05Smrg        static char *names[] = {
188a3bd7f05Smrg            "INCR",
189a3bd7f05Smrg            "MULTIPLE",
190a3bd7f05Smrg            "TIMESTAMP",
191a3bd7f05Smrg            "_XT_SELECTION_0"
192a3bd7f05Smrg        };
193a3bd7f05Smrg
194a3bd7f05Smrg        XtPerDisplay pd = _XtGetPerDisplay(dpy);
195a3bd7f05Smrg
196a3bd7f05Smrg        sarray = (PropList) __XtMalloc((unsigned) sizeof(PropListRec));
197a3bd7f05Smrg        sarray->dpy = dpy;
198a3bd7f05Smrg        XInternAtoms(dpy, names, 4, FALSE, atoms);
199a3bd7f05Smrg        sarray->incr_atom = atoms[0];
200a3bd7f05Smrg        sarray->indirect_atom = atoms[1];
201a3bd7f05Smrg        sarray->timestamp_atom = atoms[2];
202a3bd7f05Smrg        sarray->propCount = 1;
203a3bd7f05Smrg        sarray->list =
204a3bd7f05Smrg            (SelectionProp) __XtMalloc((unsigned) sizeof(SelectionPropRec));
205a3bd7f05Smrg        sarray->list[0].prop = atoms[3];
206a3bd7f05Smrg        sarray->list[0].avail = TRUE;
207a3bd7f05Smrg        (void) XSaveContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
208a3bd7f05Smrg                            (char *) sarray);
209a3bd7f05Smrg        _XtAddCallback(&pd->destroy_callbacks,
210a3bd7f05Smrg                       FreePropList, (XtPointer) sarray);
211444c061aSmrg    }
212444c061aSmrg    UNLOCK_PROCESS;
213444c061aSmrg    return sarray;
214444c061aSmrg}
215444c061aSmrg
216a3bd7f05Smrgstatic Atom
217a3bd7f05SmrgGetSelectionProperty(Display *dpy)
218444c061aSmrg{
219a3bd7f05Smrg    SelectionProp p;
220a3bd7f05Smrg    int propCount;
221a3bd7f05Smrg    char propname[80];
222a3bd7f05Smrg    PropList sarray = GetPropList(dpy);
223a3bd7f05Smrg
224a3bd7f05Smrg    for (p = sarray->list, propCount = sarray->propCount;
225a3bd7f05Smrg         propCount; p++, propCount--) {
226a3bd7f05Smrg        if (p->avail) {
227a3bd7f05Smrg            p->avail = FALSE;
228a3bd7f05Smrg            return (p->prop);
229a3bd7f05Smrg        }
230a3bd7f05Smrg    }
231a3bd7f05Smrg    propCount = sarray->propCount++;
232a3bd7f05Smrg    sarray->list = (SelectionProp) XtRealloc((XtPointer) sarray->list,
233a3bd7f05Smrg                                             (Cardinal) ((size_t) sarray->
234a3bd7f05Smrg                                                         propCount *
235a3bd7f05Smrg                                                         sizeof
236a3bd7f05Smrg                                                         (SelectionPropRec)));
237a3bd7f05Smrg    (void) snprintf(propname, sizeof(propname), "_XT_SELECTION_%d", propCount);
238a3bd7f05Smrg    sarray->list[propCount].prop = XInternAtom(dpy, propname, FALSE);
239a3bd7f05Smrg    sarray->list[propCount].avail = FALSE;
240a3bd7f05Smrg    return (sarray->list[propCount].prop);
241444c061aSmrg}
242444c061aSmrg
243a3bd7f05Smrgstatic void
244a3bd7f05SmrgFreeSelectionProperty(Display *dpy, Atom prop)
245444c061aSmrg{
246a3bd7f05Smrg    SelectionProp p;
247a3bd7f05Smrg    int propCount;
248a3bd7f05Smrg    PropList sarray;
249a3bd7f05Smrg
250a3bd7f05Smrg    if (prop == None)
251a3bd7f05Smrg        return;
252a3bd7f05Smrg    LOCK_PROCESS;
253a3bd7f05Smrg    if (XFindContext(dpy, DefaultRootWindow(dpy), selectPropertyContext,
254a3bd7f05Smrg                     (XPointer *) &sarray))
255a3bd7f05Smrg        XtAppErrorMsg(XtDisplayToApplicationContext(dpy),
256a3bd7f05Smrg                      "noSelectionProperties", "freeSelectionProperty",
257a3bd7f05Smrg                      XtCXtToolkitError,
258a3bd7f05Smrg                      "internal error: no selection property context for display",
259a3bd7f05Smrg                      NULL, NULL);
260a3bd7f05Smrg    UNLOCK_PROCESS;
261a3bd7f05Smrg    for (p = sarray->list, propCount = sarray->propCount;
262a3bd7f05Smrg         propCount; p++, propCount--)
263a3bd7f05Smrg        if (p->prop == prop) {
264a3bd7f05Smrg            p->avail = TRUE;
265a3bd7f05Smrg            return;
266a3bd7f05Smrg        }
267444c061aSmrg}
268444c061aSmrg
269a3bd7f05Smrgstatic void
270a3bd7f05SmrgFreeInfo(CallBackInfo info)
271444c061aSmrg{
272a3bd7f05Smrg    XtFree((char *) info->incremental);
273a3bd7f05Smrg    XtFree((char *) info->callbacks);
274a3bd7f05Smrg    XtFree((char *) info->req_closure);
275a3bd7f05Smrg    XtFree((char *) info->target);
276a3bd7f05Smrg    XtFree((char *) info);
277444c061aSmrg}
278444c061aSmrg
279a3bd7f05Smrgstatic CallBackInfo
280a3bd7f05SmrgMakeInfo(Select ctx,
281a3bd7f05Smrg         XtSelectionCallbackProc *callbacks,
282a3bd7f05Smrg         XtPointer *closures,
283a3bd7f05Smrg         int count,
284a3bd7f05Smrg         Widget widget,
285a3bd7f05Smrg         Time time,
286a3bd7f05Smrg         Boolean *incremental,
287a3bd7f05Smrg         Atom *properties)
288444c061aSmrg{
289a3bd7f05Smrg    CallBackInfo info = XtNew(CallBackInfoRec);
290a3bd7f05Smrg
291a3bd7f05Smrg    info->ctx = ctx;
292a3bd7f05Smrg    info->callbacks = (XtSelectionCallbackProc *)
293a3bd7f05Smrg        __XtMalloc((unsigned)
294a3bd7f05Smrg                   ((size_t) count * sizeof(XtSelectionCallbackProc)));
295a3bd7f05Smrg    (void) memmove((char *) info->callbacks, (char *) callbacks,
296a3bd7f05Smrg                   (size_t) count * sizeof(XtSelectionCallbackProc));
297a3bd7f05Smrg    info->req_closure = (XtPointer *)
298a3bd7f05Smrg        __XtMalloc((unsigned) ((size_t) count * sizeof(XtPointer)));
299a3bd7f05Smrg    (void) memmove((char *) info->req_closure, (char *) closures,
300a3bd7f05Smrg                   (size_t) count * sizeof(XtPointer));
301a3bd7f05Smrg    if (count == 1 && properties != NULL && properties[0] != None)
302a3bd7f05Smrg        info->property = properties[0];
303a3bd7f05Smrg    else {
304a3bd7f05Smrg        info->property = GetSelectionProperty(XtDisplay(widget));
305a3bd7f05Smrg        XDeleteProperty(XtDisplay(widget), XtWindow(widget), info->property);
306a3bd7f05Smrg    }
307a3bd7f05Smrg    info->proc = HandleSelectionReplies;
308a3bd7f05Smrg    info->widget = widget;
309a3bd7f05Smrg    info->time = time;
310a3bd7f05Smrg    info->incremental =
311a3bd7f05Smrg        (Boolean *) __XtMalloc((Cardinal) ((size_t) count * sizeof(Boolean)));
312a3bd7f05Smrg    (void) memmove((char *) info->incremental, (char *) incremental,
313a3bd7f05Smrg                   (size_t) count * sizeof(Boolean));
314a3bd7f05Smrg    info->current = 0;
315a3bd7f05Smrg    info->value = NULL;
316a3bd7f05Smrg    return (info);
317444c061aSmrg}
318444c061aSmrg
319a3bd7f05Smrgstatic void
320a3bd7f05SmrgRequestSelectionValue(CallBackInfo info, Atom selection, Atom target)
321444c061aSmrg{
322444c061aSmrg#ifndef DEBUG_WO_TIMERS
323444c061aSmrg    XtAppContext app = XtWidgetToApplicationContext(info->widget);
324a3bd7f05Smrg
325a3bd7f05Smrg    info->timeout = XtAppAddTimeOut(app,
326a3bd7f05Smrg                                    app->selectionTimeout, ReqTimedOut,
327a3bd7f05Smrg                                    (XtPointer) info);
328444c061aSmrg#endif
329a3bd7f05Smrg    XtAddEventHandler(info->widget, (EventMask) 0, TRUE,
330a3bd7f05Smrg                      HandleSelectionReplies, (XtPointer) info);
331a3bd7f05Smrg    XConvertSelection(info->ctx->dpy, selection, target,
332a3bd7f05Smrg                      info->property, XtWindow(info->widget), info->time);
333444c061aSmrg}
334444c061aSmrg
335444c061aSmrgstatic XContext selectContext = 0;
336444c061aSmrg
337a3bd7f05Smrgstatic Select
338a3bd7f05SmrgNewContext(Display *dpy, Atom selection)
339444c061aSmrg{
340444c061aSmrg    /* assert(selectContext != 0) */
341444c061aSmrg    Select ctx = XtNew(SelectRec);
342a3bd7f05Smrg
343444c061aSmrg    ctx->dpy = dpy;
344444c061aSmrg    ctx->selection = selection;
345444c061aSmrg    ctx->widget = NULL;
346444c061aSmrg    ctx->prop_list = GetPropList(dpy);
347444c061aSmrg    ctx->ref_count = 0;
348444c061aSmrg    ctx->free_when_done = FALSE;
349444c061aSmrg    ctx->was_disowned = FALSE;
350444c061aSmrg    LOCK_PROCESS;
351a3bd7f05Smrg    (void) XSaveContext(dpy, (Window) selection, selectContext, (char *) ctx);
352444c061aSmrg    UNLOCK_PROCESS;
353444c061aSmrg    return ctx;
354444c061aSmrg}
355444c061aSmrg
356a3bd7f05Smrgstatic Select
357a3bd7f05SmrgFindCtx(Display *dpy, Atom selection)
358444c061aSmrg{
359444c061aSmrg    Select ctx;
360444c061aSmrg
361444c061aSmrg    LOCK_PROCESS;
362444c061aSmrg    if (selectContext == 0)
363a3bd7f05Smrg        selectContext = XUniqueContext();
364a3bd7f05Smrg    if (XFindContext(dpy, (Window) selection, selectContext, (XPointer *) &ctx))
365a3bd7f05Smrg        ctx = NewContext(dpy, selection);
366444c061aSmrg    UNLOCK_PROCESS;
367444c061aSmrg    return ctx;
368444c061aSmrg}
369444c061aSmrg
370a3bd7f05Smrgstatic void
371a3bd7f05SmrgWidgetDestroyed(Widget widget, XtPointer closure, XtPointer data _X_UNUSED)
372444c061aSmrg{
373444c061aSmrg    Select ctx = (Select) closure;
374a3bd7f05Smrg
375444c061aSmrg    if (ctx->widget == widget) {
376a3bd7f05Smrg        if (ctx->free_when_done)
377a3bd7f05Smrg            XtFree((char *) ctx);
378a3bd7f05Smrg        else
379a3bd7f05Smrg            ctx->widget = NULL;
380444c061aSmrg    }
381444c061aSmrg}
382444c061aSmrg
383444c061aSmrg/* Selection Owner code */
384444c061aSmrg
385444c061aSmrgstatic void HandleSelectionEvents(Widget, XtPointer, XEvent *, Boolean *);
386444c061aSmrg
387a3bd7f05Smrgstatic Boolean
388a3bd7f05SmrgLoseSelection(Select ctx, Widget widget, Atom selection, Time time)
389444c061aSmrg{
390a3bd7f05Smrg    if ((ctx->widget == widget) && (ctx->selection == selection) &&     /* paranoia */
391a3bd7f05Smrg        !ctx->was_disowned && ((time == CurrentTime) || (time >= ctx->time))) {
392a3bd7f05Smrg        XtRemoveEventHandler(widget, (EventMask) 0, TRUE,
393a3bd7f05Smrg                             HandleSelectionEvents, (XtPointer) ctx);
394a3bd7f05Smrg        XtRemoveCallback(widget, XtNdestroyCallback,
395a3bd7f05Smrg                         WidgetDestroyed, (XtPointer) ctx);
396a3bd7f05Smrg        ctx->was_disowned = TRUE;       /* widget officially loses ownership */
397a3bd7f05Smrg        /* now inform widget */
398a3bd7f05Smrg        if (ctx->loses) {
399a3bd7f05Smrg            if (ctx->incremental)
400a3bd7f05Smrg                (*(XtLoseSelectionIncrProc) ctx->loses)
401a3bd7f05Smrg                    (widget, &ctx->selection, ctx->owner_closure);
402a3bd7f05Smrg            else
403a3bd7f05Smrg                (*ctx->loses) (widget, &ctx->selection);
404a3bd7f05Smrg        }
405a3bd7f05Smrg        return (TRUE);
406a3bd7f05Smrg    }
407a3bd7f05Smrg    else
408a3bd7f05Smrg        return (FALSE);
409444c061aSmrg}
410444c061aSmrg
411444c061aSmrgstatic XContext selectWindowContext = 0;
412444c061aSmrg
413444c061aSmrg/* %%% Xlib.h should make this public! */
414a3bd7f05Smrgtypedef int (*xErrorHandler) (Display *, XErrorEvent *);
415444c061aSmrg
416444c061aSmrgstatic xErrorHandler oldErrorHandler = NULL;
417444c061aSmrgstatic unsigned long firstProtectRequest;
418444c061aSmrgstatic Window errorWindow;
419444c061aSmrg
420a3bd7f05Smrgstatic int
421a3bd7f05SmrgLocalErrorHandler(Display *dpy, XErrorEvent *error)
422444c061aSmrg{
423444c061aSmrg    int retval;
424444c061aSmrg
425444c061aSmrg    /* If BadWindow error on selection requestor, nothing to do but let
426444c061aSmrg     * the transfer timeout.  Otherwise, invoke saved error handler. */
427444c061aSmrg
428444c061aSmrg    LOCK_PROCESS;
429444c061aSmrg
430444c061aSmrg    if (error->error_code == BadWindow && error->resourceid == errorWindow &&
431a3bd7f05Smrg        error->serial >= firstProtectRequest) {
432a3bd7f05Smrg        UNLOCK_PROCESS;
433a3bd7f05Smrg        return 0;
434444c061aSmrg    }
435444c061aSmrg
436444c061aSmrg    if (oldErrorHandler == NULL) {
437a3bd7f05Smrg        UNLOCK_PROCESS;
438a3bd7f05Smrg        return 0;               /* should never happen */
439444c061aSmrg    }
440444c061aSmrg
441a3bd7f05Smrg    retval = (*oldErrorHandler) (dpy, error);
442444c061aSmrg    UNLOCK_PROCESS;
443444c061aSmrg    return retval;
444444c061aSmrg}
445444c061aSmrg
446a3bd7f05Smrgstatic void
447a3bd7f05SmrgStartProtectedSection(Display *dpy, Window window)
448444c061aSmrg{
449444c061aSmrg    /* protect ourselves against request window being destroyed
450444c061aSmrg     * before completion of transfer */
451444c061aSmrg
452444c061aSmrg    LOCK_PROCESS;
453444c061aSmrg    oldErrorHandler = XSetErrorHandler(LocalErrorHandler);
454444c061aSmrg    firstProtectRequest = NextRequest(dpy);
455444c061aSmrg    errorWindow = window;
456444c061aSmrg    UNLOCK_PROCESS;
457444c061aSmrg}
458444c061aSmrg
459a3bd7f05Smrgstatic void
460a3bd7f05SmrgEndProtectedSection(Display *dpy)
461444c061aSmrg{
462444c061aSmrg    /* flush any generated errors on requestor and
463444c061aSmrg     * restore original error handler */
464444c061aSmrg
465444c061aSmrg    XSync(dpy, False);
466444c061aSmrg
467444c061aSmrg    LOCK_PROCESS;
468444c061aSmrg    XSetErrorHandler(oldErrorHandler);
469444c061aSmrg    oldErrorHandler = NULL;
470444c061aSmrg    UNLOCK_PROCESS;
471444c061aSmrg}
472444c061aSmrg
473a3bd7f05Smrgstatic void
474a3bd7f05SmrgAddHandler(Request req, EventMask mask, XtEventHandler proc, XtPointer closure)
475444c061aSmrg{
476444c061aSmrg    Display *dpy = req->ctx->dpy;
477444c061aSmrg    Window window = req->requestor;
478444c061aSmrg    Widget widget = XtWindowToWidget(dpy, window);
479444c061aSmrg
480a3bd7f05Smrg    if (widget != NULL)
481a3bd7f05Smrg        req->widget = widget;
482a3bd7f05Smrg    else
483a3bd7f05Smrg        widget = req->widget;
484444c061aSmrg
485444c061aSmrg    if (XtWindow(widget) == window)
486a3bd7f05Smrg        XtAddEventHandler(widget, mask, False, proc, closure);
487444c061aSmrg    else {
488a3bd7f05Smrg        RequestWindowRec *requestWindowRec;
489a3bd7f05Smrg
490a3bd7f05Smrg        LOCK_PROCESS;
491a3bd7f05Smrg        if (selectWindowContext == 0)
492a3bd7f05Smrg            selectWindowContext = XUniqueContext();
493a3bd7f05Smrg        if (XFindContext(dpy, window, selectWindowContext,
494a3bd7f05Smrg                         (XPointer *) &requestWindowRec)) {
495a3bd7f05Smrg            requestWindowRec = XtNew(RequestWindowRec);
496a3bd7f05Smrg            requestWindowRec->active_transfer_count = 0;
497a3bd7f05Smrg            (void) XSaveContext(dpy, window, selectWindowContext,
498a3bd7f05Smrg                                (char *) requestWindowRec);
499a3bd7f05Smrg        }
500a3bd7f05Smrg        UNLOCK_PROCESS;
501a3bd7f05Smrg        if (requestWindowRec->active_transfer_count++ == 0) {
502a3bd7f05Smrg            XtRegisterDrawable(dpy, window, widget);
503a3bd7f05Smrg            XSelectInput(dpy, window, (long) mask);
504a3bd7f05Smrg        }
505a3bd7f05Smrg        XtAddRawEventHandler(widget, mask, FALSE, proc, closure);
506444c061aSmrg    }
507444c061aSmrg}
508444c061aSmrg
509a3bd7f05Smrgstatic void
510a3bd7f05SmrgRemoveHandler(Request req,
511a3bd7f05Smrg              EventMask mask,
512a3bd7f05Smrg              XtEventHandler proc,
513a3bd7f05Smrg              XtPointer closure)
514444c061aSmrg{
515444c061aSmrg    Display *dpy = req->ctx->dpy;
516444c061aSmrg    Window window = req->requestor;
517444c061aSmrg    Widget widget = req->widget;
518444c061aSmrg
519444c061aSmrg    if ((XtWindowToWidget(dpy, window) == widget) &&
520444c061aSmrg        (XtWindow(widget) != window)) {
521a3bd7f05Smrg        /* we had to hang this window onto our widget; take it off */
522a3bd7f05Smrg        RequestWindowRec *requestWindowRec;
523a3bd7f05Smrg
524a3bd7f05Smrg        XtRemoveRawEventHandler(widget, mask, TRUE, proc, closure);
525a3bd7f05Smrg        LOCK_PROCESS;
526a3bd7f05Smrg        (void) XFindContext(dpy, window, selectWindowContext,
527a3bd7f05Smrg                            (XPointer *) &requestWindowRec);
528a3bd7f05Smrg        UNLOCK_PROCESS;
529a3bd7f05Smrg        if (--requestWindowRec->active_transfer_count == 0) {
530a3bd7f05Smrg            XtUnregisterDrawable(dpy, window);
531a3bd7f05Smrg            StartProtectedSection(dpy, window);
532a3bd7f05Smrg            XSelectInput(dpy, window, 0L);
533a3bd7f05Smrg            EndProtectedSection(dpy);
534a3bd7f05Smrg            LOCK_PROCESS;
535a3bd7f05Smrg            (void) XDeleteContext(dpy, window, selectWindowContext);
536a3bd7f05Smrg            UNLOCK_PROCESS;
537a3bd7f05Smrg            XtFree((char *) requestWindowRec);
538a3bd7f05Smrg        }
539a3bd7f05Smrg    }
540a3bd7f05Smrg    else {
541a3bd7f05Smrg        XtRemoveEventHandler(widget, mask, TRUE, proc, closure);
542444c061aSmrg    }
543444c061aSmrg}
544444c061aSmrg
545a3bd7f05Smrgstatic void
546a3bd7f05SmrgOwnerTimedOut(XtPointer closure, XtIntervalId *id _X_UNUSED)
547444c061aSmrg{
548a3bd7f05Smrg    Request req = (Request) closure;
549444c061aSmrg    Select ctx = req->ctx;
550444c061aSmrg
551444c061aSmrg    if (ctx->incremental && (ctx->owner_cancel != NULL)) {
552a3bd7f05Smrg        (*ctx->owner_cancel) (ctx->widget, &ctx->selection,
553a3bd7f05Smrg                              &req->target, (XtRequestId *) &req,
554a3bd7f05Smrg                              ctx->owner_closure);
555a3bd7f05Smrg    }
556a3bd7f05Smrg    else {
557a3bd7f05Smrg        if (ctx->notify == NULL)
558a3bd7f05Smrg            XtFree((char *) req->value);
559a3bd7f05Smrg        else {
560a3bd7f05Smrg            /* the requestor hasn't deleted the property, but
561a3bd7f05Smrg             * the owner needs to free the value.
562a3bd7f05Smrg             */
563a3bd7f05Smrg            if (ctx->incremental)
564a3bd7f05Smrg                (*(XtSelectionDoneIncrProc) ctx->notify)
565a3bd7f05Smrg                    (ctx->widget, &ctx->selection, &req->target,
566a3bd7f05Smrg                     (XtRequestId *) &req, ctx->owner_closure);
567a3bd7f05Smrg            else
568a3bd7f05Smrg                (*ctx->notify) (ctx->widget, &ctx->selection, &req->target);
569a3bd7f05Smrg        }
570a3bd7f05Smrg    }
571a3bd7f05Smrg
572a3bd7f05Smrg    RemoveHandler(req, (EventMask) PropertyChangeMask,
573a3bd7f05Smrg                  HandlePropertyGone, closure);
574a3bd7f05Smrg    XtFree((char *) req);
575444c061aSmrg    if (--ctx->ref_count == 0 && ctx->free_when_done)
576a3bd7f05Smrg        XtFree((char *) ctx);
577444c061aSmrg}
578444c061aSmrg
579a3bd7f05Smrgstatic void
580a3bd7f05SmrgSendIncrement(Request incr)
581444c061aSmrg{
582444c061aSmrg    Display *dpy = incr->ctx->dpy;
583444c061aSmrg
5840568f49bSmrg    unsigned long incrSize = (unsigned long) MAX_SELECTION_INCR(dpy);
585a3bd7f05Smrg
586444c061aSmrg    if (incrSize > incr->bytelength - incr->offset)
587444c061aSmrg        incrSize = incr->bytelength - incr->offset;
588444c061aSmrg    StartProtectedSection(dpy, incr->requestor);
589444c061aSmrg    XChangeProperty(dpy, incr->requestor, incr->property,
590a3bd7f05Smrg                    incr->type, incr->format, PropModeReplace,
591a3bd7f05Smrg                    (unsigned char *) incr->value + incr->offset,
592a3bd7f05Smrg                    NUMELEM((int) incrSize, incr->format));
593444c061aSmrg    EndProtectedSection(dpy);
594444c061aSmrg    incr->offset += incrSize;
595444c061aSmrg}
596444c061aSmrg
597a3bd7f05Smrgstatic void
598a3bd7f05SmrgAllSent(Request req)
599444c061aSmrg{
600444c061aSmrg    Select ctx = req->ctx;
601a3bd7f05Smrg
602444c061aSmrg    StartProtectedSection(ctx->dpy, req->requestor);
603444c061aSmrg    XChangeProperty(ctx->dpy, req->requestor,
604a3bd7f05Smrg                    req->property, req->type, req->format,
605a3bd7f05Smrg                    PropModeReplace, (unsigned char *) NULL, 0);
606444c061aSmrg    EndProtectedSection(ctx->dpy);
607444c061aSmrg    req->allSent = TRUE;
608444c061aSmrg
609a3bd7f05Smrg    if (ctx->notify == NULL)
610a3bd7f05Smrg        XtFree((char *) req->value);
611444c061aSmrg}
612444c061aSmrg
613a3bd7f05Smrgstatic void
614a3bd7f05SmrgHandlePropertyGone(Widget widget _X_UNUSED,
615a3bd7f05Smrg                   XtPointer closure,
616a3bd7f05Smrg                   XEvent *ev,
617a3bd7f05Smrg                   Boolean *cont _X_UNUSED)
618444c061aSmrg{
619444c061aSmrg    XPropertyEvent *event = (XPropertyEvent *) ev;
620a3bd7f05Smrg    Request req = (Request) closure;
621444c061aSmrg    Select ctx = req->ctx;
622444c061aSmrg
623444c061aSmrg    if ((event->type != PropertyNotify) ||
624444c061aSmrg        (event->state != PropertyDelete) ||
625a3bd7f05Smrg        (event->atom != req->property) || (event->window != req->requestor))
626a3bd7f05Smrg        return;
627444c061aSmrg#ifndef DEBUG_WO_TIMERS
628444c061aSmrg    XtRemoveTimeOut(req->timeout);
629444c061aSmrg#endif
630444c061aSmrg    if (req->allSent) {
631a3bd7f05Smrg        if (ctx->notify) {
632a3bd7f05Smrg            if (ctx->incremental) {
633a3bd7f05Smrg                (*(XtSelectionDoneIncrProc) ctx->notify)
634a3bd7f05Smrg                    (ctx->widget, &ctx->selection, &req->target,
635a3bd7f05Smrg                     (XtRequestId *) &req, ctx->owner_closure);
636a3bd7f05Smrg            }
637a3bd7f05Smrg            else
638a3bd7f05Smrg                (*ctx->notify) (ctx->widget, &ctx->selection, &req->target);
639a3bd7f05Smrg        }
640a3bd7f05Smrg        RemoveHandler(req, (EventMask) PropertyChangeMask,
641a3bd7f05Smrg                      HandlePropertyGone, closure);
642a3bd7f05Smrg        XtFree((char *) req);
643a3bd7f05Smrg        if (--ctx->ref_count == 0 && ctx->free_when_done)
644a3bd7f05Smrg            XtFree((char *) ctx);
645a3bd7f05Smrg    }
646a3bd7f05Smrg    else {                      /* is this part of an incremental transfer? */
647a3bd7f05Smrg        if (ctx->incremental) {
648a3bd7f05Smrg            if (req->bytelength == 0)
649a3bd7f05Smrg                AllSent(req);
650a3bd7f05Smrg            else {
651a3bd7f05Smrg                unsigned long size =
652a3bd7f05Smrg                    (unsigned long) MAX_SELECTION_INCR(ctx->dpy);
653a3bd7f05Smrg                SendIncrement(req);
654a3bd7f05Smrg                (*(XtConvertSelectionIncrProc) ctx->convert)
655a3bd7f05Smrg                    (ctx->widget, &ctx->selection, &req->target,
656a3bd7f05Smrg                     &req->type, &req->value,
657a3bd7f05Smrg                     &req->bytelength, &req->format,
658a3bd7f05Smrg                     &size, ctx->owner_closure, (XtPointer *) &req);
659a3bd7f05Smrg                if (req->bytelength)
660a3bd7f05Smrg                    req->bytelength = BYTELENGTH(req->bytelength, req->format);
661a3bd7f05Smrg                req->offset = 0;
662a3bd7f05Smrg            }
663a3bd7f05Smrg        }
664a3bd7f05Smrg        else {
665a3bd7f05Smrg            if (req->offset < req->bytelength)
666a3bd7f05Smrg                SendIncrement(req);
667a3bd7f05Smrg            else
668a3bd7f05Smrg                AllSent(req);
669a3bd7f05Smrg        }
670444c061aSmrg#ifndef DEBUG_WO_TIMERS
671a3bd7f05Smrg        {
672a3bd7f05Smrg            XtAppContext app = XtWidgetToApplicationContext(req->widget);
673a3bd7f05Smrg
674a3bd7f05Smrg            req->timeout = XtAppAddTimeOut(app,
675a3bd7f05Smrg                                           app->selectionTimeout, OwnerTimedOut,
676a3bd7f05Smrg                                           (XtPointer) req);
677a3bd7f05Smrg        }
678444c061aSmrg#endif
679444c061aSmrg    }
680444c061aSmrg}
681444c061aSmrg
682a3bd7f05Smrgstatic void
683a3bd7f05SmrgPrepareIncremental(Request req,
684a3bd7f05Smrg                   Widget widget,
685a3bd7f05Smrg                   Window window,
686a3bd7f05Smrg                   Atom property _X_UNUSED,
687a3bd7f05Smrg                   Atom target,
688a3bd7f05Smrg                   Atom targetType,
689a3bd7f05Smrg                   XtPointer value,
690a3bd7f05Smrg                   unsigned long length,
691a3bd7f05Smrg                   int format)
692444c061aSmrg{
693a3bd7f05Smrg    req->type = targetType;
694a3bd7f05Smrg    req->value = value;
695a3bd7f05Smrg    req->bytelength = BYTELENGTH(length, format);
696a3bd7f05Smrg    req->format = format;
697a3bd7f05Smrg    req->offset = 0;
698a3bd7f05Smrg    req->target = target;
699a3bd7f05Smrg    req->widget = widget;
700a3bd7f05Smrg    req->allSent = FALSE;
701444c061aSmrg#ifndef DEBUG_WO_TIMERS
702a3bd7f05Smrg    {
703a3bd7f05Smrg        XtAppContext app = XtWidgetToApplicationContext(widget);
704a3bd7f05Smrg
705a3bd7f05Smrg        req->timeout = XtAppAddTimeOut(app,
706a3bd7f05Smrg                                       app->selectionTimeout, OwnerTimedOut,
707a3bd7f05Smrg                                       (XtPointer) req);
708a3bd7f05Smrg    }
709444c061aSmrg#endif
710a3bd7f05Smrg    AddHandler(req, (EventMask) PropertyChangeMask,
711a3bd7f05Smrg               HandlePropertyGone, (XtPointer) req);
712444c061aSmrg/* now send client INCR property */
713a3bd7f05Smrg    XChangeProperty(req->ctx->dpy, window, req->property,
714a3bd7f05Smrg                    req->ctx->prop_list->incr_atom,
715a3bd7f05Smrg                    32, PropModeReplace, (unsigned char *) &req->bytelength, 1);
716444c061aSmrg}
717444c061aSmrg
718a3bd7f05Smrgstatic Boolean
719a3bd7f05SmrgGetConversion(Select ctx,       /* logical owner */
720a3bd7f05Smrg              XSelectionRequestEvent *event,
721a3bd7f05Smrg              Atom target,
722a3bd7f05Smrg              Atom property,    /* requestor's property */
723a3bd7f05Smrg              Widget widget)    /* physical owner (receives events) */
724a3bd7f05Smrg{
725444c061aSmrg    XtPointer value = NULL;
726444c061aSmrg    unsigned long length;
727444c061aSmrg    int format;
728444c061aSmrg    Atom targetType;
729444c061aSmrg    Request req = XtNew(RequestRec);
730444c061aSmrg    Boolean timestamp_target = (target == ctx->prop_list->timestamp_atom);
731444c061aSmrg
732444c061aSmrg    req->ctx = ctx;
733444c061aSmrg    req->event = *event;
734444c061aSmrg    req->property = property;
735444c061aSmrg    req->requestor = event->requestor;
736444c061aSmrg
737444c061aSmrg    if (timestamp_target) {
738a3bd7f05Smrg        value = __XtMalloc(sizeof(long));
739a3bd7f05Smrg        *(long *) value = (long) ctx->time;
740a3bd7f05Smrg        targetType = XA_INTEGER;
741a3bd7f05Smrg        length = 1;
742a3bd7f05Smrg        format = 32;
743444c061aSmrg    }
744444c061aSmrg    else {
745a3bd7f05Smrg        ctx->ref_count++;
746a3bd7f05Smrg        if (ctx->incremental == TRUE) {
747a3bd7f05Smrg            unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy);
748a3bd7f05Smrg
749a3bd7f05Smrg            if ((*(XtConvertSelectionIncrProc) ctx->convert)
750a3bd7f05Smrg                (ctx->widget, &event->selection, &target,
751a3bd7f05Smrg                 &targetType, &value, &length, &format,
752a3bd7f05Smrg                 &size, ctx->owner_closure, (XtRequestId *) &req)
753a3bd7f05Smrg                == FALSE) {
754a3bd7f05Smrg                XtFree((char *) req);
755a3bd7f05Smrg                ctx->ref_count--;
756a3bd7f05Smrg                return (FALSE);
757a3bd7f05Smrg            }
758a3bd7f05Smrg            StartProtectedSection(ctx->dpy, event->requestor);
759a3bd7f05Smrg            PrepareIncremental(req, widget, event->requestor, property,
760a3bd7f05Smrg                               target, targetType, value, length, format);
761a3bd7f05Smrg            return (TRUE);
762a3bd7f05Smrg        }
763a3bd7f05Smrg        ctx->req = req;
764a3bd7f05Smrg        if ((*ctx->convert) (ctx->widget, &event->selection, &target,
765a3bd7f05Smrg                             &targetType, &value, &length, &format) == FALSE) {
766a3bd7f05Smrg            XtFree((char *) req);
767a3bd7f05Smrg            ctx->req = NULL;
768a3bd7f05Smrg            ctx->ref_count--;
769a3bd7f05Smrg            return (FALSE);
770a3bd7f05Smrg        }
771a3bd7f05Smrg        ctx->req = NULL;
772444c061aSmrg    }
773444c061aSmrg    StartProtectedSection(ctx->dpy, event->requestor);
774a3bd7f05Smrg    if (BYTELENGTH(length, format) <=
775a3bd7f05Smrg        (unsigned long) MAX_SELECTION_INCR(ctx->dpy)) {
776a3bd7f05Smrg        if (!timestamp_target) {
777a3bd7f05Smrg            if (ctx->notify != NULL) {
778a3bd7f05Smrg                req->target = target;
779a3bd7f05Smrg                req->widget = widget;
780a3bd7f05Smrg                req->allSent = TRUE;
781444c061aSmrg#ifndef DEBUG_WO_TIMERS
782a3bd7f05Smrg                {
783a3bd7f05Smrg                    XtAppContext app =
784a3bd7f05Smrg                        XtWidgetToApplicationContext(req->widget);
785a3bd7f05Smrg                    req->timeout =
786a3bd7f05Smrg                        XtAppAddTimeOut(app, app->selectionTimeout,
787a3bd7f05Smrg                                        OwnerTimedOut, (XtPointer) req);
788a3bd7f05Smrg                }
789444c061aSmrg#endif
790a3bd7f05Smrg                AddHandler(req, (EventMask) PropertyChangeMask,
791a3bd7f05Smrg                           HandlePropertyGone, (XtPointer) req);
792a3bd7f05Smrg            }
793a3bd7f05Smrg            else
794a3bd7f05Smrg                ctx->ref_count--;
795444c061aSmrg        }
796a3bd7f05Smrg        XChangeProperty(ctx->dpy, event->requestor, property,
797a3bd7f05Smrg                        targetType, format, PropModeReplace,
798a3bd7f05Smrg                        (unsigned char *) value, (int) length);
799a3bd7f05Smrg        /* free storage for client if no notify proc */
800a3bd7f05Smrg        if (timestamp_target || ctx->notify == NULL) {
801a3bd7f05Smrg            XtFree((char *) value);
802a3bd7f05Smrg            XtFree((char *) req);
803a3bd7f05Smrg        }
804a3bd7f05Smrg    }
805a3bd7f05Smrg    else {
806a3bd7f05Smrg        PrepareIncremental(req, widget, event->requestor, property,
807a3bd7f05Smrg                           target, targetType, value, length, format);
808a3bd7f05Smrg    }
809a3bd7f05Smrg    return (TRUE);
810444c061aSmrg}
811444c061aSmrg
812a3bd7f05Smrgstatic void
813a3bd7f05SmrgHandleSelectionEvents(Widget widget,
814a3bd7f05Smrg                      XtPointer closure,
815a3bd7f05Smrg                      XEvent *event,
816a3bd7f05Smrg                      Boolean *cont _X_UNUSED)
817444c061aSmrg{
818444c061aSmrg    Select ctx;
819444c061aSmrg    XSelectionEvent ev;
820444c061aSmrg    Atom target;
821444c061aSmrg
822444c061aSmrg    ctx = (Select) closure;
823444c061aSmrg    switch (event->type) {
824a3bd7f05Smrg    case SelectionClear:
825a3bd7f05Smrg        /* if this event is not for the selection we registered for,
826a3bd7f05Smrg         * don't do anything */
827a3bd7f05Smrg        if (ctx->selection != event->xselectionclear.selection ||
828a3bd7f05Smrg            ctx->serial > event->xselectionclear.serial)
829a3bd7f05Smrg            break;
830a3bd7f05Smrg        (void) LoseSelection(ctx, widget, event->xselectionclear.selection,
831a3bd7f05Smrg                             event->xselectionclear.time);
832a3bd7f05Smrg        break;
833a3bd7f05Smrg    case SelectionRequest:
834a3bd7f05Smrg        /* if this event is not for the selection we registered for,
835a3bd7f05Smrg         * don't do anything */
836a3bd7f05Smrg        if (ctx->selection != event->xselectionrequest.selection)
837a3bd7f05Smrg            break;
838a3bd7f05Smrg        ev.type = SelectionNotify;
839a3bd7f05Smrg        ev.display = event->xselectionrequest.display;
840a3bd7f05Smrg
841a3bd7f05Smrg        ev.requestor = event->xselectionrequest.requestor;
842a3bd7f05Smrg        ev.selection = event->xselectionrequest.selection;
843a3bd7f05Smrg        ev.time = event->xselectionrequest.time;
844a3bd7f05Smrg        ev.target = event->xselectionrequest.target;
845a3bd7f05Smrg        if (event->xselectionrequest.property == None)  /* obsolete requestor */
846a3bd7f05Smrg            event->xselectionrequest.property = event->xselectionrequest.target;
847a3bd7f05Smrg        if (ctx->widget != widget || ctx->was_disowned
848a3bd7f05Smrg            || ((event->xselectionrequest.time != CurrentTime)
849a3bd7f05Smrg                && (event->xselectionrequest.time < ctx->time))) {
850a3bd7f05Smrg            ev.property = None;
851a3bd7f05Smrg            StartProtectedSection(ev.display, ev.requestor);
852a3bd7f05Smrg        }
853a3bd7f05Smrg        else {
854a3bd7f05Smrg            if (ev.target == ctx->prop_list->indirect_atom) {
855a3bd7f05Smrg                IndirectPair *p;
856a3bd7f05Smrg                int format;
857a3bd7f05Smrg                unsigned long bytesafter, length;
858a3bd7f05Smrg                unsigned char *value = NULL;
859a3bd7f05Smrg                int count;
860a3bd7f05Smrg                Boolean writeback = FALSE;
861a3bd7f05Smrg
862a3bd7f05Smrg                ev.property = event->xselectionrequest.property;
863a3bd7f05Smrg                StartProtectedSection(ev.display, ev.requestor);
864a3bd7f05Smrg                if (XGetWindowProperty(ev.display, ev.requestor,
865a3bd7f05Smrg                                       event->xselectionrequest.property, 0L,
866a3bd7f05Smrg                                       1000000, False, (Atom) AnyPropertyType,
867a3bd7f05Smrg                                       &target, &format, &length, &bytesafter,
868a3bd7f05Smrg                                       &value) == Success)
869a3bd7f05Smrg                    count =
870a3bd7f05Smrg                        (int) (BYTELENGTH(length, format) /
871a3bd7f05Smrg                               sizeof(IndirectPair));
872a3bd7f05Smrg                else
873a3bd7f05Smrg                    count = 0;
874a3bd7f05Smrg                for (p = (IndirectPair *) value; count; p++, count--) {
875a3bd7f05Smrg                    EndProtectedSection(ctx->dpy);
876a3bd7f05Smrg                    if (!GetConversion(ctx, (XSelectionRequestEvent *) event,
877a3bd7f05Smrg                                       p->target, p->property, widget)) {
878a3bd7f05Smrg
879a3bd7f05Smrg                        p->target = None;
880a3bd7f05Smrg                        writeback = TRUE;
881a3bd7f05Smrg                        StartProtectedSection(ctx->dpy, ev.requestor);
882a3bd7f05Smrg                    }
883a3bd7f05Smrg                }
884a3bd7f05Smrg                if (writeback)
885a3bd7f05Smrg                    XChangeProperty(ev.display, ev.requestor,
886a3bd7f05Smrg                                    event->xselectionrequest.property, target,
887a3bd7f05Smrg                                    format, PropModeReplace, value,
888a3bd7f05Smrg                                    (int) length);
889a3bd7f05Smrg                XFree((char *) value);
890a3bd7f05Smrg            }
891a3bd7f05Smrg            else {              /* not multiple */
892a3bd7f05Smrg
893a3bd7f05Smrg                if (GetConversion(ctx, (XSelectionRequestEvent *) event,
894a3bd7f05Smrg                                  event->xselectionrequest.target,
895a3bd7f05Smrg                                  event->xselectionrequest.property, widget))
896a3bd7f05Smrg                    ev.property = event->xselectionrequest.property;
897a3bd7f05Smrg                else {
898a3bd7f05Smrg                    ev.property = None;
899a3bd7f05Smrg                    StartProtectedSection(ctx->dpy, ev.requestor);
900a3bd7f05Smrg                }
901a3bd7f05Smrg            }
902a3bd7f05Smrg        }
903a3bd7f05Smrg        (void) XSendEvent(ctx->dpy, ev.requestor, False, (unsigned long) NULL,
904a3bd7f05Smrg                          (XEvent *) &ev);
905a3bd7f05Smrg
906a3bd7f05Smrg        EndProtectedSection(ctx->dpy);
907a3bd7f05Smrg
908a3bd7f05Smrg        break;
909444c061aSmrg    }
910444c061aSmrg}
911444c061aSmrg
912a3bd7f05Smrgstatic Boolean
913a3bd7f05SmrgOwnSelection(Widget widget,
914a3bd7f05Smrg             Atom selection,
915a3bd7f05Smrg             Time time,
916a3bd7f05Smrg             XtConvertSelectionProc convert,
917a3bd7f05Smrg             XtLoseSelectionProc lose,
918a3bd7f05Smrg             XtSelectionDoneProc notify,
919a3bd7f05Smrg             XtCancelConvertSelectionProc cancel,
920a3bd7f05Smrg             XtPointer closure,
921a3bd7f05Smrg             Boolean incremental)
922444c061aSmrg{
923444c061aSmrg    Select ctx;
924444c061aSmrg    Select oldctx = NULL;
925444c061aSmrg
926a3bd7f05Smrg    if (!XtIsRealized(widget))
927a3bd7f05Smrg        return False;
928444c061aSmrg
929444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
930444c061aSmrg    if (ctx->widget != widget || ctx->time != time ||
931a3bd7f05Smrg        ctx->ref_count || ctx->was_disowned) {
932a3bd7f05Smrg        Boolean replacement = FALSE;
933a3bd7f05Smrg        Window window = XtWindow(widget);
934a3bd7f05Smrg        unsigned long serial = XNextRequest(ctx->dpy);
935a3bd7f05Smrg
936444c061aSmrg        XSetSelectionOwner(ctx->dpy, selection, window, time);
937444c061aSmrg        if (XGetSelectionOwner(ctx->dpy, selection) != window)
938a3bd7f05Smrg            return FALSE;
939a3bd7f05Smrg        if (ctx->ref_count) {   /* exchange is in-progress */
940444c061aSmrg#ifdef DEBUG_ACTIVE
941a3bd7f05Smrg            printf
942a3bd7f05Smrg                ("Active exchange for widget \"%s\"; selection=0x%lx, ref_count=%d\n",
943a3bd7f05Smrg                 XtName(widget), (long) selection, ctx->ref_count);
944444c061aSmrg#endif
945a3bd7f05Smrg            if (ctx->widget != widget ||
946a3bd7f05Smrg                ctx->convert != convert ||
947a3bd7f05Smrg                ctx->loses != lose ||
948a3bd7f05Smrg                ctx->notify != notify ||
949a3bd7f05Smrg                ctx->owner_cancel != cancel ||
950a3bd7f05Smrg                ctx->incremental != incremental ||
951a3bd7f05Smrg                ctx->owner_closure != closure) {
952a3bd7f05Smrg                if (ctx->widget == widget) {
953a3bd7f05Smrg                    XtRemoveEventHandler(widget, (EventMask) 0, TRUE,
954a3bd7f05Smrg                                         HandleSelectionEvents,
955a3bd7f05Smrg                                         (XtPointer) ctx);
956a3bd7f05Smrg                    XtRemoveCallback(widget, XtNdestroyCallback,
957a3bd7f05Smrg                                     WidgetDestroyed, (XtPointer) ctx);
958a3bd7f05Smrg                    replacement = TRUE;
959a3bd7f05Smrg                }
960a3bd7f05Smrg                else if (!ctx->was_disowned) {
961a3bd7f05Smrg                    oldctx = ctx;
962a3bd7f05Smrg                }
963a3bd7f05Smrg                ctx->free_when_done = TRUE;
964a3bd7f05Smrg                ctx = NewContext(XtDisplay(widget), selection);
965a3bd7f05Smrg            }
966a3bd7f05Smrg            else if (!ctx->was_disowned) {      /* current owner is new owner */
967a3bd7f05Smrg                ctx->time = time;
968a3bd7f05Smrg                return TRUE;
969a3bd7f05Smrg            }
970a3bd7f05Smrg        }
971a3bd7f05Smrg        if (ctx->widget != widget || ctx->was_disowned || replacement) {
972a3bd7f05Smrg            if (ctx->widget && !ctx->was_disowned && !replacement) {
973a3bd7f05Smrg                oldctx = ctx;
974a3bd7f05Smrg                oldctx->free_when_done = TRUE;
975a3bd7f05Smrg                ctx = NewContext(XtDisplay(widget), selection);
976a3bd7f05Smrg            }
977a3bd7f05Smrg            XtAddEventHandler(widget, (EventMask) 0, TRUE,
978a3bd7f05Smrg                              HandleSelectionEvents, (XtPointer) ctx);
979a3bd7f05Smrg            XtAddCallback(widget, XtNdestroyCallback,
980a3bd7f05Smrg                          WidgetDestroyed, (XtPointer) ctx);
981a3bd7f05Smrg        }
982a3bd7f05Smrg        ctx->widget = widget;   /* Selection offically changes hands. */
983a3bd7f05Smrg        ctx->time = time;
984a3bd7f05Smrg        ctx->serial = serial;
985444c061aSmrg    }
986444c061aSmrg    ctx->convert = convert;
987444c061aSmrg    ctx->loses = lose;
988444c061aSmrg    ctx->notify = notify;
989444c061aSmrg    ctx->owner_cancel = cancel;
9900568f49bSmrg    XtSetBit(ctx->incremental, incremental);
991444c061aSmrg    ctx->owner_closure = closure;
992444c061aSmrg    ctx->was_disowned = FALSE;
993444c061aSmrg
994444c061aSmrg    /* Defer calling the previous selection owner's lose selection procedure
995444c061aSmrg     * until the new selection is established, to allow the previous
996444c061aSmrg     * selection owner to ask for the new selection to be converted in
997444c061aSmrg     * the lose selection procedure.  The context pointer is the closure
998444c061aSmrg     * of the event handler and the destroy callback, so the old context
999444c061aSmrg     * pointer and the record contents must be preserved for LoseSelection.
1000444c061aSmrg     */
1001444c061aSmrg    if (oldctx) {
1002a3bd7f05Smrg        (void) LoseSelection(oldctx, oldctx->widget, selection, oldctx->time);
1003a3bd7f05Smrg        if (!oldctx->ref_count && oldctx->free_when_done)
1004a3bd7f05Smrg            XtFree((char *) oldctx);
1005444c061aSmrg    }
1006444c061aSmrg    return TRUE;
1007444c061aSmrg}
1008444c061aSmrg
1009a3bd7f05SmrgBoolean
1010a3bd7f05SmrgXtOwnSelection(Widget widget,
1011a3bd7f05Smrg               Atom selection,
1012a3bd7f05Smrg               Time time,
1013a3bd7f05Smrg               XtConvertSelectionProc convert,
1014a3bd7f05Smrg               XtLoseSelectionProc lose,
1015a3bd7f05Smrg               XtSelectionDoneProc notify)
1016444c061aSmrg{
1017444c061aSmrg    Boolean retval;
1018a3bd7f05Smrg
1019444c061aSmrg    WIDGET_TO_APPCON(widget);
1020444c061aSmrg
1021444c061aSmrg    LOCK_APP(app);
1022444c061aSmrg    retval = OwnSelection(widget, selection, time, convert, lose, notify,
1023a3bd7f05Smrg                          (XtCancelConvertSelectionProc) NULL,
1024a3bd7f05Smrg                          (XtPointer) NULL, FALSE);
1025444c061aSmrg    UNLOCK_APP(app);
1026444c061aSmrg    return retval;
1027444c061aSmrg}
1028444c061aSmrg
1029a3bd7f05SmrgBoolean
1030a3bd7f05SmrgXtOwnSelectionIncremental(Widget widget,
1031a3bd7f05Smrg                          Atom selection,
1032a3bd7f05Smrg                          Time time,
1033a3bd7f05Smrg                          XtConvertSelectionIncrProc convert,
1034a3bd7f05Smrg                          XtLoseSelectionIncrProc lose,
1035a3bd7f05Smrg                          XtSelectionDoneIncrProc notify,
1036a3bd7f05Smrg                          XtCancelConvertSelectionProc cancel,
1037a3bd7f05Smrg                          XtPointer closure)
1038444c061aSmrg{
1039444c061aSmrg    Boolean retval;
1040a3bd7f05Smrg
1041444c061aSmrg    WIDGET_TO_APPCON(widget);
1042444c061aSmrg
1043444c061aSmrg    LOCK_APP(app);
1044444c061aSmrg    retval = OwnSelection(widget, selection, time,
1045a3bd7f05Smrg                          (XtConvertSelectionProc) convert,
1046a3bd7f05Smrg                          (XtLoseSelectionProc) lose,
1047a3bd7f05Smrg                          (XtSelectionDoneProc) notify, cancel, closure, TRUE);
1048444c061aSmrg    UNLOCK_APP(app);
1049444c061aSmrg    return retval;
1050444c061aSmrg}
1051444c061aSmrg
1052a3bd7f05Smrgvoid
1053a3bd7f05SmrgXtDisownSelection(Widget widget, Atom selection, Time time)
1054444c061aSmrg{
1055444c061aSmrg    Select ctx;
1056a3bd7f05Smrg
1057444c061aSmrg    WIDGET_TO_APPCON(widget);
1058444c061aSmrg
1059444c061aSmrg    LOCK_APP(app);
1060444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1061444c061aSmrg    if (LoseSelection(ctx, widget, selection, time))
1062a3bd7f05Smrg        XSetSelectionOwner(XtDisplay(widget), selection, None, time);
1063444c061aSmrg    UNLOCK_APP(app);
1064444c061aSmrg}
1065444c061aSmrg
1066444c061aSmrg/* Selection Requestor code */
1067444c061aSmrg
1068a3bd7f05Smrgstatic Boolean
1069a3bd7f05SmrgIsINCRtype(CallBackInfo info, Window window, Atom prop)
1070444c061aSmrg{
1071444c061aSmrg    unsigned long bytesafter;
1072444c061aSmrg    unsigned long length;
1073444c061aSmrg    int format;
1074444c061aSmrg    Atom type;
1075444c061aSmrg    unsigned char *value;
1076444c061aSmrg
1077a3bd7f05Smrg    if (prop == None)
1078a3bd7f05Smrg        return False;
1079444c061aSmrg
10809e7bcd65Smrg    if (XGetWindowProperty(XtDisplay(info->widget), window, prop, 0L, 0L,
1081a3bd7f05Smrg                           False, info->ctx->prop_list->incr_atom, &type,
1082a3bd7f05Smrg                           &format, &length, &bytesafter, &value) != Success)
1083a3bd7f05Smrg        return False;
1084444c061aSmrg
1085444c061aSmrg    return (type == info->ctx->prop_list->incr_atom);
1086444c061aSmrg}
1087444c061aSmrg
1088a3bd7f05Smrgstatic void
1089a3bd7f05SmrgReqCleanup(Widget widget,
1090a3bd7f05Smrg           XtPointer closure,
1091a3bd7f05Smrg           XEvent *ev,
1092a3bd7f05Smrg           Boolean *cont _X_UNUSED)
1093444c061aSmrg{
1094a3bd7f05Smrg    CallBackInfo info = (CallBackInfo) closure;
1095444c061aSmrg    unsigned long bytesafter, length;
1096444c061aSmrg    int format;
1097444c061aSmrg    Atom target;
1098444c061aSmrg
1099444c061aSmrg    if (ev->type == SelectionNotify) {
1100a3bd7f05Smrg        XSelectionEvent *event = (XSelectionEvent *) ev;
1101a3bd7f05Smrg
1102a3bd7f05Smrg        if (!MATCH_SELECT(event, info))
1103a3bd7f05Smrg            return;             /* not really for us */
1104a3bd7f05Smrg        XtRemoveEventHandler(widget, (EventMask) 0, TRUE,
1105a3bd7f05Smrg                             ReqCleanup, (XtPointer) info);
1106a3bd7f05Smrg        if (IsINCRtype(info, XtWindow(widget), event->property)) {
1107a3bd7f05Smrg            info->proc = HandleGetIncrement;
1108a3bd7f05Smrg            XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
1109a3bd7f05Smrg                              FALSE, ReqCleanup, (XtPointer) info);
1110a3bd7f05Smrg        }
1111a3bd7f05Smrg        else {
1112a3bd7f05Smrg            if (event->property != None)
1113a3bd7f05Smrg                XDeleteProperty(event->display, XtWindow(widget),
1114a3bd7f05Smrg                                event->property);
1115a3bd7f05Smrg            FreeSelectionProperty(XtDisplay(widget), info->property);
1116a3bd7f05Smrg            FreeInfo(info);
1117a3bd7f05Smrg        }
1118a3bd7f05Smrg    }
1119a3bd7f05Smrg    else if ((ev->type == PropertyNotify) &&
1120a3bd7f05Smrg             (ev->xproperty.state == PropertyNewValue) &&
1121a3bd7f05Smrg             (ev->xproperty.atom == info->property)) {
1122a3bd7f05Smrg        XPropertyEvent *event = (XPropertyEvent *) ev;
1123a3bd7f05Smrg        char *value = NULL;
1124a3bd7f05Smrg
1125a3bd7f05Smrg        if (XGetWindowProperty(event->display, XtWindow(widget),
1126a3bd7f05Smrg                               event->atom, 0L, 1000000, True, AnyPropertyType,
1127a3bd7f05Smrg                               &target, &format, &length, &bytesafter,
1128a3bd7f05Smrg                               (unsigned char **) &value) == Success) {
1129a3bd7f05Smrg            XFree(value);
1130a3bd7f05Smrg            if (length == 0) {
1131a3bd7f05Smrg                XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask,
1132a3bd7f05Smrg                                     FALSE, ReqCleanup, (XtPointer) info);
1133a3bd7f05Smrg                FreeSelectionProperty(XtDisplay(widget), info->property);
1134a3bd7f05Smrg                XtFree(info->value);    /* requestor never got this, so free now */
1135a3bd7f05Smrg                FreeInfo(info);
1136a3bd7f05Smrg            }
1137a3bd7f05Smrg        }
1138444c061aSmrg    }
1139444c061aSmrg}
1140444c061aSmrg
1141a3bd7f05Smrgstatic void
1142a3bd7f05SmrgReqTimedOut(XtPointer closure, XtIntervalId *id _X_UNUSED)
1143444c061aSmrg{
1144444c061aSmrg    XtPointer value = NULL;
1145444c061aSmrg    unsigned long length = 0;
1146444c061aSmrg    int format = 8;
1147444c061aSmrg    Atom resulttype = XT_CONVERT_FAIL;
1148a3bd7f05Smrg    CallBackInfo info = (CallBackInfo) closure;
1149444c061aSmrg    unsigned long bytesafter;
1150444c061aSmrg    unsigned long proplength;
1151444c061aSmrg    Atom type;
1152444c061aSmrg
1153444c061aSmrg    if (*info->target == info->ctx->prop_list->indirect_atom) {
1154a3bd7f05Smrg        IndirectPair *pairs = NULL;
1155a3bd7f05Smrg
1156a3bd7f05Smrg        if (XGetWindowProperty(XtDisplay(info->widget), XtWindow(info->widget),
1157a3bd7f05Smrg                               info->property, 0L, 10000000, True,
1158a3bd7f05Smrg                               AnyPropertyType, &type, &format, &proplength,
1159a3bd7f05Smrg                               &bytesafter, (unsigned char **) &pairs)
1160a3bd7f05Smrg            == Success) {
1161a3bd7f05Smrg            XtPointer *c;
1162a3bd7f05Smrg            int i;
1163a3bd7f05Smrg
1164a3bd7f05Smrg            XFree(pairs);
1165a3bd7f05Smrg            for (proplength = proplength / IndirectPairWordSize, i = 0,
1166a3bd7f05Smrg                 c = info->req_closure; proplength; proplength--, c++, i++)
1167a3bd7f05Smrg                (*info->callbacks[i]) (info->widget, *c, &info->ctx->selection,
1168a3bd7f05Smrg                                       &resulttype, value, &length, &format);
1169a3bd7f05Smrg        }
1170a3bd7f05Smrg    }
1171a3bd7f05Smrg    else {
1172a3bd7f05Smrg        (*info->callbacks[0]) (info->widget, *info->req_closure,
1173a3bd7f05Smrg                               &info->ctx->selection, &resulttype, value,
1174a3bd7f05Smrg                               &length, &format);
1175444c061aSmrg    }
1176444c061aSmrg
1177444c061aSmrg    /* change event handlers for straggler events */
1178a3bd7f05Smrg    if (info->proc == (XtEventHandler) HandleSelectionReplies) {
1179a3bd7f05Smrg        XtRemoveEventHandler(info->widget, (EventMask) 0,
1180a3bd7f05Smrg                             TRUE, info->proc, (XtPointer) info);
1181a3bd7f05Smrg        XtAddEventHandler(info->widget, (EventMask) 0, TRUE,
1182a3bd7f05Smrg                          ReqCleanup, (XtPointer) info);
1183a3bd7f05Smrg    }
1184a3bd7f05Smrg    else {
1185a3bd7f05Smrg        XtRemoveEventHandler(info->widget, (EventMask) PropertyChangeMask,
1186a3bd7f05Smrg                             FALSE, info->proc, (XtPointer) info);
1187a3bd7f05Smrg        XtAddEventHandler(info->widget, (EventMask) PropertyChangeMask,
1188a3bd7f05Smrg                          FALSE, ReqCleanup, (XtPointer) info);
1189444c061aSmrg    }
1190444c061aSmrg
1191444c061aSmrg}
1192444c061aSmrg
1193a3bd7f05Smrgstatic void
1194a3bd7f05SmrgHandleGetIncrement(Widget widget,
1195a3bd7f05Smrg                   XtPointer closure,
1196a3bd7f05Smrg                   XEvent *ev,
1197a3bd7f05Smrg                   Boolean *cont _X_UNUSED)
1198444c061aSmrg{
1199444c061aSmrg    XPropertyEvent *event = (XPropertyEvent *) ev;
1200444c061aSmrg    CallBackInfo info = (CallBackInfo) closure;
1201444c061aSmrg    Select ctx = info->ctx;
1202444c061aSmrg    char *value;
1203444c061aSmrg    unsigned long bytesafter;
1204444c061aSmrg    unsigned long length;
1205444c061aSmrg    int bad;
1206444c061aSmrg    int n = info->current;
1207444c061aSmrg
1208444c061aSmrg    if ((event->state != PropertyNewValue) || (event->atom != info->property))
1209a3bd7f05Smrg        return;
1210444c061aSmrg
1211444c061aSmrg    bad = XGetWindowProperty(event->display, XtWindow(widget),
1212a3bd7f05Smrg                             event->atom, 0L,
1213a3bd7f05Smrg                             10000000, True, AnyPropertyType, &info->type,
1214a3bd7f05Smrg                             &info->format, &length, &bytesafter,
1215a3bd7f05Smrg                             (unsigned char **)&value);
1216444c061aSmrg    if (bad)
1217a3bd7f05Smrg        return;
1218444c061aSmrg#ifndef DEBUG_WO_TIMERS
1219444c061aSmrg    XtRemoveTimeOut(info->timeout);
1220444c061aSmrg#endif
1221444c061aSmrg    if (length == 0) {
1222a3bd7f05Smrg        unsigned long u_offset = NUMELEM2(info->offset, info->format);
1223a3bd7f05Smrg
1224a3bd7f05Smrg        (*info->callbacks[n]) (widget, *info->req_closure, &ctx->selection,
1225a3bd7f05Smrg                               &info->type,
1226a3bd7f05Smrg                               (info->offset == 0 ? value : info->value),
1227a3bd7f05Smrg                               &u_offset, &info->format);
1228a3bd7f05Smrg        /* assert ((info->offset != 0) == (info->incremental[n]) */
1229a3bd7f05Smrg        if (info->offset != 0)
1230a3bd7f05Smrg            XFree(value);
1231a3bd7f05Smrg        XtRemoveEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
1232a3bd7f05Smrg                             HandleGetIncrement, (XtPointer) info);
1233a3bd7f05Smrg        FreeSelectionProperty(event->display, info->property);
1234a3bd7f05Smrg
1235a3bd7f05Smrg        FreeInfo(info);
1236a3bd7f05Smrg    }
1237a3bd7f05Smrg    else {                      /* add increment to collection */
1238a3bd7f05Smrg        if (info->incremental[n]) {
1239444c061aSmrg#ifdef XT_COPY_SELECTION
1240a3bd7f05Smrg            int size = (int) BYTELENGTH(length, info->format) + 1;
1241a3bd7f05Smrg            char *tmp = __XtMalloc((Cardinal) size);
1242a3bd7f05Smrg
1243a3bd7f05Smrg            (void) memmove(tmp, value, (size_t) size);
1244a3bd7f05Smrg            XFree(value);
1245a3bd7f05Smrg            value = tmp;
1246444c061aSmrg#endif
1247a3bd7f05Smrg            (*info->callbacks[n]) (widget, *info->req_closure, &ctx->selection,
1248a3bd7f05Smrg                                   &info->type, value, &length, &info->format);
1249a3bd7f05Smrg        }
1250a3bd7f05Smrg        else {
1251a3bd7f05Smrg            int size = (int) BYTELENGTH(length, info->format);
1252a3bd7f05Smrg
1253a3bd7f05Smrg            if (info->offset + size > info->bytelength) {
1254a3bd7f05Smrg                /* allocate enough for this and the next increment */
1255a3bd7f05Smrg                info->bytelength = info->offset + size * 2;
1256a3bd7f05Smrg                info->value = XtRealloc(info->value,
1257a3bd7f05Smrg                                        (Cardinal) info->bytelength);
1258a3bd7f05Smrg            }
1259a3bd7f05Smrg            (void) memmove(&info->value[info->offset], value, (size_t) size);
1260a3bd7f05Smrg            info->offset += size;
1261a3bd7f05Smrg            XFree(value);
1262a3bd7f05Smrg        }
1263a3bd7f05Smrg        /* reset timer */
1264444c061aSmrg#ifndef DEBUG_WO_TIMERS
1265a3bd7f05Smrg        {
1266a3bd7f05Smrg            XtAppContext app = XtWidgetToApplicationContext(info->widget);
1267a3bd7f05Smrg
1268a3bd7f05Smrg            info->timeout = XtAppAddTimeOut(app,
1269a3bd7f05Smrg                                            app->selectionTimeout, ReqTimedOut,
1270a3bd7f05Smrg                                            (XtPointer) info);
1271a3bd7f05Smrg        }
1272444c061aSmrg#endif
1273a3bd7f05Smrg    }
1274444c061aSmrg}
1275444c061aSmrg
1276a3bd7f05Smrgstatic void
1277a3bd7f05SmrgHandleNone(Widget widget,
1278a3bd7f05Smrg           XtSelectionCallbackProc callback,
1279a3bd7f05Smrg           XtPointer closure,
1280a3bd7f05Smrg           Atom selection)
1281444c061aSmrg{
1282444c061aSmrg    unsigned long length = 0;
1283444c061aSmrg    int format = 8;
1284444c061aSmrg    Atom type = None;
1285444c061aSmrg
1286a3bd7f05Smrg    (*callback) (widget, closure, &selection, &type, NULL, &length, &format);
1287444c061aSmrg}
1288444c061aSmrg
1289a3bd7f05Smrgstatic unsigned long
1290a3bd7f05SmrgIncrPropSize(Widget widget,
1291a3bd7f05Smrg             unsigned char *value,
1292a3bd7f05Smrg             int format,
1293a3bd7f05Smrg             unsigned long length)
1294444c061aSmrg{
1295444c061aSmrg    if (format == 32) {
1296a3bd7f05Smrg        unsigned long size;
1297a3bd7f05Smrg
1298a3bd7f05Smrg        size = ((unsigned long *) value)[length - 1];   /* %%% what order for longs? */
1299a3bd7f05Smrg        return size;
1300444c061aSmrg    }
1301444c061aSmrg    else {
1302a3bd7f05Smrg        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
1303a3bd7f05Smrg                        "badFormat", "xtGetSelectionValue", XtCXtToolkitError,
1304a3bd7f05Smrg                        "Selection owner returned type INCR property with format != 32",
1305a3bd7f05Smrg                        NULL, NULL);
1306a3bd7f05Smrg        return 0;
1307444c061aSmrg    }
1308444c061aSmrg}
1309444c061aSmrg
1310444c061aSmrgstatic
1311a3bd7f05Smrg    Boolean
1312a3bd7f05SmrgHandleNormal(Display *dpy,
1313a3bd7f05Smrg             Widget widget,
1314a3bd7f05Smrg             Atom property,
1315a3bd7f05Smrg             CallBackInfo info,
1316a3bd7f05Smrg             XtPointer closure,
1317a3bd7f05Smrg             Atom selection)
1318444c061aSmrg{
1319444c061aSmrg    unsigned long bytesafter;
1320444c061aSmrg    unsigned long length;
1321444c061aSmrg    int format;
1322444c061aSmrg    Atom type;
13239e7bcd65Smrg    unsigned char *value = NULL;
1324444c061aSmrg    int number = info->current;
1325444c061aSmrg
13269e7bcd65Smrg    if (XGetWindowProperty(dpy, XtWindow(widget), property, 0L, 10000000,
1327a3bd7f05Smrg                           False, AnyPropertyType, &type, &format, &length,
1328a3bd7f05Smrg                           &bytesafter, &value) != Success)
1329a3bd7f05Smrg        return FALSE;
1330444c061aSmrg
1331444c061aSmrg    if (type == info->ctx->prop_list->incr_atom) {
1332a3bd7f05Smrg        unsigned long size = IncrPropSize(widget, value, format, length);
1333a3bd7f05Smrg
1334a3bd7f05Smrg        XFree((char *) value);
1335a3bd7f05Smrg        if (info->property != property) {
1336a3bd7f05Smrg            /* within MULTIPLE */
1337a3bd7f05Smrg            CallBackInfo ninfo;
1338a3bd7f05Smrg
1339a3bd7f05Smrg            ninfo = MakeInfo(info->ctx, &info->callbacks[number],
1340a3bd7f05Smrg                             &info->req_closure[number], 1, widget,
1341a3bd7f05Smrg                             info->time, &info->incremental[number], &property);
1342a3bd7f05Smrg            ninfo->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom));
1343a3bd7f05Smrg            *ninfo->target = info->target[number + 1];
1344a3bd7f05Smrg            info = ninfo;
1345a3bd7f05Smrg        }
1346a3bd7f05Smrg        HandleIncremental(dpy, widget, property, info, size);
1347a3bd7f05Smrg        return FALSE;
1348444c061aSmrg    }
1349444c061aSmrg
1350444c061aSmrg    XDeleteProperty(dpy, XtWindow(widget), property);
1351444c061aSmrg#ifdef XT_COPY_SELECTION
1352a3bd7f05Smrg    if (value) {                /* it could have been deleted after the SelectionNotify */
1353a3bd7f05Smrg        int size = (int) BYTELENGTH(length, info->format) + 1;
1354a3bd7f05Smrg        char *tmp = __XtMalloc((Cardinal) size);
1355a3bd7f05Smrg
1356a3bd7f05Smrg        (void) memmove(tmp, value, (size_t) size);
1357a3bd7f05Smrg        XFree(value);
1358a3bd7f05Smrg        value = (unsigned char *) tmp;
1359444c061aSmrg    }
1360444c061aSmrg#endif
1361a3bd7f05Smrg    (*info->callbacks[number]) (widget, closure, &selection,
1362a3bd7f05Smrg                                &type, (XtPointer) value, &length, &format);
1363444c061aSmrg
1364444c061aSmrg    if (info->incremental[number]) {
1365a3bd7f05Smrg        /* let requestor know the whole thing has been received */
1366a3bd7f05Smrg        value = (unsigned char *) __XtMalloc((unsigned) 1);
1367a3bd7f05Smrg        length = 0;
1368a3bd7f05Smrg        (*info->callbacks[number]) (widget, closure, &selection,
1369a3bd7f05Smrg                                    &type, (XtPointer) value, &length, &format);
1370444c061aSmrg    }
1371444c061aSmrg    return TRUE;
1372444c061aSmrg}
1373444c061aSmrg
1374a3bd7f05Smrgstatic void
1375a3bd7f05SmrgHandleIncremental(Display *dpy,
1376a3bd7f05Smrg                  Widget widget,
1377a3bd7f05Smrg                  Atom property,
1378a3bd7f05Smrg                  CallBackInfo info,
1379a3bd7f05Smrg                  unsigned long size)
1380444c061aSmrg{
1381444c061aSmrg    XtAddEventHandler(widget, (EventMask) PropertyChangeMask, FALSE,
1382a3bd7f05Smrg                      HandleGetIncrement, (XtPointer) info);
1383444c061aSmrg
1384444c061aSmrg    /* now start the transfer */
1385444c061aSmrg    XDeleteProperty(dpy, XtWindow(widget), property);
1386444c061aSmrg    XFlush(dpy);
1387444c061aSmrg
13880568f49bSmrg    info->bytelength = (int) size;
1389a3bd7f05Smrg    if (info->incremental[info->current])       /* requestor wants incremental too */
1390a3bd7f05Smrg        info->value = NULL;     /* so no need for buffer to assemble value */
1391444c061aSmrg    else
1392a3bd7f05Smrg        info->value = (char *) __XtMalloc((unsigned) info->bytelength);
1393444c061aSmrg    info->offset = 0;
1394444c061aSmrg
1395444c061aSmrg    /* reset the timer */
1396444c061aSmrg    info->proc = HandleGetIncrement;
1397444c061aSmrg#ifndef DEBUG_WO_TIMERS
1398444c061aSmrg    {
1399a3bd7f05Smrg        XtAppContext app = XtWidgetToApplicationContext(info->widget);
1400a3bd7f05Smrg
1401a3bd7f05Smrg        info->timeout = XtAppAddTimeOut(app,
1402a3bd7f05Smrg                                        app->selectionTimeout, ReqTimedOut,
1403a3bd7f05Smrg                                        (XtPointer) info);
1404444c061aSmrg    }
1405444c061aSmrg#endif
1406444c061aSmrg}
1407444c061aSmrg
1408a3bd7f05Smrgstatic void
1409a3bd7f05SmrgHandleSelectionReplies(Widget widget,
1410a3bd7f05Smrg                       XtPointer closure,
1411a3bd7f05Smrg                       XEvent *ev,
1412a3bd7f05Smrg                       Boolean *cont _X_UNUSED)
1413444c061aSmrg{
1414444c061aSmrg    XSelectionEvent *event = (XSelectionEvent *) ev;
1415444c061aSmrg    Display *dpy = event->display;
1416444c061aSmrg    CallBackInfo info = (CallBackInfo) closure;
1417444c061aSmrg    Select ctx = info->ctx;
1418444c061aSmrg    unsigned long bytesafter;
1419444c061aSmrg    unsigned long length;
1420444c061aSmrg    int format;
1421444c061aSmrg    Atom type;
1422444c061aSmrg
1423a3bd7f05Smrg    if (event->type != SelectionNotify)
1424a3bd7f05Smrg        return;
1425a3bd7f05Smrg    if (!MATCH_SELECT(event, info))
1426a3bd7f05Smrg        return;                 /* not really for us */
1427444c061aSmrg#ifndef DEBUG_WO_TIMERS
1428444c061aSmrg    XtRemoveTimeOut(info->timeout);
1429444c061aSmrg#endif
1430a3bd7f05Smrg    XtRemoveEventHandler(widget, (EventMask) 0, TRUE,
1431a3bd7f05Smrg                         HandleSelectionReplies, (XtPointer) info);
1432444c061aSmrg    if (event->target == ctx->prop_list->indirect_atom) {
1433a3bd7f05Smrg        IndirectPair *pairs = NULL, *p;
1434a3bd7f05Smrg        XtPointer *c;
1435a3bd7f05Smrg
1436a3bd7f05Smrg        if (XGetWindowProperty(dpy, XtWindow(widget), info->property, 0L,
1437a3bd7f05Smrg                               10000000, True, AnyPropertyType, &type, &format,
1438a3bd7f05Smrg                               &length, &bytesafter, (unsigned char **) &pairs)
1439a3bd7f05Smrg            != Success)
1440a3bd7f05Smrg            length = 0;
1441a3bd7f05Smrg        for (length = length / IndirectPairWordSize, p = pairs,
1442a3bd7f05Smrg             c = info->req_closure;
1443a3bd7f05Smrg             length; length--, p++, c++, info->current++) {
1444a3bd7f05Smrg            if (event->property == None || format != 32 || p->target == None
1445a3bd7f05Smrg                || /* bug compatibility */ p->property == None) {
1446a3bd7f05Smrg                HandleNone(widget, info->callbacks[info->current],
1447a3bd7f05Smrg                           *c, event->selection);
1448a3bd7f05Smrg                if (p->property != None)
1449a3bd7f05Smrg                    FreeSelectionProperty(XtDisplay(widget), p->property);
1450a3bd7f05Smrg            }
1451a3bd7f05Smrg            else {
1452a3bd7f05Smrg                if (HandleNormal(dpy, widget, p->property, info, *c,
1453a3bd7f05Smrg                                 event->selection)) {
1454444c061aSmrg                    FreeSelectionProperty(XtDisplay(widget), p->property);
1455a3bd7f05Smrg                }
1456a3bd7f05Smrg            }
1457a3bd7f05Smrg        }
1458a3bd7f05Smrg        XFree((char *) pairs);
1459a3bd7f05Smrg        FreeSelectionProperty(dpy, info->property);
1460a3bd7f05Smrg        FreeInfo(info);
1461a3bd7f05Smrg    }
1462a3bd7f05Smrg    else if (event->property == None) {
1463a3bd7f05Smrg        HandleNone(widget, info->callbacks[0], *info->req_closure,
1464a3bd7f05Smrg                   event->selection);
1465444c061aSmrg        FreeSelectionProperty(XtDisplay(widget), info->property);
1466a3bd7f05Smrg        FreeInfo(info);
1467a3bd7f05Smrg    }
1468a3bd7f05Smrg    else {
1469a3bd7f05Smrg        if (HandleNormal(dpy, widget, event->property, info,
1470a3bd7f05Smrg                         *info->req_closure, event->selection)) {
1471a3bd7f05Smrg            FreeSelectionProperty(XtDisplay(widget), info->property);
1472a3bd7f05Smrg            FreeInfo(info);
1473a3bd7f05Smrg        }
1474444c061aSmrg    }
1475444c061aSmrg}
1476444c061aSmrg
1477a3bd7f05Smrgstatic void
1478a3bd7f05SmrgDoLocalTransfer(Request req,
1479a3bd7f05Smrg                Atom selection,
1480a3bd7f05Smrg                Atom target,
1481a3bd7f05Smrg                Widget widget, /* The widget requesting the value. */
1482a3bd7f05Smrg                XtSelectionCallbackProc callback,
1483a3bd7f05Smrg                XtPointer closure,    /* the closure for the callback, not the conversion */
1484a3bd7f05Smrg                Boolean incremental, Atom property)
1485444c061aSmrg{
1486444c061aSmrg    Select ctx = req->ctx;
1487444c061aSmrg    XtPointer value = NULL, temp, total = NULL;
1488444c061aSmrg    unsigned long length;
1489444c061aSmrg    int format;
1490444c061aSmrg    Atom resulttype;
1491444c061aSmrg    unsigned long totallength = 0;
1492444c061aSmrg
1493a3bd7f05Smrg    req->event.type = 0;
1494a3bd7f05Smrg    req->event.target = target;
1495a3bd7f05Smrg    req->event.property = req->property = property;
1496a3bd7f05Smrg    req->event.requestor = req->requestor = XtWindow(widget);
1497a3bd7f05Smrg
1498a3bd7f05Smrg    if (ctx->incremental) {
1499a3bd7f05Smrg        unsigned long size = (unsigned long) MAX_SELECTION_INCR(ctx->dpy);
1500a3bd7f05Smrg
1501a3bd7f05Smrg        if (!(*(XtConvertSelectionIncrProc) ctx->convert)
1502a3bd7f05Smrg            (ctx->widget, &selection, &target,
1503a3bd7f05Smrg             &resulttype, &value, &length, &format,
1504a3bd7f05Smrg             &size, ctx->owner_closure, (XtRequestId *) &req)) {
1505a3bd7f05Smrg            HandleNone(widget, callback, closure, selection);
1506a3bd7f05Smrg        }
1507a3bd7f05Smrg        else {
1508a3bd7f05Smrg            if (incremental) {
1509a3bd7f05Smrg                Boolean allSent = FALSE;
1510a3bd7f05Smrg
1511a3bd7f05Smrg                while (!allSent) {
1512a3bd7f05Smrg                    if (ctx->notify && (value != NULL)) {
1513a3bd7f05Smrg                        int bytelength = (int) BYTELENGTH(length, format);
1514a3bd7f05Smrg
1515a3bd7f05Smrg                        /* both sides think they own this storage */
1516a3bd7f05Smrg                        temp = __XtMalloc((unsigned) bytelength);
1517a3bd7f05Smrg                        (void) memmove(temp, value, (size_t) bytelength);
1518a3bd7f05Smrg                        value = temp;
1519a3bd7f05Smrg                    }
1520a3bd7f05Smrg                    /* use care; older clients were never warned that
1521a3bd7f05Smrg                     * they must return a value even if length==0
1522a3bd7f05Smrg                     */
1523a3bd7f05Smrg                    if (value == NULL)
1524a3bd7f05Smrg                        value = __XtMalloc((unsigned) 1);
1525a3bd7f05Smrg                    (*callback) (widget, closure, &selection,
1526a3bd7f05Smrg                                 &resulttype, value, &length, &format);
1527a3bd7f05Smrg                    if (length) {
1528a3bd7f05Smrg                        /* should owner be notified on end-of-piece?
1529a3bd7f05Smrg                         * Spec is unclear, but non-local transfers don't.
1530a3bd7f05Smrg                         */
1531a3bd7f05Smrg                        (*(XtConvertSelectionIncrProc) ctx->convert)
1532a3bd7f05Smrg                            (ctx->widget, &selection, &target,
1533a3bd7f05Smrg                             &resulttype, &value, &length, &format,
1534a3bd7f05Smrg                             &size, ctx->owner_closure, (XtRequestId *) &req);
1535a3bd7f05Smrg                    }
1536a3bd7f05Smrg                    else
1537a3bd7f05Smrg                        allSent = TRUE;
1538a3bd7f05Smrg                }
1539a3bd7f05Smrg            }
1540a3bd7f05Smrg            else {
1541a3bd7f05Smrg                while (length) {
1542a3bd7f05Smrg                    int bytelength = (int) BYTELENGTH(length, format);
1543a3bd7f05Smrg
1544a3bd7f05Smrg                    total = XtRealloc(total,
1545a3bd7f05Smrg                                      (Cardinal) (totallength =
1546a3bd7f05Smrg                                                  totallength +
1547a3bd7f05Smrg                                                  (unsigned long) bytelength));
1548a3bd7f05Smrg                    (void) memmove((char *) total + totallength - bytelength,
1549a3bd7f05Smrg                                   value, (size_t) bytelength);
1550a3bd7f05Smrg                    (*(XtConvertSelectionIncrProc) ctx->convert)
1551a3bd7f05Smrg                        (ctx->widget, &selection, &target,
1552a3bd7f05Smrg                         &resulttype, &value, &length, &format,
1553a3bd7f05Smrg                         &size, ctx->owner_closure, (XtRequestId *) &req);
1554a3bd7f05Smrg                }
1555a3bd7f05Smrg                if (total == NULL)
1556a3bd7f05Smrg                    total = __XtMalloc(1);
1557a3bd7f05Smrg                totallength = NUMELEM2(totallength, format);
1558a3bd7f05Smrg                (*callback) (widget, closure, &selection, &resulttype,
1559a3bd7f05Smrg                             total, &totallength, &format);
1560a3bd7f05Smrg            }
1561a3bd7f05Smrg            if (ctx->notify)
1562a3bd7f05Smrg                (*(XtSelectionDoneIncrProc) ctx->notify)
1563a3bd7f05Smrg                    (ctx->widget, &selection, &target,
1564a3bd7f05Smrg                     (XtRequestId *) &req, ctx->owner_closure);
1565a3bd7f05Smrg            else
1566a3bd7f05Smrg                XtFree((char *) value);
1567a3bd7f05Smrg        }
1568a3bd7f05Smrg    }
1569a3bd7f05Smrg    else {                      /* not incremental owner */
1570a3bd7f05Smrg        if (!(*ctx->convert) (ctx->widget, &selection, &target,
1571a3bd7f05Smrg                              &resulttype, &value, &length, &format)) {
1572a3bd7f05Smrg            HandleNone(widget, callback, closure, selection);
1573a3bd7f05Smrg        }
1574a3bd7f05Smrg        else {
1575a3bd7f05Smrg            if (ctx->notify && (value != NULL)) {
1576a3bd7f05Smrg                int bytelength = (int) BYTELENGTH(length, format);
1577a3bd7f05Smrg
1578a3bd7f05Smrg                /* both sides think they own this storage; better copy */
1579a3bd7f05Smrg                temp = __XtMalloc((unsigned) bytelength);
1580a3bd7f05Smrg                (void) memmove(temp, value, (size_t) bytelength);
1581a3bd7f05Smrg                value = temp;
1582a3bd7f05Smrg            }
1583a3bd7f05Smrg            if (value == NULL)
1584a3bd7f05Smrg                value = __XtMalloc((unsigned) 1);
1585a3bd7f05Smrg            (*callback) (widget, closure, &selection, &resulttype,
1586a3bd7f05Smrg                         value, &length, &format);
1587a3bd7f05Smrg            if (ctx->notify)
1588a3bd7f05Smrg                (*ctx->notify) (ctx->widget, &selection, &target);
1589a3bd7f05Smrg        }
1590a3bd7f05Smrg    }
1591444c061aSmrg}
1592444c061aSmrg
1593a3bd7f05Smrgstatic void
1594a3bd7f05SmrgGetSelectionValue(Widget widget,
1595a3bd7f05Smrg                  Atom selection,
1596a3bd7f05Smrg                  Atom target,
1597a3bd7f05Smrg                  XtSelectionCallbackProc callback,
1598a3bd7f05Smrg                  XtPointer closure,
1599a3bd7f05Smrg                  Time time,
1600a3bd7f05Smrg                  Boolean incremental,
1601a3bd7f05Smrg                  Atom property)
1602444c061aSmrg{
1603444c061aSmrg    Select ctx;
1604444c061aSmrg    Atom properties[1];
1605444c061aSmrg
1606444c061aSmrg    properties[0] = property;
1607444c061aSmrg
1608444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1609444c061aSmrg    if (ctx->widget && !ctx->was_disowned) {
1610a3bd7f05Smrg        RequestRec req;
1611a3bd7f05Smrg
1612a3bd7f05Smrg        ctx->req = &req;
1613a3bd7f05Smrg        req.ctx = ctx;
1614a3bd7f05Smrg        req.event.time = time;
1615a3bd7f05Smrg        ctx->ref_count++;
1616a3bd7f05Smrg        DoLocalTransfer(&req, selection, target, widget,
1617a3bd7f05Smrg                        callback, closure, incremental, property);
1618a3bd7f05Smrg        if (--ctx->ref_count == 0 && ctx->free_when_done)
1619a3bd7f05Smrg            XtFree((char *) ctx);
1620a3bd7f05Smrg        else
1621a3bd7f05Smrg            ctx->req = NULL;
1622444c061aSmrg    }
1623444c061aSmrg    else {
1624a3bd7f05Smrg        CallBackInfo info;
1625a3bd7f05Smrg
1626a3bd7f05Smrg        info = MakeInfo(ctx, &callback, &closure, 1, widget,
1627a3bd7f05Smrg                        time, &incremental, properties);
1628a3bd7f05Smrg        info->target = (Atom *) __XtMalloc((unsigned) sizeof(Atom));
1629a3bd7f05Smrg        *(info->target) = target;
1630a3bd7f05Smrg        RequestSelectionValue(info, selection, target);
1631444c061aSmrg    }
1632444c061aSmrg}
1633444c061aSmrg
1634a3bd7f05Smrgvoid
1635a3bd7f05SmrgXtGetSelectionValue(Widget widget,
1636a3bd7f05Smrg                    Atom selection,
1637a3bd7f05Smrg                    Atom target,
1638a3bd7f05Smrg                    XtSelectionCallbackProc callback,
1639a3bd7f05Smrg                    XtPointer closure,
1640a3bd7f05Smrg                    Time time)
1641444c061aSmrg{
1642444c061aSmrg    Atom property;
1643444c061aSmrg    Boolean incr = False;
1644a3bd7f05Smrg
1645444c061aSmrg    WIDGET_TO_APPCON(widget);
1646444c061aSmrg
1647444c061aSmrg    LOCK_APP(app);
1648444c061aSmrg    property = GetParamInfo(widget, selection);
1649444c061aSmrg    RemoveParamInfo(widget, selection);
1650444c061aSmrg
1651444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1652a3bd7f05Smrg        AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
1653a3bd7f05Smrg                             &closure, &incr, &property);
1654a3bd7f05Smrg    }
1655a3bd7f05Smrg    else {
1656a3bd7f05Smrg        GetSelectionValue(widget, selection, target, callback,
1657a3bd7f05Smrg                          closure, time, FALSE, property);
1658444c061aSmrg    }
1659444c061aSmrg    UNLOCK_APP(app);
1660444c061aSmrg}
1661444c061aSmrg
1662a3bd7f05Smrgvoid
1663a3bd7f05SmrgXtGetSelectionValueIncremental(Widget widget,
1664a3bd7f05Smrg                               Atom selection,
1665a3bd7f05Smrg                               Atom target,
1666a3bd7f05Smrg                               XtSelectionCallbackProc callback,
1667a3bd7f05Smrg                               XtPointer closure,
1668a3bd7f05Smrg                               Time time)
1669444c061aSmrg{
1670444c061aSmrg    Atom property;
1671444c061aSmrg    Boolean incr = TRUE;
1672a3bd7f05Smrg
1673444c061aSmrg    WIDGET_TO_APPCON(widget);
1674444c061aSmrg
1675444c061aSmrg    LOCK_APP(app);
1676444c061aSmrg    property = GetParamInfo(widget, selection);
1677444c061aSmrg    RemoveParamInfo(widget, selection);
1678444c061aSmrg
1679444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1680a3bd7f05Smrg        AddSelectionRequests(widget, selection, 1, &target, &callback, 1,
1681a3bd7f05Smrg                             &closure, &incr, &property);
1682a3bd7f05Smrg    }
1683a3bd7f05Smrg    else {
1684a3bd7f05Smrg        GetSelectionValue(widget, selection, target, callback,
1685a3bd7f05Smrg                          closure, time, TRUE, property);
1686444c061aSmrg    }
1687444c061aSmrg
1688444c061aSmrg    UNLOCK_APP(app);
1689444c061aSmrg}
1690444c061aSmrg
1691a3bd7f05Smrgstatic void
1692a3bd7f05SmrgGetSelectionValues(Widget widget,
1693a3bd7f05Smrg                   Atom selection,
1694a3bd7f05Smrg                   Atom *targets,
1695a3bd7f05Smrg                   int count,
1696a3bd7f05Smrg                   XtSelectionCallbackProc *callbacks,
1697a3bd7f05Smrg                   int num_callbacks,
1698a3bd7f05Smrg                   XtPointer *closures,
1699a3bd7f05Smrg                   Time time,
1700a3bd7f05Smrg                   Boolean *incremental,
1701a3bd7f05Smrg                   Atom *properties)
1702444c061aSmrg{
1703444c061aSmrg    Select ctx;
17040568f49bSmrg    IndirectPair *pairs;
1705444c061aSmrg
1706a3bd7f05Smrg    if (count == 0)
1707a3bd7f05Smrg        return;
1708444c061aSmrg    ctx = FindCtx(XtDisplay(widget), selection);
1709444c061aSmrg    if (ctx->widget && !ctx->was_disowned) {
1710444c061aSmrg        int j, i;
1711a3bd7f05Smrg        RequestRec req;
1712a3bd7f05Smrg
1713a3bd7f05Smrg        ctx->req = &req;
1714a3bd7f05Smrg        req.ctx = ctx;
1715a3bd7f05Smrg        req.event.time = time;
1716a3bd7f05Smrg        ctx->ref_count++;
1717a3bd7f05Smrg        for (i = 0, j = 0; count; count--, i++, j++) {
1718a3bd7f05Smrg            if (j >= num_callbacks)
1719a3bd7f05Smrg                j = 0;
1720a3bd7f05Smrg
1721a3bd7f05Smrg            DoLocalTransfer(&req, selection, targets[i], widget,
1722a3bd7f05Smrg                            callbacks[j], closures[i], incremental[i],
1723a3bd7f05Smrg                            properties ? properties[i] : None);
1724a3bd7f05Smrg
1725a3bd7f05Smrg        }
1726a3bd7f05Smrg        if (--ctx->ref_count == 0 && ctx->free_when_done)
1727a3bd7f05Smrg            XtFree((char *) ctx);
1728a3bd7f05Smrg        else
1729a3bd7f05Smrg            ctx->req = NULL;
1730a3bd7f05Smrg    }
1731a3bd7f05Smrg    else {
1732444c061aSmrg        XtSelectionCallbackProc *passed_callbacks;
1733a3bd7f05Smrg        XtSelectionCallbackProc stack_cbs[32];
1734a3bd7f05Smrg        CallBackInfo info;
1735a3bd7f05Smrg        IndirectPair *p;
1736a3bd7f05Smrg        Atom *t;
1737444c061aSmrg        int i = 0, j = 0;
1738444c061aSmrg
1739a3bd7f05Smrg        passed_callbacks = (XtSelectionCallbackProc *)
1740a3bd7f05Smrg            XtStackAlloc(sizeof(XtSelectionCallbackProc) * (size_t) count,
1741a3bd7f05Smrg                         stack_cbs);
1742a3bd7f05Smrg
1743a3bd7f05Smrg        /* To deal with the old calls from XtGetSelectionValues* we
1744a3bd7f05Smrg           will repeat however many callbacks have been passed into
1745a3bd7f05Smrg           the array */
1746a3bd7f05Smrg        for (i = 0; i < count; i++) {
1747a3bd7f05Smrg            if (j >= num_callbacks)
1748a3bd7f05Smrg                j = 0;
1749a3bd7f05Smrg            passed_callbacks[i] = callbacks[j];
1750a3bd7f05Smrg            j++;
1751a3bd7f05Smrg        }
1752a3bd7f05Smrg        info = MakeInfo(ctx, passed_callbacks, closures, count, widget,
1753a3bd7f05Smrg                        time, incremental, properties);
1754a3bd7f05Smrg        XtStackFree((XtPointer) passed_callbacks, stack_cbs);
1755a3bd7f05Smrg
1756a3bd7f05Smrg        info->target = (Atom *)
1757a3bd7f05Smrg            __XtMalloc((unsigned) ((size_t) (count + 1) * sizeof(Atom)));
1758444c061aSmrg        (*info->target) = ctx->prop_list->indirect_atom;
1759a3bd7f05Smrg        (void) memmove((char *) info->target + sizeof(Atom), (char *) targets,
1760a3bd7f05Smrg                       (size_t) count * sizeof(Atom));
1761a3bd7f05Smrg        pairs = (IndirectPair *)
1762a3bd7f05Smrg            __XtMalloc((unsigned) ((size_t) count * sizeof(IndirectPair)));
1763a3bd7f05Smrg        for (p = &pairs[count - 1], t = &targets[count - 1], i = count - 1;
1764a3bd7f05Smrg             p >= pairs; p--, t--, i--) {
1765a3bd7f05Smrg            p->target = *t;
1766a3bd7f05Smrg            if (properties == NULL || properties[i] == None) {
1767a3bd7f05Smrg                p->property = GetSelectionProperty(XtDisplay(widget));
1768a3bd7f05Smrg                XDeleteProperty(XtDisplay(widget), XtWindow(widget),
1769a3bd7f05Smrg                                p->property);
1770a3bd7f05Smrg            }
1771a3bd7f05Smrg            else {
1772a3bd7f05Smrg                p->property = properties[i];
1773a3bd7f05Smrg            }
1774a3bd7f05Smrg        }
1775a3bd7f05Smrg        XChangeProperty(XtDisplay(widget), XtWindow(widget),
1776a3bd7f05Smrg                        info->property, info->property,
1777a3bd7f05Smrg                        32, PropModeReplace, (unsigned char *) pairs,
1778a3bd7f05Smrg                        count * IndirectPairWordSize);
1779a3bd7f05Smrg        XtFree((char *) pairs);
1780a3bd7f05Smrg        RequestSelectionValue(info, selection, ctx->prop_list->indirect_atom);
1781444c061aSmrg    }
1782444c061aSmrg}
1783444c061aSmrg
1784a3bd7f05Smrgvoid
1785a3bd7f05SmrgXtGetSelectionValues(Widget widget,
1786a3bd7f05Smrg                     Atom selection,
1787a3bd7f05Smrg                     Atom *targets,
1788a3bd7f05Smrg                     int count,
1789a3bd7f05Smrg                     XtSelectionCallbackProc callback,
1790a3bd7f05Smrg                     XtPointer *closures,
1791a3bd7f05Smrg                     Time time)
1792444c061aSmrg{
1793444c061aSmrg    Boolean incremental_values[32];
1794444c061aSmrg    Boolean *incremental;
1795444c061aSmrg    int i;
1796a3bd7f05Smrg
1797444c061aSmrg    WIDGET_TO_APPCON(widget);
1798444c061aSmrg
1799444c061aSmrg    LOCK_APP(app);
1800a3bd7f05Smrg    incremental =
1801a3bd7f05Smrg        XtStackAlloc((size_t) count * sizeof(Boolean), incremental_values);
1802a3bd7f05Smrg    for (i = 0; i < count; i++)
1803a3bd7f05Smrg        incremental[i] = FALSE;
1804444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1805a3bd7f05Smrg        AddSelectionRequests(widget, selection, count, targets, &callback,
1806a3bd7f05Smrg                             1, closures, incremental, NULL);
1807a3bd7f05Smrg    }
1808a3bd7f05Smrg    else {
1809a3bd7f05Smrg        GetSelectionValues(widget, selection, targets, count, &callback, 1,
1810a3bd7f05Smrg                           closures, time, incremental, NULL);
1811444c061aSmrg    }
1812444c061aSmrg    XtStackFree((XtPointer) incremental, incremental_values);
1813444c061aSmrg    UNLOCK_APP(app);
1814444c061aSmrg}
1815444c061aSmrg
1816a3bd7f05Smrgvoid
1817a3bd7f05SmrgXtGetSelectionValuesIncremental(Widget widget,
1818a3bd7f05Smrg                                Atom selection,
1819a3bd7f05Smrg                                Atom *targets,
1820a3bd7f05Smrg                                int count,
1821a3bd7f05Smrg                                XtSelectionCallbackProc callback,
1822a3bd7f05Smrg                                XtPointer *closures,
1823a3bd7f05Smrg                                Time time)
1824444c061aSmrg{
1825444c061aSmrg    Boolean incremental_values[32];
1826444c061aSmrg    Boolean *incremental;
1827444c061aSmrg    int i;
1828a3bd7f05Smrg
1829444c061aSmrg    WIDGET_TO_APPCON(widget);
1830444c061aSmrg
1831444c061aSmrg    LOCK_APP(app);
1832a3bd7f05Smrg    incremental =
1833a3bd7f05Smrg        XtStackAlloc((size_t) count * sizeof(Boolean), incremental_values);
1834a3bd7f05Smrg    for (i = 0; i < count; i++)
1835a3bd7f05Smrg        incremental[i] = TRUE;
1836444c061aSmrg    if (IsGatheringRequest(widget, selection)) {
1837a3bd7f05Smrg        AddSelectionRequests(widget, selection, count, targets, &callback,
1838a3bd7f05Smrg                             1, closures, incremental, NULL);
1839a3bd7f05Smrg    }
1840a3bd7f05Smrg    else {
1841a3bd7f05Smrg        GetSelectionValues(widget, selection, targets, count,
1842a3bd7f05Smrg                           &callback, 1, closures, time, incremental, NULL);
1843444c061aSmrg    }
1844444c061aSmrg    XtStackFree((XtPointer) incremental, incremental_values);
1845444c061aSmrg    UNLOCK_APP(app);
1846444c061aSmrg}
1847444c061aSmrg
1848a3bd7f05Smrgstatic Request
1849a3bd7f05SmrgGetRequestRecord(Widget widget, Atom selection, XtRequestId id)
1850444c061aSmrg{
1851a3bd7f05Smrg    Request req = (Request) id;
1852444c061aSmrg    Select ctx = NULL;
1853444c061aSmrg
1854a3bd7f05Smrg    if ((req == NULL
1855a3bd7f05Smrg         && ((ctx = FindCtx(XtDisplay(widget), selection)) == NULL
1856a3bd7f05Smrg             || ctx->req == NULL
1857a3bd7f05Smrg             || ctx->selection != selection || ctx->widget == NULL))
1858a3bd7f05Smrg        || (req != NULL
1859a3bd7f05Smrg            && (req->ctx == NULL
1860a3bd7f05Smrg                || req->ctx->selection != selection
1861a3bd7f05Smrg                || req->ctx->widget != widget))) {
1862a3bd7f05Smrg        String params = XtName(widget);
1863a3bd7f05Smrg        Cardinal num_params = 1;
1864a3bd7f05Smrg
1865a3bd7f05Smrg        XtAppWarningMsg(XtWidgetToApplicationContext(widget),
1866a3bd7f05Smrg                        "notInConvertSelection", "xtGetSelectionRequest",
1867a3bd7f05Smrg                        XtCXtToolkitError,
1868a3bd7f05Smrg                        "XtGetSelectionRequest or XtGetSelectionParameters called for widget \"%s\" outside of ConvertSelection proc",
1869a3bd7f05Smrg                        &params, &num_params);
1870a3bd7f05Smrg        return NULL;
1871444c061aSmrg    }
1872444c061aSmrg
1873444c061aSmrg    if (req == NULL) {
1874a3bd7f05Smrg        /* non-incremental owner; only one request can be
1875a3bd7f05Smrg         * outstanding at a time, so it's safe to keep ptr in ctx */
1876a3bd7f05Smrg        req = ctx->req;
1877444c061aSmrg    }
1878444c061aSmrg    return req;
1879444c061aSmrg}
1880444c061aSmrg
1881a3bd7f05SmrgXSelectionRequestEvent *
1882a3bd7f05SmrgXtGetSelectionRequest(Widget widget, Atom selection, XtRequestId id)
1883444c061aSmrg{
1884a3bd7f05Smrg    Request req = (Request) id;
1885a3bd7f05Smrg
1886444c061aSmrg    WIDGET_TO_APPCON(widget);
1887444c061aSmrg
1888444c061aSmrg    LOCK_APP(app);
1889444c061aSmrg
1890444c061aSmrg    req = GetRequestRecord(widget, selection, id);
1891444c061aSmrg
1892a3bd7f05Smrg    if (!req) {
1893a3bd7f05Smrg        UNLOCK_APP(app);
1894a3bd7f05Smrg        return (XSelectionRequestEvent *) NULL;
1895444c061aSmrg    }
1896444c061aSmrg
1897444c061aSmrg    if (req->event.type == 0) {
1898a3bd7f05Smrg        /* owner is local; construct the remainder of the event */
1899a3bd7f05Smrg        req->event.type = SelectionRequest;
1900a3bd7f05Smrg        req->event.serial = LastKnownRequestProcessed(XtDisplay(widget));
1901a3bd7f05Smrg        req->event.send_event = True;
1902a3bd7f05Smrg        req->event.display = XtDisplay(widget);
1903a3bd7f05Smrg
1904a3bd7f05Smrg        req->event.owner = XtWindow(req->ctx->widget);
1905a3bd7f05Smrg        req->event.selection = selection;
1906444c061aSmrg    }
1907444c061aSmrg    UNLOCK_APP(app);
1908444c061aSmrg    return &req->event;
1909444c061aSmrg}
1910444c061aSmrg
1911444c061aSmrg/* Property atom access */
1912a3bd7f05SmrgAtom
1913a3bd7f05SmrgXtReservePropertyAtom(Widget w)
1914444c061aSmrg{
1915a3bd7f05Smrg    return (GetSelectionProperty(XtDisplay(w)));
1916444c061aSmrg}
1917444c061aSmrg
1918a3bd7f05Smrgvoid
1919a3bd7f05SmrgXtReleasePropertyAtom(Widget w, Atom atom)
1920444c061aSmrg{
1921a3bd7f05Smrg    FreeSelectionProperty(XtDisplay(w), atom);
1922444c061aSmrg}
1923444c061aSmrg
1924444c061aSmrg/* Multiple utilities */
1925444c061aSmrg
1926444c061aSmrg/* All requests are put in a single list per widget.  It is
1927444c061aSmrg   very unlikely anyone will be gathering multiple MULTIPLE
1928444c061aSmrg   requests at the same time,  so the loss in efficiency for
1929444c061aSmrg   this case is acceptable */
1930444c061aSmrg
1931444c061aSmrg/* Queue one or more requests to the one we're gathering */
1932a3bd7f05Smrgstatic void
1933a3bd7f05SmrgAddSelectionRequests(Widget wid,
1934a3bd7f05Smrg                     Atom sel,
1935a3bd7f05Smrg                     int count,
1936a3bd7f05Smrg                     Atom *targets,
1937a3bd7f05Smrg                     XtSelectionCallbackProc *callbacks,
1938a3bd7f05Smrg                     int num_cb,
1939a3bd7f05Smrg                     XtPointer *closures,
1940a3bd7f05Smrg                     Boolean *incrementals,
1941a3bd7f05Smrg                     Atom *properties)
1942444c061aSmrg{
1943a3bd7f05Smrg    QueuedRequestInfo qi;
1944a3bd7f05Smrg    Window window = XtWindow(wid);
1945a3bd7f05Smrg    Display *dpy = XtDisplay(wid);
1946444c061aSmrg
1947a3bd7f05Smrg    LOCK_PROCESS;
1948a3bd7f05Smrg    if (multipleContext == 0)
1949a3bd7f05Smrg        multipleContext = XUniqueContext();
1950a3bd7f05Smrg
1951a3bd7f05Smrg    qi = NULL;
1952a3bd7f05Smrg    (void) XFindContext(dpy, window, multipleContext, (XPointer *) &qi);
1953a3bd7f05Smrg
1954a3bd7f05Smrg    if (qi != NULL) {
1955a3bd7f05Smrg        QueuedRequest *req = qi->requests;
1956a3bd7f05Smrg        int start = qi->count;
1957a3bd7f05Smrg        int i = 0;
1958a3bd7f05Smrg        int j = 0;
1959a3bd7f05Smrg
1960a3bd7f05Smrg        qi->count += count;
1961a3bd7f05Smrg        req = (QueuedRequest *) XtRealloc((char *) req,
1962a3bd7f05Smrg                                          (Cardinal) ((size_t) (start + count) *
1963a3bd7f05Smrg                                                      sizeof(QueuedRequest)));
1964a3bd7f05Smrg        while (i < count) {
1965a3bd7f05Smrg            QueuedRequest newreq = (QueuedRequest)
1966a3bd7f05Smrg                __XtMalloc(sizeof(QueuedRequestRec));
1967a3bd7f05Smrg
1968a3bd7f05Smrg            newreq->selection = sel;
1969a3bd7f05Smrg            newreq->target = targets[i];
1970a3bd7f05Smrg            if (properties != NULL)
1971a3bd7f05Smrg                newreq->param = properties[i];
1972a3bd7f05Smrg            else {
1973a3bd7f05Smrg                newreq->param = GetSelectionProperty(dpy);
1974a3bd7f05Smrg                XDeleteProperty(dpy, window, newreq->param);
1975a3bd7f05Smrg            }
1976a3bd7f05Smrg            newreq->callback = callbacks[j];
1977a3bd7f05Smrg            newreq->closure = closures[i];
1978a3bd7f05Smrg            newreq->incremental = incrementals[i];
1979a3bd7f05Smrg
1980a3bd7f05Smrg            req[start] = newreq;
1981a3bd7f05Smrg            start++;
1982a3bd7f05Smrg            i++;
1983a3bd7f05Smrg            j++;
1984a3bd7f05Smrg            if (j > num_cb)
1985a3bd7f05Smrg                j = 0;
1986a3bd7f05Smrg        }
1987444c061aSmrg
1988a3bd7f05Smrg        qi->requests = req;
1989a3bd7f05Smrg    }
1990a3bd7f05Smrg    else {
1991a3bd7f05Smrg        /* Impossible */
1992a3bd7f05Smrg    }
1993444c061aSmrg
1994a3bd7f05Smrg    UNLOCK_PROCESS;
1995a3bd7f05Smrg}
1996444c061aSmrg
1997a3bd7f05Smrg/* Only call IsGatheringRequest when we have a lock already */
1998444c061aSmrg
1999a3bd7f05Smrgstatic Boolean
2000a3bd7f05SmrgIsGatheringRequest(Widget wid, Atom sel)
2001a3bd7f05Smrg{
2002a3bd7f05Smrg    QueuedRequestInfo qi;
2003a3bd7f05Smrg    Window window = XtWindow(wid);
2004a3bd7f05Smrg    Display *dpy = XtDisplay(wid);
2005a3bd7f05Smrg    Boolean found = False;
2006a3bd7f05Smrg
2007a3bd7f05Smrg    if (multipleContext == 0)
2008a3bd7f05Smrg        multipleContext = XUniqueContext();
2009a3bd7f05Smrg
2010a3bd7f05Smrg    qi = NULL;
2011a3bd7f05Smrg    (void) XFindContext(dpy, window, multipleContext, (XPointer *) &qi);
2012a3bd7f05Smrg
2013a3bd7f05Smrg    if (qi != NULL) {
2014a3bd7f05Smrg        int i = 0;
2015a3bd7f05Smrg
2016a3bd7f05Smrg        while (qi->selections[i] != None) {
2017a3bd7f05Smrg            if (qi->selections[i] == sel) {
2018a3bd7f05Smrg                found = True;
2019a3bd7f05Smrg                break;
2020a3bd7f05Smrg            }
2021a3bd7f05Smrg            i++;
2022a3bd7f05Smrg        }
2023444c061aSmrg    }
2024444c061aSmrg
2025a3bd7f05Smrg    return (found);
2026444c061aSmrg}
2027444c061aSmrg
2028444c061aSmrg/* Cleanup request scans the request queue and releases any
2029444c061aSmrg   properties queued, and removes any requests queued */
2030a3bd7f05Smrgstatic void
2031a3bd7f05SmrgCleanupRequest(Display *dpy, QueuedRequestInfo qi, Atom sel)
2032444c061aSmrg{
2033a3bd7f05Smrg    int i, j, n;
2034a3bd7f05Smrg
2035a3bd7f05Smrg    i = 0;
2036a3bd7f05Smrg
2037a3bd7f05Smrg    /* Remove this selection from the list */
2038a3bd7f05Smrg    n = 0;
2039a3bd7f05Smrg    while (qi->selections[n] != sel && qi->selections[n] != None)
2040a3bd7f05Smrg        n++;
2041a3bd7f05Smrg    if (qi->selections[n] == sel) {
2042a3bd7f05Smrg        while (qi->selections[n] != None) {
2043a3bd7f05Smrg            qi->selections[n] = qi->selections[n + 1];
2044a3bd7f05Smrg            n++;
2045a3bd7f05Smrg        }
2046444c061aSmrg    }
2047444c061aSmrg
2048a3bd7f05Smrg    while (i < qi->count) {
2049a3bd7f05Smrg        QueuedRequest req = qi->requests[i];
2050444c061aSmrg
2051a3bd7f05Smrg        if (req->selection == sel) {
2052a3bd7f05Smrg            /* Match */
2053a3bd7f05Smrg            if (req->param != None)
2054a3bd7f05Smrg                FreeSelectionProperty(dpy, req->param);
2055a3bd7f05Smrg            qi->count--;
2056444c061aSmrg
2057a3bd7f05Smrg            for (j = i; j < qi->count; j++)
2058a3bd7f05Smrg                qi->requests[j] = qi->requests[j + 1];
2059444c061aSmrg
2060a3bd7f05Smrg            XtFree((char *) req);
2061a3bd7f05Smrg        }
2062a3bd7f05Smrg        else {
2063a3bd7f05Smrg            i++;
2064a3bd7f05Smrg        }
2065444c061aSmrg    }
2066444c061aSmrg}
2067444c061aSmrg
2068a3bd7f05Smrgvoid
2069a3bd7f05SmrgXtCreateSelectionRequest(Widget widget, Atom selection)
2070444c061aSmrg{
2071a3bd7f05Smrg    QueuedRequestInfo queueInfo;
2072a3bd7f05Smrg    Window window = XtWindow(widget);
2073a3bd7f05Smrg    Display *dpy = XtDisplay(widget);
2074a3bd7f05Smrg    int n;
2075444c061aSmrg
2076a3bd7f05Smrg    LOCK_PROCESS;
2077a3bd7f05Smrg    if (multipleContext == 0)
2078a3bd7f05Smrg        multipleContext = XUniqueContext();
2079444c061aSmrg
2080a3bd7f05Smrg    queueInfo = NULL;
2081a3bd7f05Smrg    (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo);
2082444c061aSmrg
2083a3bd7f05Smrg    /* If there is one,  then cancel it */
2084a3bd7f05Smrg    if (queueInfo != NULL)
2085a3bd7f05Smrg        CleanupRequest(dpy, queueInfo, selection);
2086a3bd7f05Smrg    else {
2087a3bd7f05Smrg        /* Create it */
2088a3bd7f05Smrg        queueInfo =
2089a3bd7f05Smrg            (QueuedRequestInfo) __XtMalloc(sizeof(QueuedRequestInfoRec));
2090a3bd7f05Smrg        queueInfo->count = 0;
2091a3bd7f05Smrg        queueInfo->selections = (Atom *) __XtMalloc(sizeof(Atom) * 2);
2092a3bd7f05Smrg        queueInfo->selections[0] = None;
2093a3bd7f05Smrg        queueInfo->requests = (QueuedRequest *)
2094a3bd7f05Smrg            __XtMalloc(sizeof(QueuedRequest));
2095a3bd7f05Smrg    }
2096a3bd7f05Smrg
2097a3bd7f05Smrg    /* Append this selection to list */
2098a3bd7f05Smrg    n = 0;
2099a3bd7f05Smrg    while (queueInfo->selections[n] != None)
2100a3bd7f05Smrg        n++;
2101a3bd7f05Smrg    queueInfo->selections =
2102a3bd7f05Smrg        (Atom *) XtRealloc((char *) queueInfo->selections,
2103a3bd7f05Smrg                           (Cardinal) ((size_t) (n + 2) * sizeof(Atom)));
2104a3bd7f05Smrg    queueInfo->selections[n] = selection;
2105a3bd7f05Smrg    queueInfo->selections[n + 1] = None;
2106a3bd7f05Smrg
2107a3bd7f05Smrg    (void) XSaveContext(dpy, window, multipleContext, (char *) queueInfo);
2108a3bd7f05Smrg    UNLOCK_PROCESS;
2109444c061aSmrg}
2110444c061aSmrg
2111a3bd7f05Smrgvoid
2112a3bd7f05SmrgXtSendSelectionRequest(Widget widget, Atom selection, Time time)
2113444c061aSmrg{
2114a3bd7f05Smrg    QueuedRequestInfo queueInfo;
2115a3bd7f05Smrg    Window window = XtWindow(widget);
2116a3bd7f05Smrg    Display *dpy = XtDisplay(widget);
2117444c061aSmrg
2118a3bd7f05Smrg    LOCK_PROCESS;
2119a3bd7f05Smrg    if (multipleContext == 0)
2120a3bd7f05Smrg        multipleContext = XUniqueContext();
2121a3bd7f05Smrg
2122a3bd7f05Smrg    queueInfo = NULL;
2123a3bd7f05Smrg    (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo);
2124a3bd7f05Smrg    if (queueInfo != NULL) {
2125a3bd7f05Smrg        int i;
2126a3bd7f05Smrg        int count = 0;
2127a3bd7f05Smrg        QueuedRequest *req = queueInfo->requests;
2128a3bd7f05Smrg
2129a3bd7f05Smrg        /* Construct the requests and send it using
2130a3bd7f05Smrg           GetSelectionValues */
2131a3bd7f05Smrg        for (i = 0; i < queueInfo->count; i++)
2132a3bd7f05Smrg            if (req[i]->selection == selection)
2133a3bd7f05Smrg                count++;
2134a3bd7f05Smrg
2135a3bd7f05Smrg        if (count > 0) {
2136a3bd7f05Smrg            if (count == 1) {
2137a3bd7f05Smrg                for (i = 0; i < queueInfo->count; i++)
2138a3bd7f05Smrg                    if (req[i]->selection == selection)
2139a3bd7f05Smrg                        break;
2140a3bd7f05Smrg
2141a3bd7f05Smrg                /* special case a multiple which isn't needed */
2142a3bd7f05Smrg                GetSelectionValue(widget, selection, req[i]->target,
2143a3bd7f05Smrg                                  req[i]->callback, req[i]->closure, time,
2144a3bd7f05Smrg                                  req[i]->incremental, req[i]->param);
2145a3bd7f05Smrg            }
2146a3bd7f05Smrg            else {
2147a3bd7f05Smrg                Atom *targets;
2148a3bd7f05Smrg                Atom t[PREALLOCED];
2149a3bd7f05Smrg                XtSelectionCallbackProc *cbs;
2150a3bd7f05Smrg                XtSelectionCallbackProc c[PREALLOCED];
2151a3bd7f05Smrg                XtPointer *closures;
2152a3bd7f05Smrg                XtPointer cs[PREALLOCED];
2153a3bd7f05Smrg                Boolean *incrs;
2154a3bd7f05Smrg                Boolean ins[PREALLOCED];
2155a3bd7f05Smrg                Atom *props;
2156a3bd7f05Smrg                Atom p[PREALLOCED];
2157a3bd7f05Smrg                int j = 0;
2158a3bd7f05Smrg
2159a3bd7f05Smrg                /* Allocate */
2160a3bd7f05Smrg                targets =
2161a3bd7f05Smrg                    (Atom *) XtStackAlloc((size_t) count * sizeof(Atom), t);
2162a3bd7f05Smrg                cbs = (XtSelectionCallbackProc *)
2163a3bd7f05Smrg                    XtStackAlloc((size_t) count *
2164a3bd7f05Smrg                                 sizeof(XtSelectionCallbackProc), c);
2165a3bd7f05Smrg                closures =
2166a3bd7f05Smrg                    (XtPointer *) XtStackAlloc((size_t) count *
2167a3bd7f05Smrg                                               sizeof(XtPointer), cs);
2168a3bd7f05Smrg                incrs =
2169a3bd7f05Smrg                    (Boolean *) XtStackAlloc((size_t) count * sizeof(Boolean),
2170a3bd7f05Smrg                                             ins);
2171a3bd7f05Smrg                props = (Atom *) XtStackAlloc((size_t) count * sizeof(Atom), p);
2172a3bd7f05Smrg
2173a3bd7f05Smrg                /* Copy */
2174a3bd7f05Smrg                for (i = 0; i < queueInfo->count; i++) {
2175a3bd7f05Smrg                    if (req[i]->selection == selection) {
2176a3bd7f05Smrg                        targets[j] = req[i]->target;
2177a3bd7f05Smrg                        cbs[j] = req[i]->callback;
2178a3bd7f05Smrg                        closures[j] = req[i]->closure;
2179a3bd7f05Smrg                        incrs[j] = req[i]->incremental;
2180a3bd7f05Smrg                        props[j] = req[i]->param;
2181a3bd7f05Smrg                        j++;
2182a3bd7f05Smrg                    }
2183a3bd7f05Smrg                }
2184a3bd7f05Smrg
2185a3bd7f05Smrg                /* Make the request */
2186a3bd7f05Smrg                GetSelectionValues(widget, selection, targets, count,
2187a3bd7f05Smrg                                   cbs, count, closures, time, incrs, props);
2188a3bd7f05Smrg
2189a3bd7f05Smrg                /* Free */
2190a3bd7f05Smrg                XtStackFree((XtPointer) targets, t);
2191a3bd7f05Smrg                XtStackFree((XtPointer) cbs, c);
2192a3bd7f05Smrg                XtStackFree((XtPointer) closures, cs);
2193a3bd7f05Smrg                XtStackFree((XtPointer) incrs, ins);
2194a3bd7f05Smrg                XtStackFree((XtPointer) props, p);
2195a3bd7f05Smrg            }
2196a3bd7f05Smrg        }
2197a3bd7f05Smrg    }
2198444c061aSmrg
2199a3bd7f05Smrg    CleanupRequest(dpy, queueInfo, selection);
2200a3bd7f05Smrg    UNLOCK_PROCESS;
2201444c061aSmrg}
2202444c061aSmrg
2203a3bd7f05Smrgvoid
2204a3bd7f05SmrgXtCancelSelectionRequest(Widget widget, Atom selection)
2205444c061aSmrg{
2206a3bd7f05Smrg    QueuedRequestInfo queueInfo;
2207a3bd7f05Smrg    Window window = XtWindow(widget);
2208a3bd7f05Smrg    Display *dpy = XtDisplay(widget);
2209444c061aSmrg
2210a3bd7f05Smrg    LOCK_PROCESS;
2211a3bd7f05Smrg    if (multipleContext == 0)
2212a3bd7f05Smrg        multipleContext = XUniqueContext();
2213a3bd7f05Smrg
2214a3bd7f05Smrg    queueInfo = NULL;
2215a3bd7f05Smrg    (void) XFindContext(dpy, window, multipleContext, (XPointer *) &queueInfo);
2216a3bd7f05Smrg    /* If there is one,  then cancel it */
2217a3bd7f05Smrg    if (queueInfo != NULL)
2218a3bd7f05Smrg        CleanupRequest(dpy, queueInfo, selection);
2219a3bd7f05Smrg    UNLOCK_PROCESS;
2220444c061aSmrg}
2221444c061aSmrg
2222444c061aSmrg/* Parameter utilities */
2223444c061aSmrg
2224444c061aSmrg/* Parameters on a selection request */
2225444c061aSmrg/* Places data on allocated parameter atom,  then records the
2226444c061aSmrg   parameter atom data for use in the next call to one of
2227444c061aSmrg   the XtGetSelectionValue functions. */
2228a3bd7f05Smrgvoid
2229a3bd7f05SmrgXtSetSelectionParameters(Widget requestor,
2230a3bd7f05Smrg                         Atom selection,
2231a3bd7f05Smrg                         Atom type,
2232a3bd7f05Smrg                         XtPointer value,
2233a3bd7f05Smrg                         unsigned long length,
2234a3bd7f05Smrg                         int format)
2235444c061aSmrg{
2236a3bd7f05Smrg    Display *dpy = XtDisplay(requestor);
2237a3bd7f05Smrg    Window window = XtWindow(requestor);
2238a3bd7f05Smrg    Atom property = GetParamInfo(requestor, selection);
2239a3bd7f05Smrg
2240a3bd7f05Smrg    if (property == None) {
2241a3bd7f05Smrg        property = GetSelectionProperty(dpy);
2242a3bd7f05Smrg        AddParamInfo(requestor, selection, property);
2243a3bd7f05Smrg    }
2244a3bd7f05Smrg
2245a3bd7f05Smrg    XChangeProperty(dpy, window, property,
2246a3bd7f05Smrg                    type, format, PropModeReplace,
2247a3bd7f05Smrg                    (unsigned char *) value, (int) length);
2248444c061aSmrg}
2249444c061aSmrg
2250444c061aSmrg/* Retrieves data passed in a parameter. Data for this is stored
2251444c061aSmrg   on the originator's window */
2252a3bd7f05Smrgvoid
2253a3bd7f05SmrgXtGetSelectionParameters(Widget owner,
2254a3bd7f05Smrg                         Atom selection,
2255a3bd7f05Smrg                         XtRequestId request_id,
2256a3bd7f05Smrg                         Atom *type_return,
2257a3bd7f05Smrg                         XtPointer *value_return,
2258a3bd7f05Smrg                         unsigned long *length_return,
2259a3bd7f05Smrg                         int *format_return)
2260444c061aSmrg{
2261444c061aSmrg    Request req;
2262444c061aSmrg    Display *dpy = XtDisplay(owner);
2263a3bd7f05Smrg
2264444c061aSmrg    WIDGET_TO_APPCON(owner);
2265444c061aSmrg
2266444c061aSmrg    *value_return = NULL;
22670568f49bSmrg    *length_return = (unsigned long) (*format_return = 0);
2268444c061aSmrg    *type_return = None;
2269444c061aSmrg
2270444c061aSmrg    LOCK_APP(app);
2271444c061aSmrg
2272444c061aSmrg    req = GetRequestRecord(owner, selection, request_id);
2273444c061aSmrg
2274444c061aSmrg    if (req && req->property) {
2275a3bd7f05Smrg        unsigned long bytes_after;      /* unused */
2276a3bd7f05Smrg
2277a3bd7f05Smrg        StartProtectedSection(dpy, req->requestor);
2278a3bd7f05Smrg        XGetWindowProperty(dpy, req->requestor, req->property, 0L, 10000000,
2279a3bd7f05Smrg                           False, AnyPropertyType, type_return, format_return,
2280a3bd7f05Smrg                           length_return, &bytes_after,
2281a3bd7f05Smrg                           (unsigned char **) value_return);
2282a3bd7f05Smrg        EndProtectedSection(dpy);
2283444c061aSmrg#ifdef XT_COPY_SELECTION
2284a3bd7f05Smrg        if (*value_return) {
2285a3bd7f05Smrg            int size = (int) BYTELENGTH(*length_return, *format_return) + 1;
2286a3bd7f05Smrg            char *tmp = __XtMalloc((Cardinal) size);
2287a3bd7f05Smrg
2288a3bd7f05Smrg            (void) memmove(tmp, *value_return, (size_t) size);
2289a3bd7f05Smrg            XFree(*value_return);
2290a3bd7f05Smrg            *value_return = tmp;
2291a3bd7f05Smrg        }
2292444c061aSmrg#endif
2293444c061aSmrg    }
2294444c061aSmrg    UNLOCK_APP(app);
2295444c061aSmrg}
2296444c061aSmrg
2297444c061aSmrg/*  Parameters are temporarily stashed in an XContext.  A list is used because
2298444c061aSmrg *  there may be more than one selection request in progress.  The context
2299444c061aSmrg *  data is deleted when the list is empty.  In the future, the parameter
2300444c061aSmrg *  context could be merged with other contexts used during selections.
2301444c061aSmrg */
2302444c061aSmrg
2303a3bd7f05Smrgstatic void
2304a3bd7f05SmrgAddParamInfo(Widget w, Atom selection, Atom param_atom)
2305444c061aSmrg{
2306444c061aSmrg    Param p;
2307444c061aSmrg    ParamInfo pinfo;
2308444c061aSmrg
2309444c061aSmrg    LOCK_PROCESS;
2310444c061aSmrg    if (paramPropertyContext == 0)
2311a3bd7f05Smrg        paramPropertyContext = XUniqueContext();
2312444c061aSmrg
2313444c061aSmrg    if (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2314a3bd7f05Smrg                     (XPointer *) &pinfo)) {
2315a3bd7f05Smrg        pinfo = (ParamInfo) __XtMalloc(sizeof(ParamInfoRec));
2316a3bd7f05Smrg        pinfo->count = 1;
2317a3bd7f05Smrg        pinfo->paramlist = XtNew(ParamRec);
2318a3bd7f05Smrg        p = pinfo->paramlist;
2319a3bd7f05Smrg        (void) XSaveContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2320a3bd7f05Smrg                            (char *) pinfo);
2321444c061aSmrg    }
2322444c061aSmrg    else {
2323a3bd7f05Smrg        int n;
2324a3bd7f05Smrg
2325a3bd7f05Smrg        for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) {
2326a3bd7f05Smrg            if (p->selection == None || p->selection == selection)
2327a3bd7f05Smrg                break;
2328a3bd7f05Smrg        }
2329a3bd7f05Smrg        if (n == 0) {
2330a3bd7f05Smrg            pinfo->count++;
2331a3bd7f05Smrg            pinfo->paramlist = (Param)
2332a3bd7f05Smrg                XtRealloc((char *) pinfo->paramlist,
2333a3bd7f05Smrg                          (Cardinal) (pinfo->count * sizeof(ParamRec)));
2334a3bd7f05Smrg            p = &pinfo->paramlist[pinfo->count - 1];
2335a3bd7f05Smrg            (void) XSaveContext(XtDisplay(w), XtWindow(w),
2336a3bd7f05Smrg                                paramPropertyContext, (char *) pinfo);
2337a3bd7f05Smrg        }
2338444c061aSmrg    }
2339444c061aSmrg    p->selection = selection;
2340444c061aSmrg    p->param = param_atom;
2341444c061aSmrg    UNLOCK_PROCESS;
2342444c061aSmrg}
2343444c061aSmrg
2344a3bd7f05Smrgstatic void
2345a3bd7f05SmrgRemoveParamInfo(Widget w, Atom selection)
2346444c061aSmrg{
2347444c061aSmrg    ParamInfo pinfo;
2348444c061aSmrg    Boolean retain = False;
2349444c061aSmrg
2350444c061aSmrg    LOCK_PROCESS;
2351444c061aSmrg    if (paramPropertyContext
2352a3bd7f05Smrg        && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2353a3bd7f05Smrg                         (XPointer *) &pinfo) == 0)) {
2354a3bd7f05Smrg        Param p;
2355a3bd7f05Smrg        int n;
2356a3bd7f05Smrg
2357a3bd7f05Smrg        /* Find and invalidate the parameter data. */
2358a3bd7f05Smrg        for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++) {
2359a3bd7f05Smrg            if (p->selection != None) {
2360a3bd7f05Smrg                if (p->selection == selection)
2361a3bd7f05Smrg                    p->selection = None;
2362a3bd7f05Smrg                else
2363a3bd7f05Smrg                    retain = True;
2364a3bd7f05Smrg            }
2365a3bd7f05Smrg        }
2366a3bd7f05Smrg        /* If there's no valid data remaining, release the context entry. */
2367a3bd7f05Smrg        if (!retain) {
2368a3bd7f05Smrg            XtFree((char *) pinfo->paramlist);
2369a3bd7f05Smrg            XtFree((char *) pinfo);
2370a3bd7f05Smrg            XDeleteContext(XtDisplay(w), XtWindow(w), paramPropertyContext);
2371a3bd7f05Smrg        }
2372444c061aSmrg    }
2373444c061aSmrg    UNLOCK_PROCESS;
2374444c061aSmrg}
2375444c061aSmrg
2376a3bd7f05Smrgstatic Atom
2377a3bd7f05SmrgGetParamInfo(Widget w, Atom selection)
2378444c061aSmrg{
2379444c061aSmrg    ParamInfo pinfo;
2380444c061aSmrg    Atom atom = None;
2381444c061aSmrg
2382444c061aSmrg    LOCK_PROCESS;
2383444c061aSmrg    if (paramPropertyContext
2384a3bd7f05Smrg        && (XFindContext(XtDisplay(w), XtWindow(w), paramPropertyContext,
2385a3bd7f05Smrg                         (XPointer *) &pinfo) == 0)) {
2386a3bd7f05Smrg        Param p;
2387a3bd7f05Smrg        int n;
2388a3bd7f05Smrg
2389a3bd7f05Smrg        for (n = (int) pinfo->count, p = pinfo->paramlist; n; n--, p++)
2390a3bd7f05Smrg            if (p->selection == selection) {
2391a3bd7f05Smrg                atom = p->param;
2392a3bd7f05Smrg                break;
2393a3bd7f05Smrg            }
2394444c061aSmrg    }
2395444c061aSmrg    UNLOCK_PROCESS;
2396444c061aSmrg    return atom;
2397444c061aSmrg}
2398